Skip to content

Commit cc96c8e

Browse files
authored
Merge pull request #972 from reactjs/sync-c003ac4e
Sync with react.dev @ c003ac4
2 parents d7c5209 + 15cae40 commit cc96c8e

File tree

9 files changed

+94
-13
lines changed

9 files changed

+94
-13
lines changed

.github/workflows/analyze.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@ jobs:
1111
analyze:
1212
runs-on: ubuntu-latest
1313
steps:
14-
- uses: actions/checkout@v2
14+
- uses: actions/checkout@v3
1515

1616
- name: Set up node
17-
uses: actions/setup-node@v1
17+
uses: actions/setup-node@v3
1818
with:
1919
node-version: '20.x'
2020

2121
- name: Install dependencies
2222
uses: bahmutov/[email protected]
2323

2424
- name: Restore next build
25-
uses: actions/cache@v2
25+
uses: actions/cache@v3
2626
id: restore-build-cache
2727
env:
2828
cache-name: cache-next-build
@@ -41,7 +41,7 @@ jobs:
4141
run: npx -p [email protected] report
4242

4343
- name: Upload bundle
44-
uses: actions/upload-artifact@v2
44+
uses: actions/upload-artifact@v3
4545
with:
4646
path: .next/analyze/__bundle_analysis.json
4747
name: bundle_analysis.json
@@ -73,7 +73,7 @@ jobs:
7373
run: ls -laR .next/analyze/base && npx -p nextjs-bundle-analysis compare
7474

7575
- name: Upload analysis comment
76-
uses: actions/upload-artifact@v2
76+
uses: actions/upload-artifact@v3
7777
with:
7878
name: analysis_comment.txt
7979
path: .next/analyze/__bundle_analysis_comment.txt
@@ -82,7 +82,7 @@ jobs:
8282
run: echo ${{ github.event.number }} > ./pr_number
8383

8484
- name: Upload PR number
85-
uses: actions/upload-artifact@v2
85+
uses: actions/upload-artifact@v3
8686
with:
8787
name: pr_number
8888
path: ./pr_number

src/components/Layout/Footer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ export function Footer() {
283283
<div
284284
className="text-xs text-left rtl:text-right mt-2 pe-0.5"
285285
dir="ltr">
286-
&copy;{new Date().getFullYear()}
286+
Copyright &copy; Meta Platforms, Inc
287287
</div>
288288
<div
289289
className="uwu-visible text-xs cursor-pointer hover:text-link hover:dark:text-link-dark hover:underline"

src/content/learn/you-might-not-need-an-effect.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ function Game() {
408408
409409
There are two problems with this code.
410410
411-
First problem is that it is very inefficient: the component (and its children) have to re-render between each `set` call in the chain. In the example above, in the worst case (`setCard` → render → `setGoldCardCount` → render → `setRound` → render → `setIsGameOver` → render) there are three unnecessary re-renders of the tree below.
411+
The first problem is that it is very inefficient: the component (and its children) have to re-render between each `set` call in the chain. In the example above, in the worst case (`setCard` → render → `setGoldCardCount` → render → `setRound` → render → `setIsGameOver` → render) there are three unnecessary re-renders of the tree below.
412412
413413
The second problem is that even if it weren't slow, as your code evolves, you will run into cases where the "chain" you wrote doesn't fit the new requirements. Imagine you are adding a way to step through the history of the game moves. You'd do it by updating each state variable to a value from the past. However, setting the `card` state to a value from the past would trigger the Effect chain again and change the data you're showing. Such code is often rigid and fragile.
414414

src/content/reference/react/useCallback.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,7 @@ function ChatRoom({ roomId }) {
711711

712712
useEffect(() => {
713713
const options = createOptions();
714-
const connection = createConnection();
714+
const connection = createConnection(options);
715715
connection.connect();
716716
// ...
717717
```
@@ -722,7 +722,7 @@ function ChatRoom({ roomId }) {
722722
```js {6}
723723
useEffect(() => {
724724
const options = createOptions();
725-
const connection = createConnection();
725+
const connection = createConnection(options);
726726
connection.connect();
727727
return () => connection.disconnect();
728728
}, [createOptions]); // 🔴 Проблема: Эта зависимость изменяется при каждом рендере
@@ -744,7 +744,7 @@ function ChatRoom({ roomId }) {
744744

745745
useEffect(() => {
746746
const options = createOptions();
747-
const connection = createConnection();
747+
const connection = createConnection(options);
748748
connection.connect();
749749
return () => connection.disconnect();
750750
}, [createOptions]); // ✅ Изменяется только при изменении createOptions
@@ -766,7 +766,7 @@ function ChatRoom({ roomId }) {
766766
}
767767

768768
const options = createOptions();
769-
const connection = createConnection();
769+
const connection = createConnection(options);
770770
connection.connect();
771771
return () => connection.disconnect();
772772
}, [roomId]); // ✅ Изменяется только при изменении roomId

src/content/reference/react/useMemo.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,6 +1055,82 @@ label {
10551055

10561056
---
10571057

1058+
### Слишком частые вызовы эффекта {/*preventing-an-effect-from-firing-too-often*/}
1059+
1060+
Время от времени вам могут понадобиться значения внутри [эффекта:](/learn/synchronizing-with-effects)
1061+
1062+
```js {4-7,10}
1063+
function ChatRoom({ roomId }) {
1064+
const [message, setMessage] = useState('');
1065+
1066+
const options = {
1067+
serverUrl: 'https://localhost:1234',
1068+
roomId: roomId
1069+
}
1070+
1071+
useEffect(() => {
1072+
const connection = createConnection(options);
1073+
connection.connect();
1074+
// ...
1075+
```
1076+
1077+
Это создаёт проблему. [Каждое реактивное значение должно быть объявлено как зависимость вашего эффекта.](/learn/lifecycle-of-reactive-effects#react-verifies-that-you-specified-every-reactive-value-as-a-dependency) Но если вы добавите `options` как зависимость, ваш эффект начнёт постоянно переподключаться к чату:
1078+
1079+
1080+
```js {5}
1081+
useEffect(() => {
1082+
const connection = createConnection(options);
1083+
connection.connect();
1084+
return () => connection.disconnect();
1085+
}, [options]); // 🔴 Проблема: эта зависимость меняется при каждом рендере
1086+
// ...
1087+
```
1088+
1089+
Решение – обернуть необходимый в эффекте объект в `useMemo`:
1090+
1091+
```js {4-9,16}
1092+
function ChatRoom({ roomId }) {
1093+
const [message, setMessage] = useState('');
1094+
1095+
const options = useMemo(() => {
1096+
return {
1097+
serverUrl: 'https://localhost:1234',
1098+
roomId: roomId
1099+
};
1100+
}, [roomId]); // ✅ Меняется только тогда, когда меняется roomId
1101+
1102+
useEffect(() => {
1103+
const connection = createConnection(options);
1104+
connection.connect();
1105+
return () => connection.disconnect();
1106+
}, [options]); // ✅ Вызывается только тогда, когда меняется options
1107+
// ...
1108+
```
1109+
1110+
Это гарантирует, что объект `options` один и тот же между повторными рендерами, если `useMemo` возвращает закешированный объект.
1111+
1112+
Однако `useMemo` является оптимизацией производительности, а не семантической гарантией. React может отбросить закешированное значение, если [возникнет условие для этого](#caveats). Это также спровоцирует перезапуск эффекта, **так что ещё лучше будет избавиться от зависимости,** переместив ваш объект *внутрь* эффекта:
1113+
1114+
```js {5-8,13}
1115+
function ChatRoom({ roomId }) {
1116+
const [message, setMessage] = useState('');
1117+
1118+
useEffect(() => {
1119+
const options = { // ✅ Нет необходимости для useMemo или зависимостей объекта!
1120+
serverUrl: 'https://localhost:1234',
1121+
roomId: roomId
1122+
}
1123+
1124+
const connection = createConnection(options);
1125+
connection.connect();
1126+
return () => connection.disconnect();
1127+
}, [roomId]); // ✅ Меняется только тогда, когда меняется roomId
1128+
// ...
1129+
```
1130+
1131+
Теперь ваш код стал проще и не требует `useMemo`. [Узнайте больше об удалении зависимостей эффекта.](/learn/removing-effect-dependencies#move-dynamic-objects-and-functions-inside-your-effect)
1132+
1133+
10581134
### Мемоизация зависимостей других хуков {/*memoizing-a-dependency-of-another-hook*/}
10591135
10601136
Предположим, что у нас есть вычисления, зависящие от объекта, создаваемого внутри компонента:

src/content/reference/react/useReducer.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ function MyComponent() {
5252
#### Замечания {/*caveats*/}
5353
5454
* `useReducer -- это хук, поэтому вызывайте его только **на верхнем уровне компонента** или собственных хуков. useReducer нельзя вызвать внутри циклов или условий. Если это нужно, создайте новый компонент и переместите состояние в него.
55+
* Функция `dispatch` стабильна между повторными рендерами, поэтому вы увидите, что её часто пропускают в списке зависимостей эффекта, но и её включение не вызовет перезапуск эффекта. Если линтер позволяет вам пропускать зависимости без ошибок, то вы можете делать это без опаски. [Узнайте больше об удалении зависимостей эффекта.](/learn/removing-effect-dependencies#move-dynamic-objects-and-functions-inside-your-effect)
5556
* В строгом режиме React будет **вызывать редюсер и инициализатор дважды**, [чтобы помочь обнаружить случайные побочные эффекты.](#my-reducer-or-initializer-function-runs-twice) Такое поведение проявляется только в режиме разработки и не влияет на продакшен-режим. Логика обновления состояния не изменится, если редюсер и инициализатор – чистые функции (какими они и должны быть). Результат второго вызова проигнорируется.
5657

5758
---

src/content/reference/react/useState.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ function handleClick() {
8585
8686
* React [batches state updates.](/learn/queueing-a-series-of-state-updates) It updates the screen **after all the event handlers have run** and have called their `set` functions. This prevents multiple re-renders during a single event. In the rare case that you need to force React to update the screen earlier, for example to access the DOM, you can use [`flushSync`.](/reference/react-dom/flushSync)
8787
88+
* The `set` function has a stable identity, so you will often see it omitted from effect dependencies, but including it will not cause the effect to fire. If the linter lets you omit a dependency without errors, it is safe to do. [Learn more about removing Effect dependencies.](/learn/removing-effect-dependencies#move-dynamic-objects-and-functions-inside-your-effect)
89+
8890
* Calling the `set` function *during rendering* is only allowed from within the currently rendering component. React will discard its output and immediately attempt to render it again with the new state. This pattern is rarely needed, but you can use it to **store information from the previous renders**. [See an example below.](#storing-information-from-previous-renders)
8991
9092
* In Strict Mode, React will **call your updater function twice** in order to [help you find accidental impurities.](#my-initializer-or-updater-function-runs-twice) This is development-only behavior and does not affect production. If your updater function is pure (as it should be), this should not affect the behavior. The result from one of the calls will be ignored.

src/content/reference/react/useTransition.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ function TabContainer() {
8080

8181
* The function you pass to `startTransition` must be synchronous. React immediately executes this function, marking all state updates that happen while it executes as Transitions. If you try to perform more state updates later (for example, in a timeout), they won't be marked as Transitions.
8282

83+
* The `startTransition` function has a stable identity, so you will often see it omitted from effect dependencies, but including it will not cause the effect to fire. If the linter lets you omit a dependency without errors, it is safe to do. [Learn more about removing Effect dependencies.](/learn/removing-effect-dependencies#move-dynamic-objects-and-functions-inside-your-effect)
84+
8385
* A state update marked as a Transition will be interrupted by other state updates. For example, if you update a chart component inside a Transition, but then start typing into an input while the chart is in the middle of a re-render, React will restart the rendering work on the chart component after handling the input update.
8486

8587
* Transition updates can't be used to control text inputs.

src/content/reference/rsc/server-actions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ When React renders the `EmptyNote` Server Component, it will create a reference
5353
export default function Button({onClick}) {
5454
console.log(onClick);
5555
// {$$typeof: Symbol.for("react.server.reference"), $$id: 'createNoteAction'}
56-
return <button onClick={onClick}>Create Empty Note</button>
56+
return <button onClick={() => onClick()}>Create Empty Note</button>
5757
}
5858
```
5959

0 commit comments

Comments
 (0)