diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index af0a1497d..8330e30d2 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 diff --git a/src/content/reference/react/useCallback.md b/src/content/reference/react/useCallback.md index 58e8a3ddf..89b6240b3 100644 --- a/src/content/reference/react/useCallback.md +++ b/src/content/reference/react/useCallback.md @@ -709,7 +709,7 @@ function ChatRoom({ roomId }) { useEffect(() => { const options = createOptions(); - const connection = createConnection(); + const connection = createConnection(options); connection.connect(); // ... ``` @@ -720,7 +720,7 @@ function ChatRoom({ roomId }) { ```js {6} useEffect(() => { const options = createOptions(); - const connection = createConnection(); + const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [createOptions]); // ๐Ÿ”ด ๋ฌธ์ œ์ : ์ด ์˜์กด์„ฑ์€ ๋งค ๋ Œ๋”๋ง๋งˆ๋‹ค ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค. @@ -742,7 +742,7 @@ function ChatRoom({ roomId }) { useEffect(() => { const options = createOptions(); - const connection = createConnection(); + const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [createOptions]); // โœ… createOptions๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งŒ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค. @@ -764,7 +764,7 @@ function ChatRoom({ roomId }) { } const options = createOptions(); - const connection = createConnection(); + const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [roomId]); // โœ… roomId๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งŒ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค. diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index 57baf01d7..9b4be3e84 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -1056,6 +1056,82 @@ label { --- +### 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) + ### ๋‹ค๋ฅธ Hook์˜ ์ข…์†์„ฑ ๋ฉ”๋ชจํ™” {/*memoizing-a-dependency-of-another-hook*/} ์ปดํฌ๋„ŒํŠธ ๋ณธ๋ฌธ์—์„œ ์ง์ ‘ ์ƒ์„ฑ๋œ ๊ฐ์ฒด์— ์˜์กดํ•˜๋Š” ์—ฐ์‚ฐ์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. diff --git a/src/content/reference/react/useReducer.md b/src/content/reference/react/useReducer.md index 08624b1d4..9b45391f2 100644 --- a/src/content/reference/react/useReducer.md +++ b/src/content/reference/react/useReducer.md @@ -52,6 +52,7 @@ function MyComponent() { #### ์ฃผ์˜ ์‚ฌํ•ญ {/*caveats*/} * `useReducer`๋Š” Hook์ด๋ฏ€๋กœ **์ปดํฌ๋„ŒํŠธ์˜ ์ตœ์ƒ์œ„** ๋˜๋Š” ์ปค์Šคํ…€ Hook์—์„œ๋งŒ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ณต๋ฌธ์ด๋‚˜ ์กฐ๊ฑด๋ฌธ์—์„œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ƒˆ๋กœ์šด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ถ”์ถœํ•˜๊ณ  ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋กœ state๋ฅผ ์˜ฎ๊ฒจ์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +* 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) * Strict Mode์—์„œ๋Š” [์šฐ์—ฐํ•œ ๋น„์ˆœ์ˆ˜์„ฑ](#my-reducer-or-initializer-function-runs-twice)์„ ์ฐพ์•„๋‚ด๊ธฐ ์œ„ํ•ด reducer์™€ init ํ•จ์ˆ˜๋ฅผ ๋‘๋ฒˆ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋งŒ ํ•œ์ •๋œ ๋™์ž‘์ด๋ฉฐ, ๋ฐฐํฌ ๋ชจ๋“œ์—๋Š” ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. reducer์™€ init ํ•จ์ˆ˜๊ฐ€ ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋ผ๋ฉด(๊ทธ๋ž˜์•ผ๋งŒ ํ•˜๋“ฏ์ด) ๋กœ์ง์— ์–ด๋– ํ•œ ์˜ํ–ฅ๋„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ˜ธ์ถœ ์ค‘ ํ•˜๋‚˜์˜ ๊ฒฐ๊ณผ๋Š” ๋ฌด์‹œํ•ฉ๋‹ˆ๋‹ค. --- diff --git a/src/content/reference/react/useState.md b/src/content/reference/react/useState.md index 6db1c06a6..0a3d5676c 100644 --- a/src/content/reference/react/useState.md +++ b/src/content/reference/react/useState.md @@ -85,6 +85,8 @@ function handleClick() { * React๋Š” [state ์—…๋ฐ์ดํŠธ๋ฅผ batch ํ•ฉ๋‹ˆ๋‹ค. ](/learn/queueing-a-series-of-state-updates) **๋ชจ๋“  ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์‹คํ–‰๋˜๊ณ ** `set` ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ ํ›„์— ํ™”๋ฉด์„ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋‹จ์ผ ์ด๋ฒคํŠธ ์ค‘์— ์—ฌ๋Ÿฌ ๋ฒˆ ๋ฆฌ๋ Œ๋”๋ง ํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋“œ๋ฌผ์ง€๋งŒ DOM์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด React๊ฐ€ ํ™”๋ฉด์„ ๋” ์ผ์ฐ ์—…๋ฐ์ดํŠธํ•˜๋„๋ก ๊ฐ•์ œํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ, [`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) + * *๋ Œ๋”๋ง ๋„์ค‘* `set` ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์€ ํ˜„์žฌ ๋ Œ๋”๋ง ์ค‘์ธ ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ๋งŒ ํ—ˆ์šฉ๋ฉ๋‹ˆ๋‹ค. React๋Š” ํ•ด๋‹น ์ถœ๋ ฅ์„ ๋ฒ„๋ฆฌ๊ณ  ์ฆ‰์‹œ ์ƒˆ๋กœ์šด state๋กœ ๋‹ค์‹œ ๋ Œ๋”๋ง์„ ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค. ์ด ํŒจํ„ด์€ ๊ฑฐ์˜ ํ•„์š”ํ•˜์ง€ ์•Š์ง€๋งŒ **์ด์ „ ๋ Œ๋”๋ง์˜ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค**. [์•„๋ž˜ ์˜ˆ์‹œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.](#storing-information-from-previous-renders) * Strict Mode์—์„œ React๋Š” [์˜๋„์น˜์•Š์€ ๋ถˆ์ˆœ๋ฌผ์„ ์ฐพ๊ธฐ ์œ„ํ•ด](#my-initializer-or-updater-function-runs-twice) **์—…๋ฐ์ดํ„ฐ ํ•จ์ˆ˜๋ฅผ ๋‘ ๋ฒˆ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค**. ์ด๋Š” ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์ „์šฉ ๋™์ž‘์ด๋ฉฐ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—๋Š” ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์—…๋ฐ์ดํ„ฐ ํ•จ์ˆ˜๊ฐ€ ์ˆœ์ˆ˜ํ•˜๋‹ค๋ฉด(๊ทธ๋ž˜์•ผ ํ•ฉ๋‹ˆ๋‹ค) ๋™์ž‘์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ˜ธ์ถœ ์ค‘ ํ•˜๋‚˜์˜ ๊ฒฐ๊ณผ๋Š” ๋ฌด์‹œ๋ฉ๋‹ˆ๋‹ค. diff --git a/src/content/reference/react/useTransition.md b/src/content/reference/react/useTransition.md index fdc6e3157..57d5de226 100644 --- a/src/content/reference/react/useTransition.md +++ b/src/content/reference/react/useTransition.md @@ -80,6 +80,8 @@ function TabContainer() { * `startTransition`์— ์ „๋‹ฌํ•˜๋Š” ํ•จ์ˆ˜๋Š” ๋™๊ธฐ์‹์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. React๋Š” ์ด ํ•จ์ˆ˜๋ฅผ ์ฆ‰์‹œ ์‹คํ–‰ํ•˜์—ฌ ์‹คํ–‰ํ•˜๋Š” ๋™์•ˆ ๋ฐœ์ƒํ•˜๋Š” ๋ชจ๋“  state ์—…๋ฐ์ดํŠธ๋ฅผ Transition ์œผ๋กœ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ๋‚˜์ค‘์— ๋” ๋งŽ์€ state ์—…๋ฐ์ดํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ ค๊ณ  ํ•˜๋ฉด(์˜ˆ์‹œ: timeout), Transition ์œผ๋กœ ํ‘œ์‹œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. +* 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) + * Transition์œผ๋กœ ํ‘œ์‹œ๋œ state ์—…๋ฐ์ดํŠธ๋Š” ๋‹ค๋ฅธ state ์—…๋ฐ์ดํŠธ์— ์˜ํ•ด ์ค‘๋‹จ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, Transition ๋‚ด์—์„œ ์ฐจํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์—…๋ฐ์ดํŠธํ•œ ๋‹ค์Œ ์ฐจํŠธ๊ฐ€ ๋‹ค์‹œ ๋ Œ๋”๋ง ๋˜๋Š” ๋„์ค‘์— ์ž…๋ ฅ์„ ์‹œ์ž‘ํ•˜๋ฉด React๋Š” ์ž…๋ ฅ ์—…๋ฐ์ดํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•œ ํ›„ ์ฐจํŠธ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ Œ๋”๋ง ์ž‘์—…์„ ๋‹ค์‹œ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. * Transition ์—…๋ฐ์ดํŠธ๋Š” ํ…์ŠคํŠธ ์ž…๋ ฅ์„ ์ œ์–ดํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. diff --git a/src/content/reference/rsc/server-actions.md b/src/content/reference/rsc/server-actions.md index 835df3dea..59c08a06d 100644 --- a/src/content/reference/rsc/server-actions.md +++ b/src/content/reference/rsc/server-actions.md @@ -53,7 +53,7 @@ React๊ฐ€ `EmptyNote` ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•  ๋•Œ, `createNoteAction` export default function Button({onClick}) { console.log(onClick); // {$$typeof: Symbol.for("react.server.reference"), $$id: 'createNoteAction'} - return + return } ```