From 0f2284ddc8dcab8bbb9b42c04f3c7af94b5b2e73 Mon Sep 17 00:00:00 2001 From: Jan Kassens Date: Mon, 9 Sep 2024 14:28:04 -0700 Subject: [PATCH 1/6] Update copyright footer (#7152) Per https://fburl.com/wiki/ioqmn40p --- src/components/Layout/Footer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Layout/Footer.tsx b/src/components/Layout/Footer.tsx index 5bcf9df98..4e19039ed 100644 --- a/src/components/Layout/Footer.tsx +++ b/src/components/Layout/Footer.tsx @@ -283,7 +283,7 @@ export function Footer() {
- ©{new Date().getFullYear()} + Copyright © Meta Platforms, Inc
Date: Mon, 16 Sep 2024 12:36:31 +0530 Subject: [PATCH 2/6] Update the version 3 (#7161) --- .github/workflows/analyze.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index 87dcfdc73..2a905a0df 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -11,10 +11,10 @@ jobs: analyze: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up node - uses: actions/setup-node@v1 + uses: actions/setup-node@v3 with: node-version: '20.x' @@ -22,7 +22,7 @@ jobs: uses: bahmutov/npm-install@v1.7.10 - name: Restore next build - uses: actions/cache@v2 + uses: actions/cache@v3 id: restore-build-cache env: cache-name: cache-next-build @@ -41,7 +41,7 @@ jobs: run: npx -p nextjs-bundle-analysis@0.5.0 report - name: Upload bundle - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: path: .next/analyze/__bundle_analysis.json name: bundle_analysis.json @@ -73,7 +73,7 @@ jobs: run: ls -laR .next/analyze/base && npx -p nextjs-bundle-analysis compare - name: Upload analysis comment - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: analysis_comment.txt path: .next/analyze/__bundle_analysis_comment.txt @@ -82,7 +82,7 @@ jobs: run: echo ${{ github.event.number }} > ./pr_number - name: Upload PR number - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: pr_number path: ./pr_number From 505c85db8c232b474282d55391c67884de8d99dd Mon Sep 17 00:00:00 2001 From: Strek Date: Tue, 17 Sep 2024 13:48:58 +0530 Subject: [PATCH 3/6] Update you-might-not-need-an-effect.md (#7169) --- src/content/learn/you-might-not-need-an-effect.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/you-might-not-need-an-effect.md b/src/content/learn/you-might-not-need-an-effect.md index 27031720d..a009793ab 100644 --- a/src/content/learn/you-might-not-need-an-effect.md +++ b/src/content/learn/you-might-not-need-an-effect.md @@ -408,7 +408,7 @@ function Game() { There are two problems with this code. -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. +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. 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. From 39abc60fce1588b4e83cc45d52b522aa63c01bc2 Mon Sep 17 00:00:00 2001 From: Ricky Date: Thu, 19 Sep 2024 14:42:44 -0400 Subject: [PATCH 4/6] Nit: server actions can't be passed events (#7175) --- src/content/reference/rsc/server-actions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/rsc/server-actions.md b/src/content/reference/rsc/server-actions.md index 06613cb7c..d24e896f0 100644 --- a/src/content/reference/rsc/server-actions.md +++ b/src/content/reference/rsc/server-actions.md @@ -53,7 +53,7 @@ When React renders the `EmptyNote` Server Component, it will create a reference export default function Button({onClick}) { console.log(onClick); // {$$typeof: Symbol.for("react.server.reference"), $$id: 'createNoteAction'} - return + return } ``` From c003ac4eb130fca70b88cf3a1b80ce5f76c51ae3 Mon Sep 17 00:00:00 2001 From: Ricky Date: Sun, 22 Sep 2024 13:19:03 -0400 Subject: [PATCH 5/6] Add stable fn notes to useMemo, useTransition, useState, and useReducer (#7181) --- src/content/reference/react/useCallback.md | 8 +- src/content/reference/react/useMemo.md | 77 ++++++++++++++++++++ src/content/reference/react/useReducer.md | 1 + src/content/reference/react/useState.md | 2 + src/content/reference/react/useTransition.md | 2 + 5 files changed, 86 insertions(+), 4 deletions(-) diff --git a/src/content/reference/react/useCallback.md b/src/content/reference/react/useCallback.md index 93ce700e4..abcd474df 100644 --- a/src/content/reference/react/useCallback.md +++ b/src/content/reference/react/useCallback.md @@ -711,7 +711,7 @@ function ChatRoom({ roomId }) { useEffect(() => { const options = createOptions(); - const connection = createConnection(); + const connection = createConnection(options); connection.connect(); // ... ``` @@ -722,7 +722,7 @@ This creates a problem. [Every reactive value must be declared as a dependency o ```js {6} useEffect(() => { const options = createOptions(); - const connection = createConnection(); + const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [createOptions]); // 🔴 Problem: This dependency changes on every render @@ -744,7 +744,7 @@ function ChatRoom({ roomId }) { useEffect(() => { const options = createOptions(); - const connection = createConnection(); + const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [createOptions]); // ✅ Only changes when createOptions changes @@ -766,7 +766,7 @@ function ChatRoom({ roomId }) { } const options = createOptions(); - const connection = createConnection(); + const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [roomId]); // ✅ Only changes when roomId changes diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index a44c86fc8..33193ee3b 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -1056,6 +1056,83 @@ Keep in mind that you need to run React in production mode, disable [React Devel --- +### Preventing an Effect from firing too often {/*preventing-an-effect-from-firing-too-often*/} + +Sometimes, you might want to use a value inside an [Effect:](/learn/synchronizing-with-effects) + +```js {4-7,10} +function ChatRoom({ roomId }) { + const [message, setMessage] = useState(''); + + const options = { + serverUrl: 'https://localhost:1234', + roomId: roomId + } + + useEffect(() => { + const connection = createConnection(options); + connection.connect(); + // ... +``` + +This creates a problem. [Every reactive value must be declared as a dependency of your Effect.](/learn/lifecycle-of-reactive-effects#react-verifies-that-you-specified-every-reactive-value-as-a-dependency) However, if you declare `options` as a dependency, it will cause your Effect to constantly reconnect to the chat room: + + +```js {5} + useEffect(() => { + const connection = createConnection(options); + connection.connect(); + return () => connection.disconnect(); + }, [options]); // 🔴 Problem: This dependency changes on every render + // ... +``` + +To solve this, you can wrap the object you need to call from an Effect in `useMemo`: + +```js {4-9,16} +function ChatRoom({ roomId }) { + const [message, setMessage] = useState(''); + + const options = useMemo(() => { + return { + serverUrl: 'https://localhost:1234', + roomId: roomId + }; + }, [roomId]); // ✅ Only changes when roomId changes + + useEffect(() => { + const options = createOptions(); + const connection = createConnection(options); + connection.connect(); + return () => connection.disconnect(); + }, [options]); // ✅ Only changes when createOptions changes + // ... +``` + +This ensures that the `options` object is the same between re-renders if `useMemo` returns the cached object. + +However, since `useMemo` is performance optimization, not a semantic guarantee, React may throw away the cached value if [there is a specific reason to do that](#caveats). This will also cause the effect to re-fire, **so it's even better to remove the need for a function dependency** by moving your object *inside* the Effect: + +```js {5-8,13} +function ChatRoom({ roomId }) { + const [message, setMessage] = useState(''); + + useEffect(() => { + const options = { // ✅ No need for useMemo or object dependencies! + serverUrl: 'https://localhost:1234', + roomId: roomId + } + + const connection = createConnection(options); + connection.connect(); + return () => connection.disconnect(); + }, [roomId]); // ✅ Only changes when roomId changes + // ... +``` + +Now your code is simpler and doesn't need `useMemo`. [Learn more about removing Effect dependencies.](/learn/removing-effect-dependencies#move-dynamic-objects-and-functions-inside-your-effect) + + ### Memoizing a dependency of another Hook {/*memoizing-a-dependency-of-another-hook*/} Suppose you have a calculation that depends on an object created directly in the component body: diff --git a/src/content/reference/react/useReducer.md b/src/content/reference/react/useReducer.md index dbd18f6b8..cfd0fb856 100644 --- a/src/content/reference/react/useReducer.md +++ b/src/content/reference/react/useReducer.md @@ -52,6 +52,7 @@ function MyComponent() { #### Caveats {/*caveats*/} * `useReducer` is a Hook, so you can only call it **at the top level of your component** or your own Hooks. You can't call it inside loops or conditions. If you need that, extract a new component and move the state into it. +* The `dispatch` 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) * In Strict Mode, React will **call your reducer and initializer twice** in order to [help you find accidental impurities.](#my-reducer-or-initializer-function-runs-twice) This is development-only behavior and does not affect production. If your reducer and initializer are pure (as they should be), this should not affect your logic. The result from one of the calls is ignored. --- diff --git a/src/content/reference/react/useState.md b/src/content/reference/react/useState.md index 48d96f8ee..4aa9d5911 100644 --- a/src/content/reference/react/useState.md +++ b/src/content/reference/react/useState.md @@ -85,6 +85,8 @@ function handleClick() { * 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) +* 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) + * 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) * 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. diff --git a/src/content/reference/react/useTransition.md b/src/content/reference/react/useTransition.md index 77c2cdad5..5066fe637 100644 --- a/src/content/reference/react/useTransition.md +++ b/src/content/reference/react/useTransition.md @@ -80,6 +80,8 @@ function TabContainer() { * 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. +* 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) + * 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. * Transition updates can't be used to control text inputs. From 15cae40f22706f8a5341d911681a7e363aebc4a9 Mon Sep 17 00:00:00 2001 From: Maxim Titov Date: Mon, 23 Sep 2024 22:32:05 +0500 Subject: [PATCH 6/6] translate notes about effect dependencies --- src/content/reference/react/useMemo.md | 31 ++++++++++------------- src/content/reference/react/useReducer.md | 7 +---- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index f3b178f3d..c2004abca 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -1055,12 +1055,9 @@ label { --- -<<<<<<< HEAD -### Мемоизация зависимостей других хуков {/*memoizing-a-dependency-of-another-hook*/} -======= -### Preventing an Effect from firing too often {/*preventing-an-effect-from-firing-too-often*/} +### Слишком частые вызовы эффекта {/*preventing-an-effect-from-firing-too-often*/} -Sometimes, you might want to use a value inside an [Effect:](/learn/synchronizing-with-effects) +Время от времени вам могут понадобиться значения внутри [эффекта:](/learn/synchronizing-with-effects) ```js {4-7,10} function ChatRoom({ roomId }) { @@ -1077,7 +1074,7 @@ function ChatRoom({ roomId }) { // ... ``` -This creates a problem. [Every reactive value must be declared as a dependency of your Effect.](/learn/lifecycle-of-reactive-effects#react-verifies-that-you-specified-every-reactive-value-as-a-dependency) However, if you declare `options` as a dependency, it will cause your Effect to constantly reconnect to the chat room: +Это создаёт проблему. [Каждое реактивное значение должно быть объявлено как зависимость вашего эффекта.](/learn/lifecycle-of-reactive-effects#react-verifies-that-you-specified-every-reactive-value-as-a-dependency) Но если вы добавите `options` как зависимость, ваш эффект начнёт постоянно переподключаться к чату: ```js {5} @@ -1085,11 +1082,11 @@ This creates a problem. [Every reactive value must be declared as a dependency o const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); - }, [options]); // 🔴 Problem: This dependency changes on every render + }, [options]); // 🔴 Проблема: эта зависимость меняется при каждом рендере // ... ``` -To solve this, you can wrap the object you need to call from an Effect in `useMemo`: +Решение – обернуть необходимый в эффекте объект в `useMemo`: ```js {4-9,16} function ChatRoom({ roomId }) { @@ -1100,27 +1097,26 @@ function ChatRoom({ roomId }) { serverUrl: 'https://localhost:1234', roomId: roomId }; - }, [roomId]); // ✅ Only changes when roomId changes + }, [roomId]); // ✅ Меняется только тогда, когда меняется roomId useEffect(() => { - const options = createOptions(); const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); - }, [options]); // ✅ Only changes when createOptions changes + }, [options]); // ✅ Вызывается только тогда, когда меняется options // ... ``` -This ensures that the `options` object is the same between re-renders if `useMemo` returns the cached object. +Это гарантирует, что объект `options` один и тот же между повторными рендерами, если `useMemo` возвращает закешированный объект. -However, since `useMemo` is performance optimization, not a semantic guarantee, React may throw away the cached value if [there is a specific reason to do that](#caveats). This will also cause the effect to re-fire, **so it's even better to remove the need for a function dependency** by moving your object *inside* the Effect: +Однако `useMemo` является оптимизацией производительности, а не семантической гарантией. React может отбросить закешированное значение, если [возникнет условие для этого](#caveats). Это также спровоцирует перезапуск эффекта, **так что ещё лучше будет избавиться от зависимости,** переместив ваш объект *внутрь* эффекта: ```js {5-8,13} function ChatRoom({ roomId }) { const [message, setMessage] = useState(''); useEffect(() => { - const options = { // ✅ No need for useMemo or object dependencies! + const options = { // ✅ Нет необходимости для useMemo или зависимостей объекта! serverUrl: 'https://localhost:1234', roomId: roomId } @@ -1128,15 +1124,14 @@ function ChatRoom({ roomId }) { const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); - }, [roomId]); // ✅ Only changes when roomId changes + }, [roomId]); // ✅ Меняется только тогда, когда меняется roomId // ... ``` -Now your code is simpler and doesn't need `useMemo`. [Learn more about removing Effect dependencies.](/learn/removing-effect-dependencies#move-dynamic-objects-and-functions-inside-your-effect) +Теперь ваш код стал проще и не требует `useMemo`. [Узнайте больше об удалении зависимостей эффекта.](/learn/removing-effect-dependencies#move-dynamic-objects-and-functions-inside-your-effect) -### Memoizing a dependency of another Hook {/*memoizing-a-dependency-of-another-hook*/} ->>>>>>> c003ac4eb130fca70b88cf3a1b80ce5f76c51ae3 +### Мемоизация зависимостей других хуков {/*memoizing-a-dependency-of-another-hook*/} Предположим, что у нас есть вычисления, зависящие от объекта, создаваемого внутри компонента: diff --git a/src/content/reference/react/useReducer.md b/src/content/reference/react/useReducer.md index 50e37675d..d339631b2 100644 --- a/src/content/reference/react/useReducer.md +++ b/src/content/reference/react/useReducer.md @@ -51,14 +51,9 @@ function MyComponent() { #### Замечания {/*caveats*/} -<<<<<<< HEAD * `useReducer -- это хук, поэтому вызывайте его только **на верхнем уровне компонента** или собственных хуков. useReducer нельзя вызвать внутри циклов или условий. Если это нужно, создайте новый компонент и переместите состояние в него. +* Функция `dispatch` стабильна между повторными рендерами, поэтому вы увидите, что её часто пропускают в списке зависимостей эффекта, но и её включение не вызовет перезапуск эффекта. Если линтер позволяет вам пропускать зависимости без ошибок, то вы можете делать это без опаски. [Узнайте больше об удалении зависимостей эффекта.](/learn/removing-effect-dependencies#move-dynamic-objects-and-functions-inside-your-effect) * В строгом режиме React будет **вызывать редюсер и инициализатор дважды**, [чтобы помочь обнаружить случайные побочные эффекты.](#my-reducer-or-initializer-function-runs-twice) Такое поведение проявляется только в режиме разработки и не влияет на продакшен-режим. Логика обновления состояния не изменится, если редюсер и инициализатор – чистые функции (какими они и должны быть). Результат второго вызова проигнорируется. -======= -* `useReducer` is a Hook, so you can only call it **at the top level of your component** or your own Hooks. You can't call it inside loops or conditions. If you need that, extract a new component and move the state into it. -* The `dispatch` 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) -* In Strict Mode, React will **call your reducer and initializer twice** in order to [help you find accidental impurities.](#my-reducer-or-initializer-function-runs-twice) This is development-only behavior and does not affect production. If your reducer and initializer are pure (as they should be), this should not affect your logic. The result from one of the calls is ignored. ->>>>>>> c003ac4eb130fca70b88cf3a1b80ce5f76c51ae3 ---