From 9ceb0572c9b765395684ed958feba3afb55a2503 Mon Sep 17 00:00:00 2001 From: Strek Date: Mon, 26 Feb 2024 23:41:23 +0530 Subject: [PATCH 0001/1164] =?UTF-8?q?Revert=20"fix(sandpack):=20clear=20up?= =?UTF-8?q?=20bundler=20timeout=20when=20there's=20a=20syntax=20error=20(?= =?UTF-8?q?=E2=80=A6"=20(#6663)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 081d1008dd1eebffb9550a3ff623860a7d977acf. --- package.json | 2 +- src/components/MDX/Sandpack/SandpackRoot.tsx | 2 +- yarn.lock | 50 +++++++++++--------- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 274c2506e..f75ffbb28 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "check-all": "npm-run-all prettier lint:fix tsc" }, "dependencies": { - "@codesandbox/sandpack-react": "2.13.1", + "@codesandbox/sandpack-react": "2.6.0", "@docsearch/css": "3.0.0-alpha.41", "@docsearch/react": "3.0.0-alpha.41", "@headlessui/react": "^1.7.0", diff --git a/src/components/MDX/Sandpack/SandpackRoot.tsx b/src/components/MDX/Sandpack/SandpackRoot.tsx index a47fa6860..d47fd903c 100644 --- a/src/components/MDX/Sandpack/SandpackRoot.tsx +++ b/src/components/MDX/Sandpack/SandpackRoot.tsx @@ -88,7 +88,7 @@ function SandpackRoot(props: SandpackProps) { autorun, initMode: 'user-visible', initModeObserverOptions: {rootMargin: '1400px 0px'}, - bundlerURL: 'https://786946de.sandpack-bundler-4bw.pages.dev', + bundlerURL: 'https://1e4ad8f7.sandpack-bundler-4bw.pages.dev', logLevel: SandpackLogLevel.None, }}> diff --git a/yarn.lock b/yarn.lock index 8b4000ce1..f7d63ee56 100644 --- a/yarn.lock +++ b/yarn.lock @@ -611,29 +611,29 @@ style-mod "^4.0.0" w3c-keyname "^2.2.4" -"@codesandbox/nodebox@0.1.8": - version "0.1.8" - resolved "https://registry.yarnpkg.com/@codesandbox/nodebox/-/nodebox-0.1.8.tgz#2dc701005cedefac386f17a69a4c9a4f38c2325d" - integrity sha512-2VRS6JDSk+M+pg56GA6CryyUSGPjBEe8Pnae0QL3jJF1mJZJVMDKr93gJRtBbLkfZN6LD/DwMtf+2L0bpWrjqg== +"@codesandbox/nodebox@0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@codesandbox/nodebox/-/nodebox-0.1.4.tgz#1c9ed4caf6cda764500aec3d46b245e2e9b88ccc" + integrity sha512-+MR7JibjGjTRDmyQbL8Mliej6wakQP7q99+wGL/nOzd0Q3s+YWGQfv0QpYKbdMClKUTFJGvwzwOeqHVTkpWNCQ== dependencies: - outvariant "^1.4.0" + outvariant "^1.3.0" strict-event-emitter "^0.4.3" -"@codesandbox/sandpack-client@^2.13.0": - version "2.13.0" - resolved "https://registry.yarnpkg.com/@codesandbox/sandpack-client/-/sandpack-client-2.13.0.tgz#c4e12628a3aceb4a2c99c501bea691b4276eab27" - integrity sha512-1rOLj9wkbBd3RV6/zRq+IV52egy22RQMKDTtdR+lQzy87uj0tlbYjAwtUZSjkioHlj6U8Y82uWLf71nvFIxE0g== +"@codesandbox/sandpack-client@^2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@codesandbox/sandpack-client/-/sandpack-client-2.6.0.tgz#a266ac49843a0c3263ac065daaba473cb9565193" + integrity sha512-JFCe+MU+5E+nXazrNK1uS/zLV5l4UNkYQx7AjF9sJ5ZmUlshz1HRDiK/Tdp6W+3ahcSERF3dcYPCf46LJF8Yvw== dependencies: - "@codesandbox/nodebox" "0.1.8" + "@codesandbox/nodebox" "0.1.4" buffer "^6.0.3" dequal "^2.0.2" - outvariant "1.4.0" + outvariant "1.3.0" static-browser-server "1.0.3" -"@codesandbox/sandpack-react@2.13.1": - version "2.13.1" - resolved "https://registry.yarnpkg.com/@codesandbox/sandpack-react/-/sandpack-react-2.13.1.tgz#ba69a227d0c5157bb48685a02fefc0baa83bdc09" - integrity sha512-R8oGO4QHHWTyA7r6NWHtBakizgX+rl/Rc6cbQunXGNm4vV/lqqU4NS+MVp2rXA+c8DifOLi1wA2wUZUN//Z9bw== +"@codesandbox/sandpack-react@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@codesandbox/sandpack-react/-/sandpack-react-2.6.0.tgz#2c2d98b50c9db462a32831071de7e5e710d000c2" + integrity sha512-zSeJXzaVt96aIFfkyr+bMKBjV2k3hVcX+j1+aBRIOCpHhTrbszPesUmcE3yNTzGqqQfX/JnIJNRmeqFKmSLjTQ== dependencies: "@codemirror/autocomplete" "^6.4.0" "@codemirror/commands" "^6.1.3" @@ -643,12 +643,13 @@ "@codemirror/language" "^6.3.2" "@codemirror/state" "^6.2.0" "@codemirror/view" "^6.7.1" - "@codesandbox/sandpack-client" "^2.13.0" + "@codesandbox/sandpack-client" "^2.6.0" "@lezer/highlight" "^1.1.3" "@react-hook/intersection-observer" "^3.1.1" "@stitches/core" "^1.2.6" anser "^2.1.1" clean-set "^1.1.2" + codesandbox-import-util-types "^2.2.3" dequal "^2.0.2" escape-carriage "^1.3.1" lz-string "^1.4.4" @@ -1768,6 +1769,11 @@ client-only@0.0.1: resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== +codesandbox-import-util-types@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/codesandbox-import-util-types/-/codesandbox-import-util-types-2.2.3.tgz#b354b2f732ad130e119ebd9ead3bda3be5981a54" + integrity sha512-Qj00p60oNExthP2oR3vvXmUGjukij+rxJGuiaKM6tyUmSyimdZsqHI/TUvFFClAffk9s7hxGnQgWQ8KCce27qQ== + collapse-white-space@^1.0.2: version "1.0.6" resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287" @@ -4629,16 +4635,16 @@ os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -outvariant@1.4.0, outvariant@^1.3.0: +outvariant@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.3.0.tgz#c39723b1d2cba729c930b74bf962317a81b9b1c9" + integrity sha512-yeWM9k6UPfG/nzxdaPlJkB2p08hCg4xP6Lx99F+vP8YF7xyZVfTmJjrrNalkmzudD4WFvNLVudQikqUmF8zhVQ== + +outvariant@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.4.0.tgz#e742e4bda77692da3eca698ef5bfac62d9fba06e" integrity sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw== -outvariant@^1.4.0: - version "1.4.2" - resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.4.2.tgz#f54f19240eeb7f15b28263d5147405752d8e2066" - integrity sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ== - p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" From 41b1bb3b7c440c108f4fa95fbca172564feda10f Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 26 Feb 2024 19:54:43 +0000 Subject: [PATCH 0002/1164] Update Dan's twitter link --- src/content/community/team.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/community/team.md b/src/content/community/team.md index 9ef95d64a..2ea4e79b8 100644 --- a/src/content/community/team.md +++ b/src/content/community/team.md @@ -22,7 +22,7 @@ Current members of the React team are listed in alphabetical order below. Andrey started his career as a designer and then gradually transitioned into web development. After joining the React Data team at Meta he worked on adding an incremental JavaScript compiler to Relay, and then later on, worked on removing the same compiler from Relay. Outside of work, Andrey likes to play music and engage in various sports. - + Dan got into programming after he accidentally discovered Visual Basic inside Microsoft PowerPoint. He has found his true calling in turning [Sebastian](#sebastian-markbåge)'s tweets into long-form blog posts. Dan occasionally wins at Fortnite by hiding in a bush until the game ends. From 6d8e094d33a790b587f776377d6dddf6e91c60c6 Mon Sep 17 00:00:00 2001 From: Danilo Woznica Date: Tue, 27 Feb 2024 19:29:37 +0000 Subject: [PATCH 0003/1164] fix: Update @codesandbox/sandpack-react version to 2.13.4 (#6664) * fix: Update @codesandbox/sandpack-react version to 2.13.3 * fix: Fixed bundlerURL to use the correct URL * fix: Update @codesandbox/sandpack-react to version 2.13.4 * style: Hide span element in sp-icon-standalone when loading --- package.json | 2 +- src/components/MDX/Sandpack/SandpackRoot.tsx | 2 +- src/styles/sandpack.css | 4 ++ yarn.lock | 50 +++++++++----------- 4 files changed, 28 insertions(+), 30 deletions(-) diff --git a/package.json b/package.json index f75ffbb28..8fe0f4ca2 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "check-all": "npm-run-all prettier lint:fix tsc" }, "dependencies": { - "@codesandbox/sandpack-react": "2.6.0", + "@codesandbox/sandpack-react": "2.13.4", "@docsearch/css": "3.0.0-alpha.41", "@docsearch/react": "3.0.0-alpha.41", "@headlessui/react": "^1.7.0", diff --git a/src/components/MDX/Sandpack/SandpackRoot.tsx b/src/components/MDX/Sandpack/SandpackRoot.tsx index d47fd903c..a47fa6860 100644 --- a/src/components/MDX/Sandpack/SandpackRoot.tsx +++ b/src/components/MDX/Sandpack/SandpackRoot.tsx @@ -88,7 +88,7 @@ function SandpackRoot(props: SandpackProps) { autorun, initMode: 'user-visible', initModeObserverOptions: {rootMargin: '1400px 0px'}, - bundlerURL: 'https://1e4ad8f7.sandpack-bundler-4bw.pages.dev', + bundlerURL: 'https://786946de.sandpack-bundler-4bw.pages.dev', logLevel: SandpackLogLevel.None, }}> diff --git a/src/styles/sandpack.css b/src/styles/sandpack.css index dee08769c..d909f7221 100644 --- a/src/styles/sandpack.css +++ b/src/styles/sandpack.css @@ -608,3 +608,7 @@ html.dark .sp-devtools > div { } } } + +.sp-loading .sp-icon-standalone span { + display: none; +} diff --git a/yarn.lock b/yarn.lock index f7d63ee56..9baa44954 100644 --- a/yarn.lock +++ b/yarn.lock @@ -611,29 +611,29 @@ style-mod "^4.0.0" w3c-keyname "^2.2.4" -"@codesandbox/nodebox@0.1.4": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@codesandbox/nodebox/-/nodebox-0.1.4.tgz#1c9ed4caf6cda764500aec3d46b245e2e9b88ccc" - integrity sha512-+MR7JibjGjTRDmyQbL8Mliej6wakQP7q99+wGL/nOzd0Q3s+YWGQfv0QpYKbdMClKUTFJGvwzwOeqHVTkpWNCQ== +"@codesandbox/nodebox@0.1.8": + version "0.1.8" + resolved "https://registry.yarnpkg.com/@codesandbox/nodebox/-/nodebox-0.1.8.tgz#2dc701005cedefac386f17a69a4c9a4f38c2325d" + integrity sha512-2VRS6JDSk+M+pg56GA6CryyUSGPjBEe8Pnae0QL3jJF1mJZJVMDKr93gJRtBbLkfZN6LD/DwMtf+2L0bpWrjqg== dependencies: - outvariant "^1.3.0" + outvariant "^1.4.0" strict-event-emitter "^0.4.3" -"@codesandbox/sandpack-client@^2.6.0": - version "2.6.0" - resolved "https://registry.yarnpkg.com/@codesandbox/sandpack-client/-/sandpack-client-2.6.0.tgz#a266ac49843a0c3263ac065daaba473cb9565193" - integrity sha512-JFCe+MU+5E+nXazrNK1uS/zLV5l4UNkYQx7AjF9sJ5ZmUlshz1HRDiK/Tdp6W+3ahcSERF3dcYPCf46LJF8Yvw== +"@codesandbox/sandpack-client@^2.13.2": + version "2.13.2" + resolved "https://registry.yarnpkg.com/@codesandbox/sandpack-client/-/sandpack-client-2.13.2.tgz#8e573e96d341d3284ce579a71c6c57f16aefc80e" + integrity sha512-uAuxQOF7p8y4m7H0ojedDcWRf62xVK7UIYIJoX5LkhcV0SW1BTXcRkVNuR0/MSCSv+Og1dBeV8+Xpye9PX0quA== dependencies: - "@codesandbox/nodebox" "0.1.4" + "@codesandbox/nodebox" "0.1.8" buffer "^6.0.3" dequal "^2.0.2" - outvariant "1.3.0" + outvariant "1.4.0" static-browser-server "1.0.3" -"@codesandbox/sandpack-react@2.6.0": - version "2.6.0" - resolved "https://registry.yarnpkg.com/@codesandbox/sandpack-react/-/sandpack-react-2.6.0.tgz#2c2d98b50c9db462a32831071de7e5e710d000c2" - integrity sha512-zSeJXzaVt96aIFfkyr+bMKBjV2k3hVcX+j1+aBRIOCpHhTrbszPesUmcE3yNTzGqqQfX/JnIJNRmeqFKmSLjTQ== +"@codesandbox/sandpack-react@2.13.4": + version "2.13.4" + resolved "https://registry.yarnpkg.com/@codesandbox/sandpack-react/-/sandpack-react-2.13.4.tgz#d079da898e54a5546cfbeea13e4c3549b20f58a6" + integrity sha512-lgfcOwWAA+JKztLL5fwZ89389WvBMBl2R2BwE+RfnYKLIfgZ2UGH2Kifly4pam2iFqIzxPER7rYZJh/keSJQbg== dependencies: "@codemirror/autocomplete" "^6.4.0" "@codemirror/commands" "^6.1.3" @@ -643,13 +643,12 @@ "@codemirror/language" "^6.3.2" "@codemirror/state" "^6.2.0" "@codemirror/view" "^6.7.1" - "@codesandbox/sandpack-client" "^2.6.0" + "@codesandbox/sandpack-client" "^2.13.2" "@lezer/highlight" "^1.1.3" "@react-hook/intersection-observer" "^3.1.1" "@stitches/core" "^1.2.6" anser "^2.1.1" clean-set "^1.1.2" - codesandbox-import-util-types "^2.2.3" dequal "^2.0.2" escape-carriage "^1.3.1" lz-string "^1.4.4" @@ -1769,11 +1768,6 @@ client-only@0.0.1: resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== -codesandbox-import-util-types@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/codesandbox-import-util-types/-/codesandbox-import-util-types-2.2.3.tgz#b354b2f732ad130e119ebd9ead3bda3be5981a54" - integrity sha512-Qj00p60oNExthP2oR3vvXmUGjukij+rxJGuiaKM6tyUmSyimdZsqHI/TUvFFClAffk9s7hxGnQgWQ8KCce27qQ== - collapse-white-space@^1.0.2: version "1.0.6" resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287" @@ -4635,16 +4629,16 @@ os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -outvariant@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.3.0.tgz#c39723b1d2cba729c930b74bf962317a81b9b1c9" - integrity sha512-yeWM9k6UPfG/nzxdaPlJkB2p08hCg4xP6Lx99F+vP8YF7xyZVfTmJjrrNalkmzudD4WFvNLVudQikqUmF8zhVQ== - -outvariant@^1.3.0: +outvariant@1.4.0, outvariant@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.4.0.tgz#e742e4bda77692da3eca698ef5bfac62d9fba06e" integrity sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw== +outvariant@^1.4.0: + version "1.4.2" + resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.4.2.tgz#f54f19240eeb7f15b28263d5147405752d8e2066" + integrity sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ== + p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" From 6e650f9dc656f9670d1d7cebe1e6a7cf19e762de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s?= <72570859+tomihq@users.noreply.github.com> Date: Thu, 29 Feb 2024 08:37:35 -0300 Subject: [PATCH 0004/1164] update: "Configuring TypeScript" link for Next.js App Directory - to updated docs (#6669) --- src/content/learn/typescript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index 034ac0d46..c2b1a9948 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -22,7 +22,7 @@ TypeScript is a popular way to add type definitions to JavaScript codebases. Out All [production-grade React frameworks](/learn/start-a-new-react-project#production-grade-react-frameworks) offer support for using TypeScript. Follow the framework specific guide for installation: -- [Next.js](https://nextjs.org/docs/pages/building-your-application/configuring/typescript) +- [Next.js](https://nextjs.org/docs/app/building-your-application/configuring/typescript) - [Remix](https://remix.run/docs/en/1.19.2/guides/typescript) - [Gatsby](https://www.gatsbyjs.com/docs/how-to/custom-configuration/typescript/) - [Expo](https://docs.expo.dev/guides/typescript/) From 6310c8a9d4b414f05fe8d9cb89f63744c9745298 Mon Sep 17 00:00:00 2001 From: Ricky Date: Fri, 1 Mar 2024 14:38:24 -0500 Subject: [PATCH 0005/1164] Add /link redirects (#6670) * Add /link redirects * Update event pooling redirect --- vercel.json | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/vercel.json b/vercel.json index 5e1fbd329..e337b9890 100644 --- a/vercel.json +++ b/vercel.json @@ -13,6 +13,137 @@ "source": "/learn/meet-the-team", "destination": "/community/team", "permanent": true + }, + { + "source": "/link/warning-keys", + "destination": "/learn/rendering-lists#keeping-list-items-in-order-with-key", + "permanent": false + }, + + { + "source": "/link/invalid-hook-call", + "destination": "/warnings/invalid-hook-call-warning", + "permanent": false + }, + { + "source": "/link/hooks-data-fetching", + "destination": "/reference/react/useEffect#fetching-data-with-effects", + "permanent": false + }, + { + "source": "/link/special-props", + "destination": "/warnings/special-props", + "permanent": false + }, + { + "source": "/link/dangerously-set-inner-html", + "destination": "/reference/react-dom/components/common#dangerously-setting-the-inner-html", + "permanent": false + }, + { + "source": "/link/controlled-components", + "destination": "/reference/react-dom/components/input#controlling-an-input-with-a-state-variable", + "permanent": false + }, + { + "source": "/link/react-devtools", + "destination": "/learn/react-developer-tools", + "permanent": false + }, + { + "source": "/link/invalid-aria-props", + "destination": "/warnings/invalid-aria-prop", + "permanent": false + }, + { + "source": "/link/switch-to-createroot", + "destination": "/blog/2022/03/08/react-18-upgrade-guide#updates-to-client-rendering-apis", + "permanent": false + }, + { + "source": "/link/error-boundaries", + "destination": "/reference/react/Component#catching-rendering-errors-with-an-error-boundary", + "permanent": false + }, + { + "source": "/link/strict-mode-find-node", + "destination": "/reference/react-dom/findDOMNode#alternatives", + "permanent": false + }, + { + "source": "/link/rules-of-hooks", + "destination": "/warnings/invalid-hook-call-warning", + "permanent": false + }, + { + "source": "/link/event-pooling", + "destination": "https://legacy.reactjs.org/docs/legacy-event-pooling.html", + "permanent": false + }, + { + "source": "/link/legacy-context", + "destination": "https://legacy.reactjs.org/docs/legacy-context.html", + "permanent": false + }, + { + "source": "/link/crossorigin-error", + "destination": "https://legacy.reactjs.org/docs/cross-origin-errors.html", + "permanent": false + }, + { + "source": "/link/react-polyfills", + "destination": "https://legacy.reactjs.org/docs/javascript-environment-requirements.html", + "permanent": false + }, + { + "source": "/link/wrap-tests-with-act", + "destination": "https://legacy.reactjs.org/docs/test-utils.html#act", + "permanent": false + }, + { + "source": "/link/refs-must-have-owner", + "destination": "https://legacy.reactjs.org/warnings/refs-must-have-owner.html", + "permanent": false + }, + { + "source": "/link/derived-state", + "destination": "https://legacy.reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html", + "permanent": false + }, + { + "source": "/link/strict-mode-string-ref", + "destination": "https://legacy.reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs", + "permanent": false + }, + { + "source": "/link/perf-use-production-build", + "destination": "https://legacy.reactjs.org/docs/optimizing-performance.html#use-the-production-build", + "permanent": false + }, + { + "source": "/link/unsafe-component-lifecycles", + "destination": "https://legacy.reactjs.org/blog/2018/03/27/update-on-async-rendering.html", + "permanent": false + }, + { + "source": "/link/test-utils-mock-component", + "destination": "https://gist.github.com/bvaughn/fbf41b3f895bf2d297935faa5525eee9", + "permanent": false + }, + { + "source": "/link/attribute-behavior", + "destination": "https://legacy.reactjs.org/blog/2017/09/08/dom-attributes-in-react-16.html#changes-in-detail", + "permanent": false + }, + { + "source": "/link/react-devtools-faq", + "destination": "https://github.com/facebook/react/tree/main/packages/react-devtools#faq", + "permanent": false + }, + { + "source": "/link/setstate-in-render", + "destination": "https://github.com/facebook/react/issues/18178#issuecomment-595846312", + "permanent": false } ], "headers": [ From 265fa26e3b39739f06c956140d9acf618c6b4e6b Mon Sep 17 00:00:00 2001 From: Matt Michel Date: Sun, 3 Mar 2024 22:26:51 +0000 Subject: [PATCH 0006/1164] Update small typo in useDeferredValue.md (#6673) * Update useDeferredValue.md change text from "re-render in background" to "re-render in the background" * Update useDeferredValue.md Change instances of "in background" to "in the background". --- src/content/reference/react/useDeferredValue.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/content/reference/react/useDeferredValue.md b/src/content/reference/react/useDeferredValue.md index dcd8f98d0..f97bf0a28 100644 --- a/src/content/reference/react/useDeferredValue.md +++ b/src/content/reference/react/useDeferredValue.md @@ -40,7 +40,7 @@ function SearchPage() { #### Returns {/*returns*/} -During the initial render, the returned deferred value will be the same as the value you provided. During updates, React will first attempt a re-render with the old value (so it will return the old value), and then try another re-render in background with the new value (so it will return the updated value). +During the initial render, the returned deferred value will be the same as the value you provided. During updates, React will first attempt a re-render with the old value (so it will return the old value), and then try another re-render in the background with the new value (so it will return the updated value). #### Caveats {/*caveats*/} @@ -76,7 +76,7 @@ function SearchPage() { During the initial render, the deferred value will be the same as the value you provided. -During updates, the deferred value will "lag behind" the latest value. In particular, React will first re-render *without* updating the deferred value, and then try to re-render with the newly received value in background. +During updates, the deferred value will "lag behind" the latest value. In particular, React will first re-render *without* updating the deferred value, and then try to re-render with the newly received value in the background. **Let's walk through an example to see when this is useful.** @@ -508,7 +508,7 @@ You can think of it as happening in two steps: 1. **First, React re-renders with the new `query` (`"ab"`) but with the old `deferredQuery` (still `"a")`.** The `deferredQuery` value, which you pass to the result list, is *deferred:* it "lags behind" the `query` value. -2. **In background, React tries to re-render with *both* `query` and `deferredQuery` updated to `"ab"`.** If this re-render completes, React will show it on the screen. However, if it suspends (the results for `"ab"` have not loaded yet), React will abandon this rendering attempt, and retry this re-render again after the data has loaded. The user will keep seeing the stale deferred value until the data is ready. +2. **In the background, React tries to re-render with *both* `query` and `deferredQuery` updated to `"ab"`.** If this re-render completes, React will show it on the screen. However, if it suspends (the results for `"ab"` have not loaded yet), React will abandon this rendering attempt, and retry this re-render again after the data has loaded. The user will keep seeing the stale deferred value until the data is ready. The deferred "background" rendering is interruptible. For example, if you type into the input again, React will abandon it and restart with the new value. React will always use the latest provided value. @@ -952,7 +952,7 @@ While these techniques are helpful in some cases, `useDeferredValue` is better s Unlike debouncing or throttling, it doesn't require choosing any fixed delay. If the user's device is fast (e.g. powerful laptop), the deferred re-render would happen almost immediately and wouldn't be noticeable. If the user's device is slow, the list would "lag behind" the input proportionally to how slow the device is. -Also, unlike with debouncing or throttling, deferred re-renders done by `useDeferredValue` are interruptible by default. This means that if React is in the middle of re-rendering a large list, but the user makes another keystroke, React will abandon that re-render, handle the keystroke, and then start rendering in background again. By contrast, debouncing and throttling still produce a janky experience because they're *blocking:* they merely postpone the moment when rendering blocks the keystroke. +Also, unlike with debouncing or throttling, deferred re-renders done by `useDeferredValue` are interruptible by default. This means that if React is in the middle of re-rendering a large list, but the user makes another keystroke, React will abandon that re-render, handle the keystroke, and then start rendering in the background again. By contrast, debouncing and throttling still produce a janky experience because they're *blocking:* they merely postpone the moment when rendering blocks the keystroke. If the work you're optimizing doesn't happen during rendering, debouncing and throttling are still useful. For example, they can let you fire fewer network requests. You can also use these techniques together. From 716e8896204aecaaa13a199f9c41998fde62f61f Mon Sep 17 00:00:00 2001 From: Ricky Date: Mon, 4 Mar 2024 17:28:18 -0500 Subject: [PATCH 0007/1164] Add hydration-mismatch link (#6678) --- vercel.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vercel.json b/vercel.json index e337b9890..8d610c26e 100644 --- a/vercel.json +++ b/vercel.json @@ -55,6 +55,11 @@ "destination": "/warnings/invalid-aria-prop", "permanent": false }, + { + "source": "/link/hydration-mismatch", + "destination": "/reference/react-dom/client/hydrateRoot#hydrating-server-rendered-html", + "permanent": false + }, { "source": "/link/switch-to-createroot", "destination": "/blog/2022/03/08/react-18-upgrade-guide#updates-to-client-rendering-apis", From 5de85198a3c575d94a395138e3f471cc7172a51c Mon Sep 17 00:00:00 2001 From: Danilo Woznica Date: Fri, 8 Mar 2024 15:05:50 +0000 Subject: [PATCH 0008/1164] fix: Update sandpack-react version to 2.13.5 (#6668) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8fe0f4ca2..787756833 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "check-all": "npm-run-all prettier lint:fix tsc" }, "dependencies": { - "@codesandbox/sandpack-react": "2.13.4", + "@codesandbox/sandpack-react": "2.13.5", "@docsearch/css": "3.0.0-alpha.41", "@docsearch/react": "3.0.0-alpha.41", "@headlessui/react": "^1.7.0", diff --git a/yarn.lock b/yarn.lock index 9baa44954..b20c796ef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -630,10 +630,10 @@ outvariant "1.4.0" static-browser-server "1.0.3" -"@codesandbox/sandpack-react@2.13.4": - version "2.13.4" - resolved "https://registry.yarnpkg.com/@codesandbox/sandpack-react/-/sandpack-react-2.13.4.tgz#d079da898e54a5546cfbeea13e4c3549b20f58a6" - integrity sha512-lgfcOwWAA+JKztLL5fwZ89389WvBMBl2R2BwE+RfnYKLIfgZ2UGH2Kifly4pam2iFqIzxPER7rYZJh/keSJQbg== +"@codesandbox/sandpack-react@2.13.5": + version "2.13.5" + resolved "https://registry.yarnpkg.com/@codesandbox/sandpack-react/-/sandpack-react-2.13.5.tgz#bc4b3fe43b74fdb011f69d3d9a117415110c709e" + integrity sha512-MWzh2P/Asck0JSCKY3y7WecdUBBEqB0NFi4p+ohoZMTYqHWTaYfd7nbPlNmGIE1xcGppSZEqPVDjOpAfeQ0zFw== dependencies: "@codemirror/autocomplete" "^6.4.0" "@codemirror/commands" "^6.1.3" From 9154cea94a0d523ca0ac8e2eef32a9c2e5b8a16e Mon Sep 17 00:00:00 2001 From: Lee Keun Hwee <56650238+Geuni620@users.noreply.github.com> Date: Mon, 11 Mar 2024 21:58:58 +0900 Subject: [PATCH 0009/1164] =?UTF-8?q?fix:=20=EC=98=A4=ED=83=80=20=EB=B0=8F?= =?UTF-8?q?=20=EB=A7=81=ED=81=AC=EC=88=98=EC=A0=95=20(#876)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: link * fix: typo * fix: remove duplicate links --- src/content/learn/referencing-values-with-refs.md | 2 +- src/content/learn/removing-effect-dependencies.md | 2 +- src/content/learn/synchronizing-with-effects.md | 2 +- src/content/learn/writing-markup-with-jsx.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/content/learn/referencing-values-with-refs.md b/src/content/learn/referencing-values-with-refs.md index a3ee56470..f1b441baa 100644 --- a/src/content/learn/referencing-values-with-refs.md +++ b/src/content/learn/referencing-values-with-refs.md @@ -271,7 +271,7 @@ React는 `useRef`가 실제로 충분히 일반적이기 때문에 built-in 버 - **refs를 escape hatch로 간주합니다.** Refs는 외부 시스템이나 브라우저 API로 작업할 때 유용합니다. 애플리케이션 로직과 데이터 흐름의 상당 부분이 refs에 의존한다면 접근 방식을 재고해 보는 것이 좋습니다. - **렌더링 중에 `ref.current`를 읽거나 쓰지 마세요.** 렌더링 중에 일부 정보가 필요한 경우 [state](/learn/state-a-components-memory)를 대신 사용하세요. `ref.current`가 언제 변하는지 React는 모르기 때문에 렌더링할 때 읽어도 컴포넌트의 동작을 예측하기 어렵습니다. (`if (!ref.current) ref.current = new Thing()` 과 같은 코드는 첫 번째 렌더 중에 ref를 한 번만 설정하는 경우가 예외입니다.) -React state의 제한은 refs에 적용되지 않습니다. 예를 들어 state는 [모든 render에 대한 snapshot](/learn/state-as-a-snapshot) 및 [동기적으로 업데이트되지 않는 것](/learn/queue-a-series-the-updates)과 같이 작동합니다. 그러나 ref의 current 값을 변조하면 다음과 같이 즉시 변경됩니다. +React state의 제한은 refs에 적용되지 않습니다. 예를 들어 state는 [모든 render에 대한 snapshot](/learn/state-as-a-snapshot) 및 [동기적으로 업데이트되지 않는 것](/learn/queueing-a-series-of-state-updates)과 같이 작동합니다. 그러나 ref의 current 값을 변조하면 다음과 같이 즉시 변경됩니다. ```js ref.current = 5; diff --git a/src/content/learn/removing-effect-dependencies.md b/src/content/learn/removing-effect-dependencies.md index f727eeb99..4e505f1a0 100644 --- a/src/content/learn/removing-effect-dependencies.md +++ b/src/content/learn/removing-effect-dependencies.md @@ -891,7 +891,7 @@ console.log(Object.is(options1, options2)); // false #### 정적 객체와 함수를 컴포넌트 외부로 이동 {/*move-static-objects-and-functions-outside-your-component*/} -객체가 프롶티 및 State에 의존하지 않는 경우 해당 객체를 컴포넌트 외부로 이동할 수 있습니다. +객체가 props 및 State에 의존하지 않는 경우 해당 객체를 컴포넌트 외부로 이동할 수 있습니다. ```js {1-4,13} const options = { diff --git a/src/content/learn/synchronizing-with-effects.md b/src/content/learn/synchronizing-with-effects.md index 7f15006dc..a661071dd 100644 --- a/src/content/learn/synchronizing-with-effects.md +++ b/src/content/learn/synchronizing-with-effects.md @@ -696,7 +696,7 @@ function TodoList() { #### Effect에서 데이터를 가져오는 좋은 대안은 무엇인가요? {/*what-are-good-alternatives-to-data-fetching-in-effects*/} -Effect 안에서 `fetch` 호출을 작성하는 것은 [데이터를 가져오는](https://www.robinwieruch.de/react-hooks-fetch-data/) [인기 있는 방법](https://www.robinwieruch.de/react-hooks-fetch-data/)입니다, 특히 완전히 클라이언트 측 앱에서는요. 하지만 이는 매우 수동적인 접근 방식이며 중요한 단점이 있습니다. +Effect 안에서 `fetch` 호출을 작성하는 것은 [데이터를 가져오는 인기 있는 방법](https://www.robinwieruch.de/react-hooks-fetch-data/)입니다, 특히 완전히 클라이언트 측 앱에서는요. 하지만 이는 매우 수동적인 접근 방식이며 중요한 단점이 있습니다. - **Effect는 서버에서 실행되지 않습니다.** 따라서 초기 서버 렌더링된 HTML은 데이터가 없는 로딩 상태만 포함하게 됩니다. 클라이언트 컴퓨터는 모든 JavaScript를 다운로드하고 앱을 렌더링해야만 데이터를 로드해야 한다는 것을 알게 될 것입니다. 이는 효율적이지 않습니다. - **Effect 안에서 직접 가져오면 "네트워크 폭포"를 쉽게 만들 수 있습니다.** 부모 컴포넌트를 렌더링하면 일부 데이터를 가져오고 자식 컴포넌트를 렌더링한 다음 그들이 데이터를 가져오기 시작합니다. 네트워크가 빠르지 않으면 이는 모든 데이터를 병렬로 가져오는 것보다 훨씬 느립니다. diff --git a/src/content/learn/writing-markup-with-jsx.md b/src/content/learn/writing-markup-with-jsx.md index 2b84132e3..993031609 100644 --- a/src/content/learn/writing-markup-with-jsx.md +++ b/src/content/learn/writing-markup-with-jsx.md @@ -60,7 +60,7 @@ JavaScript -JSX와 React는 서로 다른 별개의 개념입니다. 종종 함께 사용되기도 하지만 [독립적으로](/blog/2020/09/22/introducing-the-new-jsx-transform.html#whats-a-jsx-transform) 사용할 수도 있습니다. JSX는 확장된 문법이고, React는 JavaScript 라이브러리입니다. +JSX와 React는 서로 다른 별개의 개념입니다. 종종 함께 사용되기도 하지만 [독립적으로](https://ko.legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html#whats-a-jsx-transform) 사용할 수도 있습니다. JSX는 확장된 문법이고, React는 JavaScript 라이브러리입니다. From 988e6a639e1906081a0bf2cdbd8506c74349ae39 Mon Sep 17 00:00:00 2001 From: Dong uk Kim Date: Mon, 11 Mar 2024 22:01:42 +0900 Subject: [PATCH 0010/1164] Translate reference hooks (#877) * Translate reference react-dom * Delete original text * Add missing translate * Update index.md --- src/content/reference/react-dom/hooks/index.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/content/reference/react-dom/hooks/index.md b/src/content/reference/react-dom/hooks/index.md index 937de808c..ec673ba01 100644 --- a/src/content/reference/react-dom/hooks/index.md +++ b/src/content/reference/react-dom/hooks/index.md @@ -4,24 +4,24 @@ title: "Built-in React DOM Hooks" -The `react-dom` package contains Hooks that are only supported for web applications (which run in the browser DOM environment). These Hooks are not supported in non-browser environments like iOS, Android, or Windows applications. If you are looking for Hooks that are supported in web browsers *and other environments* see [the React Hooks page](/reference/react). This page lists all the Hooks in the `react-dom` package. +`react-dom` 패키지는 웹 애플리케이션만 지원하는 Hook을 포함하고 있습니다. 이 Hook은 iOS, 안드로이드, Windows 애플리케이션과 같은 브라우저가 아닌 환경들은 지원하지 않습니다. 웹 브라우저뿐만 아니라 *다른 환경*에서도 지원되는 Hook을 찾고 있다면 [the React Hooks page](/reference/react)를 참고하세요. 이 페이지는 `react-dom` 패키지에 포함된 모든 Hook을 나열하고 있습니다. --- -## Form Hooks {/*form-hooks*/} +## 폼 Hooks {/*form-hooks*/} -Form Hooks are currently only available in React's canary and experimental channels. Learn more about [React's release channels here](/community/versioning-policy#all-release-channels). +폼 Hook은 현재 React의 Canary 채널과 실험적인 채널에서만 사용할 수 있습니다. 자세한 내용은 [React 릴리즈 채널](/community/versioning-policy#all-release-channels)에서 확인할 수 있습니다. -*Forms* let you create interactive controls for submitting information. To manage forms in your components, use one of these Hooks: +*폼*은 정보 제출을 위한 상호 작용형 제어를 만들 수 있도록 해줍니다. 컴포넌트에 있는 폼을 관리하기 위해 다음과 같은 훅 중 하나를 사용할 수 있습니다. -* [`useFormStatus`](/reference/react-dom/hooks/useFormStatus) allows you to make updates to the UI based on the status of the a form. -* [`useFormState`](/reference/react-dom/hooks/useFormState) allows you to manage state inside a form. +* [`useFormStatus`](/reference/react-dom/hooks/useFormStatus) 폼의 상태에 따라 UI를 업데이트할 수 있게 해줍니다. +* [`useFormState`](/reference/react-dom/hooks/useFormState) 폼 안에 있는 state를 관리할 수 있게 해줍니다. ```js function Form({ action }) { From a23fb44d0469b5f5f9b6275963bead37b24072c6 Mon Sep 17 00:00:00 2001 From: "Joonwoo Jang (Percy)" Date: Mon, 11 Mar 2024 21:02:13 +0800 Subject: [PATCH 0011/1164] translate: Code comments for useEffect (#873) Co-authored-by: Haegul Pyun --- src/content/reference/react/useEffect.md | 78 ++++++++++++------------ 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/src/content/reference/react/useEffect.md b/src/content/reference/react/useEffect.md index 45fc15417..6abe7850c 100644 --- a/src/content/reference/react/useEffect.md +++ b/src/content/reference/react/useEffect.md @@ -196,7 +196,7 @@ export default function App() { ```js src/chat.js export function createConnection(serverUrl, roomId) { - // A real implementation would actually connect to the server + // 실제 구현은 실제로 서버에 연결됩니다. return { connect() { console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...'); @@ -616,7 +616,7 @@ export function useChatRoom({ serverUrl, roomId }) { ```js src/chat.js export function createConnection(serverUrl, roomId) { - // A real implementation would actually connect to the server + // 실제 구현은 실제로 서버에 연결됩니다. return { connect() { console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...'); @@ -1062,14 +1062,14 @@ Effect 내부에서 `fetch` 호출을 작성하는 것은 클라이언트 사이 **Effect의 의존성을 "선택"할 수 없다는 점에 유의하세요.** Effect 코드에서 사용하는 모든 반응형 값은 의존성으로 선언되어야 합니다. Effect의 의존성 배열은 코드에 의해 결정됩니다. ```js [[2, 1, "roomId"], [2, 2, "serverUrl"], [2, 5, "serverUrl"], [2, 5, "roomId"], [2, 8, "serverUrl"], [2, 8, "roomId"]] -function ChatRoom({ roomId }) { // This is a reactive value - const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // This is a reactive value too +function ChatRoom({ roomId }) { // 이것은 반응형 값입니다 + const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // 이것도 반응형 값입니다 useEffect(() => { - const connection = createConnection(serverUrl, roomId); // This Effect reads these reactive values + const connection = createConnection(serverUrl, roomId); // 이 Effect는 이 반응형 값들을 읽습니다 connection.connect(); return () => connection.disconnect(); - }, [serverUrl, roomId]); // ✅ So you must specify them as dependencies of your Effect + }, [serverUrl, roomId]); // ✅ 그래서 이 값들을 Effect의 의존성으로 지정해야 합니다 // ... } ``` @@ -1094,14 +1094,14 @@ function ChatRoom({ roomId }) { **의존성을 제거하려면 [그것이 의존성이 되지 않아야 함을 린터에 증명해야 합니다.](/learn/removing-effect-dependencies#removing-unnecessary-dependencies)** 예를 들어, `serverUrl` 을 컴포넌트 밖으로 이동하여 그것이 반응적이지 않고 리렌더링될 때 변경되지 않을 것임을 증명할 수 있습니다. ```js {1,8} -const serverUrl = 'https://localhost:1234'; // Not a reactive value anymore +const serverUrl = 'https://localhost:1234'; // 더 이상 반응형 값이 아님 function ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); - }, [roomId]); // ✅ All dependencies declared + }, [roomId]); // ✅ 모든 의존성이 선언됨 // ... } ``` @@ -1109,15 +1109,15 @@ function ChatRoom({ roomId }) { 이제 `serverUrl`은 반응형 값이 아니며 (리렌더링될 때 변경되지 않을 것이므로), 의존성에 추가할 필요가 없습니다. **Effect의 코드가 어떤 반응형 값도 사용하지 않는다면 그 의존성 목록은 비어있어야 합니다. (`[]`)** ```js {1,2,9} -const serverUrl = 'https://localhost:1234'; // Not a reactive value anymore -const roomId = 'music'; // Not a reactive value anymore +const serverUrl = 'https://localhost:1234'; // 더 이상 반응형 값이 아님 +const roomId = 'music'; // 더 이상 반응형 값이 아님 function ChatRoom() { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); - }, []); // ✅ All dependencies declared + }, []); // ✅ 모든 의존성이 선언됨 // ... } ``` @@ -1149,7 +1149,7 @@ useEffect(() => { ```js {3} useEffect(() => { // ... -}, [a, b]); // Runs again if a or b are different +}, [a, b]); // a나 b가 다르면 다시 실행됨 ``` 아래 예제에서는 `serverUrl`와 `roomId`은 [반응형 값](/learn/lifecycle-of-reactive-effects#effects-react-to-reactive-values)이므로 둘 다 의존성으로 지정해야 합니다. 결과적으로 드롭다운에서 다른 방을 선택하거나 서버 URL 입력을 편집하면 채팅이 다시 연결됩니다. 그러나 `message`는 Effect에서 사용되지 않으므로(의존성이 아니므로), 메세지를 편집해도 대화가 다시 연결되지 않습니다. @@ -1218,7 +1218,7 @@ export default function App() { ```js src/chat.js export function createConnection(serverUrl, roomId) { - // A real implementation would actually connect to the server + // 실제 구현은 실제로 서버에 연결됩니다. return { connect() { console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...'); @@ -1246,7 +1246,7 @@ button { margin-left: 5px; } ```js {3} useEffect(() => { // ... -}, []); // Does not run again (except once in development) +}, []); // 다시 실행되지 않음 (개발 환경에서만 한번 실행) ``` **개발 환경에서는 빈 의존성 배열이 있더라도 버그를 찾기 위해 설정과 정리가 [한번 더 실행됩니다.](/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development)** @@ -1298,7 +1298,7 @@ export default function App() { ```js src/chat.js export function createConnection(serverUrl, roomId) { - // A real implementation would actually connect to the server + // 실제 구현은 실제로 서버에 연결됩니다. return { connect() { console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...'); @@ -1322,7 +1322,7 @@ export function createConnection(serverUrl, roomId) { ```js {3} useEffect(() => { // ... -}); // Always runs again +}); // 항상 다시 실행됨 ``` 이 예제에서 Effect는 `serverUrl`과 `roomId`를 변경할 때 다시 실행하는 것은 합리적입니다. 그러나 `message`를 변경할때도 다시 실행되므로 바람직하지 않습니다. 보통은 이런 이슈를 방지하고자 의존성 배열을 명시합니다. @@ -1343,7 +1343,7 @@ function ChatRoom({ roomId }) { return () => { connection.disconnect(); }; - }); // No dependency array at all + }); // 의존성 배열이 아예 없음 return ( <> @@ -1391,7 +1391,7 @@ export default function App() { ```js src/chat.js export function createConnection(serverUrl, roomId) { - // A real implementation would actually connect to the server + // 실제 구현은 실제로 서버에 연결됩니다. return { connect() { console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...'); @@ -1426,10 +1426,10 @@ function Counter() { useEffect(() => { const intervalId = setInterval(() => { - setCount(count + 1); // You want to increment the counter every second... + setCount(count + 1); // 초마다 카운터를 증가시키고 싶습니다... }, 1000) return () => clearInterval(intervalId); - }, [count]); // 🚩 ... but specifying `count` as a dependency always resets the interval. + }, [count]); // 🚩 ... 하지만 'count'를 의존성으로 명시하면 항상 인터벌이 초기화됩니다. // ... } ``` @@ -1448,10 +1448,10 @@ export default function Counter() { useEffect(() => { const intervalId = setInterval(() => { - setCount(c => c + 1); // ✅ Pass a state updater + setCount(c => c + 1); // ✅ State 업데이터를 전달 }, 1000); return () => clearInterval(intervalId); - }, []); // ✅ Now count is not a dependency + }, []); // ✅ 이제 count는 의존성이 아닙니다 return

{count}

; } @@ -1486,16 +1486,16 @@ const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId }) { const [message, setMessage] = useState(''); - const options = { // 🚩 This object is created from scratch on every re-render + const options = { // 🚩 이 객체는 재 렌더링 될 때마다 새로 생성됩니다 serverUrl: serverUrl, roomId: roomId }; useEffect(() => { - const connection = createConnection(options); // It's used inside the Effect + const connection = createConnection(options); // 객체가 Effect 안에서 사용됩니다 connection.connect(); return () => connection.disconnect(); - }, [options]); // 🚩 As a result, these dependencies are always different on a re-render + }, [options]); // 🚩 결과적으로, 의존성이 재 렌더링 때마다 다릅니다 // ... ``` @@ -1554,7 +1554,7 @@ export default function App() { ```js src/chat.js export function createConnection({ serverUrl, roomId }) { - // A real implementation would actually connect to the server + // 실제 구현은 실제로 서버에 연결됩니다. return { connect() { console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...'); @@ -1587,7 +1587,7 @@ Effect가 렌더링 중에 생성된 객체나 함수에 의존하는 경우, function ChatRoom({ roomId }) { const [message, setMessage] = useState(''); - function createOptions() { // 🚩 This function is created from scratch on every re-render + function createOptions() { // 🚩 이 함수는 재 렌더링 될 때마다 새로 생성됩니다 return { serverUrl: serverUrl, roomId: roomId @@ -1595,11 +1595,11 @@ function ChatRoom({ roomId }) { } useEffect(() => { - const options = createOptions(); // It's used inside the Effect + const options = createOptions(); // 함수가 Effect 안에서 사용됩니다 const connection = createConnection(); connection.connect(); return () => connection.disconnect(); - }, [createOptions]); // 🚩 As a result, these dependencies are always different on a re-render + }, [createOptions]); // 🚩 결과적으로, 의존성이 재 렌더링 때마다 다릅니다 // ... ``` @@ -1664,7 +1664,7 @@ export default function App() { ```js src/chat.js export function createConnection({ serverUrl, roomId }) { - // A real implementation would actually connect to the server + // 실제 구현은 실제로 서버에 연결됩니다. return { connect() { console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...'); @@ -1703,7 +1703,7 @@ button { margin-left: 10px; } function Page({ url, shoppingCart }) { useEffect(() => { logVisit(url, shoppingCart.length); - }, [url, shoppingCart]); // ✅ All dependencies declared + }, [url, shoppingCart]); // ✅ 모든 의존성이 선언됨 // ... } ``` @@ -1718,7 +1718,7 @@ function Page({ url, shoppingCart }) { useEffect(() => { onVisit(url); - }, [url]); // ✅ All dependencies declared + }, [url]); // ✅ 모든 의존성이 선언됨 // ... } ``` @@ -1745,9 +1745,9 @@ function MyComponent() { }, []); if (didMount) { - // ... return client-only JSX ... + // ... 클라이언트 전용 JSX 반환 ... } else { - // ... return initial JSX ... + // ... 초기 JSX 반환 ... } } ``` @@ -1777,7 +1777,7 @@ function MyComponent() { ```js {3} useEffect(() => { // ... -}); // 🚩 No dependency array: re-runs after every render! +}); // 🚩 의존성 배열이 없음. 재 렌더링 될 때마다 재실행됨! ``` 의존성 배열을 명시했음에도 Effect가 여전히 반복해서 실행된다면 의존성이 렌더링마다 다르기 때문입니다. @@ -1795,9 +1795,9 @@ useEffect(() => { 그다음 콘솔에서 기록된 다른 렌더링 배열을 마우스 오른쪽 버튼으로 클릭하고 두 배열 모두에 대해 전역 변수로 저장을 선택할 수 있습니다. 첫 번째 요소가 `temp1`이고 두 번째 요소가 `temp2`라고 가정하면 브라우저 콘솔을 사용하여 양쪽 배열의 각 의존성이 동일한지 확인할 수 있습니다. ```js -Object.is(temp1[0], temp2[0]); // Is the first dependency the same between the arrays? -Object.is(temp1[1], temp2[1]); // Is the second dependency the same between the arrays? -Object.is(temp1[2], temp2[2]); // ... and so on for every dependency ... +Object.is(temp1[0], temp2[0]); // 첫 번째 의존성이 배열 간에 동일한가요? +Object.is(temp1[1], temp2[1]); // 두 번째 의존성이 배열 간에 동일한가요? +Object.is(temp1[2], temp2[2]); // ... 나머지 모든 의존성도 확인합니다 ... ``` 렌더링마다 다른 의존성을 찾아냈다면 일반적으로 다음 중 하나의 방법으로 수정할 수 있습니다. @@ -1836,7 +1836,7 @@ Effect가 무한 반복되려면 다음 두 가지 조건이 충족되어야 합 ```js {2-5} useEffect(() => { - // 🔴 Avoid: Cleanup logic without corresponding setup logic + // 🔴 피하세요: 상응하는 설정 로직이 없는 정리 로직 return () => { doSomething(); }; From 1675d2c79628d35ed0fc6c6fc2a5860645a0780d Mon Sep 17 00:00:00 2001 From: "Joonwoo Jang (Percy)" Date: Mon, 11 Mar 2024 21:07:02 +0800 Subject: [PATCH 0012/1164] translate and fix: translated comments for your-first-component, removed dangling english contents (#874) Co-authored-by: Haegul Pyun --- src/content/learn/your-first-component.md | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/content/learn/your-first-component.md b/src/content/learn/your-first-component.md index a0440bbb2..4d8535220 100644 --- a/src/content/learn/your-first-component.md +++ b/src/content/learn/your-first-component.md @@ -172,8 +172,6 @@ img { margin: 0 10px 10px 0; height: 90px; } ### 컴포넌트 중첩 및 구성 {/*nesting-and-organizing-components*/} -Components are regular JavaScript functions, so you can keep multiple components in the same file. This is convenient when components are relatively small or tightly related to each other. If this file gets crowded, you can always move `Profile` to a separate file. You will learn how to do this shortly on the [page about imports.](/learn/importing-and-exporting-components) - 컴포넌트는 일반 JavaScript함수이므로 같은 파일에 여러 컴포넌트를 포함할 수 있습니다. 컴포넌트가 상대적으로 작거나 서로 밀접하게 관련되어 있을 때 편리합니다. 이 파일이 복잡해지면 언제든지 `Profile`을 별도의 파일로 옮길 수 있습니다. 이 방법은 바로 다음 챕터인 [컴포넌트의 importing과 exporting](/learn/importing-and-exporting-components) 페이지에서 확인할 수 있습니다. `Profile` 컴포넌트는 `Gallery`안에서 렌더링되기 때문에(심지어 여러번 렌더링됩니다!), `Gallery`는 각 `Profile`을 "자식"으로 렌더링하는 **부모 컴포넌트**라고 말할 수 있습니다. 컴포넌트를 한 번 정의한 다음 원하는 곳에서 원하는 만큼 여러 번 사용할 수 있다는 점이 바로 React의 마법입니다. @@ -184,7 +182,7 @@ Components are regular JavaScript functions, so you can keep multiple components ```js {2-5} export default function Gallery() { - // 🔴 Never define a component inside another component! + // 🔴 절대 컴포넌트 안에 다른 컴포넌트를 정의하면 안 됩니다! function Profile() { // ... } @@ -192,8 +190,6 @@ export default function Gallery() { } ``` -The snippet above is [very slow and causes bugs.](/learn/preserving-and-resetting-state#different-components-at-the-same-position-reset-state) Instead, define every component at the top level: - 위 스니펫은 [매우 느리고 버그를 촉발합니다.](/learn/preserving-and-resetting-state#different-components-at-the-same-position-reset-state) 대신 최상위 레벨에서 컴포넌트를 정의하세요. ```js {5-8} @@ -201,7 +197,7 @@ export default function Gallery() { // ... } -// ✅ Declare components at the top level +// ✅ 최상위 레벨에서 컴포넌트를 선언합니다 function Profile() { // ... } @@ -221,8 +217,6 @@ React 애플리케이션은 "root"컴포넌트에서 시작됩니다. 보통 새 [React 기반 프레임워크들](/learn/start-a-new-react-project)은 이를 한 단계 더 발전시킵니다. 빈 HTML파일을 사용하고 React가 JavaScript로 페이지 관리를 "다룰 수 있게" 하도록 하는 대신, React 컴포넌트에서 HTML을 자동으로 생성하기도합니다. 이를 통해 JavaScript 코드가 로드되기 전에 앱에서 일부 컨텐츠를 표시할 수 있습니다. -Still, many websites only use React to [add interactivity to existing HTML pages.](/learn/add-react-to-an-existing-project#using-react-for-a-part-of-your-existing-page) They have many root components instead of a single one for the entire page. You can use as much—or as little—React as you need. - 그렇지만 여전히 많은 웹사이트들은 React를 [약간의 상호작용을 추가하는 용도로만](/learn/add-react-to-an-existing-project#using-react-for-a-part-of-your-existing-page) 사용합니다. 이러한 웹사이트에는 전체 페이지에 하나의 root 컴포넌트가 아닌 여러 개의 root 컴포넌트가 있습니다. 필요한 만큼 React를 많이 또는 적게 사용할 수 있습니다. @@ -442,7 +436,7 @@ img { margin: 0 10px 10px 0; } ```js -// Write your component below! +// 아래에 컴포넌트를 작성해 보세요! ``` From aa31fe548672cc8f68dbd57452bfd486096b380b Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Mon, 11 Mar 2024 15:08:53 -0400 Subject: [PATCH 0013/1164] Add details about shallow renderer warning (#6689) --- src/content/warnings/react-test-renderer.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/content/warnings/react-test-renderer.md b/src/content/warnings/react-test-renderer.md index 8dc5be74e..7926922d1 100644 --- a/src/content/warnings/react-test-renderer.md +++ b/src/content/warnings/react-test-renderer.md @@ -1,7 +1,14 @@ --- -title: react-test-renderer Deprecation Warning +title: react-test-renderer Deprecation Warnings --- +## ReactTestRenderer.create() warning {/*reacttestrenderercreate-warning*/} + react-test-renderer is deprecated. A warning will fire whenever calling ReactTestRenderer.create() or ReactShallowRender.render(). The react-test-renderer package will remain available on NPM but will not be maintained and may break with new React features or changes to React's internals. The React Team recommends migrating your tests to [@testing-library/react](https://testing-library.com/docs/react-testing-library/intro/) or [@testing-library/react-native](https://callstack.github.io/react-native-testing-library/docs/getting-started) for a modern and well supported testing experience. + + +## new ShallowRenderer() warning {/*new-shallowrenderer-warning*/} + +The react-test-renderer package no longer exports a shallow renderer at `react-test-renderer/shallow`. This was simply a repackaging of a previously extracted separate package: `react-shallow-renderer`. Therefore you can continue using the shallow renderer in the same way by installing it directly. See [Github](https://github.com/enzymejs/react-shallow-renderer) / [NPM](https://www.npmjs.com/package/react-shallow-renderer). \ No newline at end of file From dc797afd3bce6f2034e55dd0213e1d3abd58e102 Mon Sep 17 00:00:00 2001 From: haena-j Date: Thu, 14 Mar 2024 22:11:03 +0900 Subject: [PATCH 0014/1164] =?UTF-8?q?Fix:=20=EC=9E=85=EB=8B=88=EB=8B=A4?= =?UTF-8?q?=EC=9D=80.=20->=20=EC=9E=85=EB=8B=88=EB=8B=A4.=20(#879)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/content/reference/react/useMemo.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index 645437ca8..11092d2bd 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -79,7 +79,7 @@ function TodoList({ todos, tab, theme }) { `useMemo`에 두 가지를 전달해야 합니다. -1. `() =>`와 같이 인수를 받지 않고 계산하려는 값을 반환하는 계산 함수 입니다은. +1. `() =>`와 같이 인수를 받지 않고 계산하려는 값을 반환하는 계산 함수 입니다. 2. 계산 내부에서 사용되는 컴포넌트 내의 모든 값을 포함하는 종속성 목록 입니다. 초기 렌더링에서 `useMemo`에서 얻을 수 있는 계산 함수를 호출한 결과값 입니다. From 1a839ff74e40f40a1a8ea6ae1d4837b68696550c Mon Sep 17 00:00:00 2001 From: lauren Date: Thu, 14 Mar 2024 10:44:40 -0400 Subject: [PATCH 0015/1164] Remove links to localhost (#6696) It seems like these localhost references were being stripped out anyway, so this isn't a bugfix but just a small cleanup. --- src/content/reference/react-dom/components/link.md | 8 ++++---- src/content/reference/react-dom/components/style.md | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/content/reference/react-dom/components/link.md b/src/content/reference/react-dom/components/link.md index fcbb9fab0..c3331d94c 100644 --- a/src/content/reference/react-dom/components/link.md +++ b/src/content/reference/react-dom/components/link.md @@ -79,7 +79,7 @@ Props that are **not recommended** for use with React: #### Special rendering behavior {/*special-rendering-behavior*/} -React will always place the DOM element corresponding to the `` component within the document’s ``, regardless of where in the React tree it is rendered. The `` is the only valid place for `` to exist within the DOM, yet it’s convenient and keeps things composable if a component representing a specific page can render `` components itself. +React will always place the DOM element corresponding to the `` component within the document’s ``, regardless of where in the React tree it is rendered. The `` is the only valid place for `` to exist within the DOM, yet it’s convenient and keeps things composable if a component representing a specific page can render `` components itself. There are a few exceptions to this: @@ -91,7 +91,7 @@ There are a few exceptions to this: In addition, if the `` is to a stylesheet (namely, it has `rel="stylesheet"` in its props), React treats it specially in the following ways: -* The component that renders `` will [suspend](http://localhost:3000/reference/react/Suspense) while the stylesheet is loading. +* The component that renders `` will [suspend](/reference/react/Suspense) while the stylesheet is loading. * If multiple components render links to the same stylesheet, React will de-duplicate them and only put a single link into the DOM. Two links are considered the same if they have the same `href` prop. There are two exception to this special behavior: @@ -133,7 +133,7 @@ export default function BlogPage() { ### Linking to a stylesheet {/*linking-to-a-stylesheet*/} -If a component depends on a certain stylesheet in order to be displayed correctly, you can render a link to that stylesheet within the component. Your component will [suspend](http://localhost:3000/reference/react/Suspense) while the stylesheet is loading. You must supply the `precedence` prop, which tells React where to place this stylesheet relative to others — stylesheets with higher precedence can override those with lower precedence. +If a component depends on a certain stylesheet in order to be displayed correctly, you can render a link to that stylesheet within the component. Your component will [suspend](/reference/react/Suspense) while the stylesheet is loading. You must supply the `precedence` prop, which tells React where to place this stylesheet relative to others — stylesheets with higher precedence can override those with lower precedence. When you want to use a stylesheet, it can be beneficial to call the [preinit](/reference/react-dom/preinit) function. Calling this function may allow the browser to start fetching the stylesheet earlier than if you just render a `` component, for example by sending an [HTTP Early Hints response](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/103). @@ -217,7 +217,7 @@ function Component() { ### Annotating specific items within the document with links {/*annotating-specific-items-within-the-document-with-links*/} -You can use the `` component with the `itemProp` prop to annotate specific items within the document with links to related resources. In this case, React will *not* place these annotations within the document `` but will place them like any other React component. +You can use the `` component with the `itemProp` prop to annotate specific items within the document with links to related resources. In this case, React will *not* place these annotations within the document `` but will place them like any other React component. ```js
diff --git a/src/content/reference/react-dom/components/style.md b/src/content/reference/react-dom/components/style.md index 238a26d8c..2c5d7b97b 100644 --- a/src/content/reference/react-dom/components/style.md +++ b/src/content/reference/react-dom/components/style.md @@ -52,7 +52,7 @@ Props that are **not recommended** for use with React: #### Special rendering behavior {/*special-rendering-behavior*/} -React can move ``), require careful positioning in the DOM due to style precedence rules. Building a stylesheet capability that allows for composability within components is hard, so users often end up either loading all of their styles far from the components that may depend on them, or they use a style library which encapsulates this complexity. + +In React 19, we're addressing this complexity and providing even deeper integration into Concurrent Rendering on the Client and Streaming Rendering on the Server with built in support for stylesheets. If you tell React the `precedence` of your stylesheet it will manage the insertion order of the stylesheet in the DOM and ensure that the stylesheet (if external) is loaded before revealing content that depends on those style rules. + +```js +function ComponentOne() { + return ( + + + +
+ High from ComponentOne +
+
+ ) +} + +function ComponentTwo() { + return ( +
+ Hi from ComponentTwo + <-- will be inserted between foo & bar +
+ ) +} +``` + +During Server Side Rendering React will include the stylesheet in the ``, which ensures that the browser will not paint until it has loaded. If the stylesheet is discovered late after we've already started streaming, React will ensure that the stylesheet is inserted into the `` on the client before revealing the content of a Suspense boundary that depends on that stylesheet. + +During Client Side Rendering React will wait for newly rendered stylesheets to load before committing the render. + +If you render this component from multiple places within your application React will only include the stylesheet once in the document: +```js +function App() { + return <> + + ... + // won't lead to a duplicate stylesheet link in the DOM + +} +``` + +For users accustomed to loading stylesheets manually this is an opportunity to locate those stylesheets alongside the components that depend on them allowing for better local reasoning and an easier time ensuring you only load the stylesheets that you actually depend on. + +style libraries and style integrations with bundlers can also adopt this new capability so even if you don't directly render your own stylesheets, you can still benefit as your tools are upgraded to use this feature. + +For more details, read the docs for [``](/reference/react-dom/components/link) and [` @@ -23,53 +23,54 @@ The [built-in browser ` ``` -[See more examples below.](#usage) +[아래에 더 많은 예시를 확인하세요.](#usage) #### Props {/*props*/} -` @@ -37,7 +37,7 @@ React의 `` 확장은 현재 React의 카나리(Canary) 버전 및 실험 #### Props {/*props*/} -`<style>`은 [모든 컴포넌트 속성](/reference/react-dom/components/common#props)을 지원합니다. +`<style>`은 [모든 컴포넌트 속성](/reference/react-dom/components/common#props)을 지원합니다. * `children`: 문자열 타입. 필수 항목. 스타일시트의 내용. * `precedence`: 문자열 타입. 문서의 `<head>` 내 다른 요소들에 비해 `<style>` DOM 노드의 순위를 지정하여, 어떤 스타일시트가 다른 스타일시트를 덮어쓸 수 있는지를 결정합니다. React는 먼저 발견한 우선순위를 "낮게", 나중에 발견한 우선순위를 "높게" 추론합니다. 많은 스타일 시스템은 스타일 규칙이 원자적이기 때문에 단일 우선순위 값을 사용해도 잘 작동할 수 있습니다. 동일한 우선순위를 가지는 스타일시트는 `<link>` 태그인지 인라인 `<style>` 태그인지 [`preinit`](/reference/react-dom/preinit) 함수로 로드된 것인지와 무관하게 함께 적용됩니다. diff --git a/src/content/reference/react-dom/components/textarea.md b/src/content/reference/react-dom/components/textarea.md index 8bdb8360c..f4d2365cb 100644 --- a/src/content/reference/react-dom/components/textarea.md +++ b/src/content/reference/react-dom/components/textarea.md @@ -51,9 +51,9 @@ title: "<textarea>" * [`disabled`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea#disabled): 불리언 타입. `true`일 경우 input은 상호작용이 불가능해지며 흐릿하게 보입니다. * [`form`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea#form): 문자열 타입. 텍스트 영역 input이 속하는 `<form>`의 `id`를 지정합니다. 생략 시 가장 가까운 부모 폼으로 설정됩니다. * [`maxLength`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea#maxlength): 숫자 타입. 텍스트의 최대 길이를 지정합니다. -* [`minLength`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea#minlength): 숫자 타입. 텍스트의 최소 길이를 지정합니다. +* [`minLength`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea#minlength): 숫자 타입. 텍스트의 최소 길이를 지정합니다. * [`name`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#name): 문자열 타입. [폼과 제출](#reading-the-textarea-value-when-submitting-a-form)되는 input의 이름을 지정합니다. -* `onChange`: [`이벤트` 핸들러](/reference/react-dom/components/common#event-handler) 함수. [제어되는 텍스트 영역](#controlling-a-text-area-with-a-state-variable) 필수 요소로 가령 사용자가 키보드를 누를 때마다 실행되는 방식으로 input 값을 변경하는 즉시 실행되며 브라우저 [`input` 이벤트](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/input_event)처럼 동작합니다. +* `onChange`: [`이벤트` 핸들러](/reference/react-dom/components/common#event-handler) 함수. [제어되는 텍스트 영역](#controlling-a-text-area-with-a-state-variable) 필수 요소로 가령 사용자가 키보드를 누를 때마다 실행되는 방식으로 input 값을 변경하는 즉시 실행되며 브라우저 [`input` 이벤트](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/input_event)처럼 동작합니다. * `onChangeCapture`: [캡처 단계](/learn/responding-to-events#capture-phase-events)에서 실행되는 `onChange` * [`onInput`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/input_event): [`이벤트` 핸들러](/reference/react-dom/components/common#event-handler) 함수. 사용자가 값을 변경하는 즉시 실행됩니다. 지금까지의 용법에 비춰봤을 때 React에서는 유사하게 동작하는 `onChange`를 사용하는 것이 관습적입니다. * `onInputCapture`: [캡처 단계](/learn/responding-to-events#capture-phase-events)에서 실행되는 `onInput` diff --git a/src/content/reference/react-dom/createPortal.md b/src/content/reference/react-dom/createPortal.md index 43aa9035c..0395fd492 100644 --- a/src/content/reference/react-dom/createPortal.md +++ b/src/content/reference/react-dom/createPortal.md @@ -46,15 +46,15 @@ Portal은 DOM 노드의 물리적 배치만 변경합니다. #### 매개변수 {/*parameters*/} -* `children` : JSX의 일부(예를 들어 `<div />` 또는 `<SomeComponent />`), [Fragment](/reference/react/Fragment)(`<>...</>`), 문자열이나 숫자 또는 이들의 배열과 같이 React로 렌더링할 수 있는 모든 것입니다. +* `children` : JSX의 일부(예를 들어 `<div />` 또는 `<SomeComponent />`), [Fragment](/reference/react/Fragment)(`<>...</>`), 문자열이나 숫자 또는 이들의 배열과 같이 React로 렌더링할 수 있는 모든 것입니다. * `domNode` : `document.getElementById()`가 반환하는 것과 같은 일부 DOM 노드. 노드가 미리 존재해야 합니다. 업데이트 중에 다른 DOM 노드를 전달하면 portal 콘텐츠가 다시 생성됩니다. -* **optional** `key`: Portal의 [key](/learn/rendering-lists/#keeping-list-items-in-order-with-key)로 사용할 고유한 문자열 또는 숫자입니다. +* **optional** `key`: Portal의 [key](/learn/rendering-lists/#keeping-list-items-in-order-with-key)로 사용할 고유한 문자열 또는 숫자입니다. #### 반환값 {/*returns*/} -`createPortal`은 JSX에 포함하거나 React 컴포넌트에서 반환할 수 있는 React 노드를 반환합니다. React가 렌더링 출력에서 이를 발견하면, 제공된 `children`을 제공된 `domNode` 안에 배치합니다. +`createPortal`은 JSX에 포함하거나 React 컴포넌트에서 반환할 수 있는 React 노드를 반환합니다. React가 렌더링 출력에서 이를 발견하면, 제공된 `children`을 제공된 `domNode` 안에 배치합니다. #### 주의 사항 {/*caveats*/} diff --git a/src/content/reference/react-dom/flushSync.md b/src/content/reference/react-dom/flushSync.md index 703c6f4aa..8cf724d44 100644 --- a/src/content/reference/react-dom/flushSync.md +++ b/src/content/reference/react-dom/flushSync.md @@ -61,7 +61,7 @@ flushSync(() => { ### 서드 파티 통합을 위한 업데이트 flushing {/*flushing-updates-for-third-party-integrations*/} -브라우저 API 또는 UI 라이브러리와 같은 서드 파티 코드를 통합할 때 React가 업데이트를 처리하도록 강제할 필요가 있을 수 있습니다. `flushSync`를 사용해서 React가 콜백 내부의 모든 <CodeStep step={1}>state updates</CodeStep>를 동기적으로 처리하도록 할 수 있습니다. +브라우저 API 또는 UI 라이브러리와 같은 서드 파티 코드를 통합할 때 React가 업데이트를 처리하도록 강제할 필요가 있을 수 있습니다. `flushSync`를 사용해서 React가 콜백 내부의 모든 <CodeStep step={1}>state updates</CodeStep>를 동기적으로 처리하도록 할 수 있습니다. ```js [[1, 2, "setSomething(123)"]] flushSync(() => { diff --git a/src/content/reference/react-dom/hooks/useFormStatus.md b/src/content/reference/react-dom/hooks/useFormStatus.md index d067fc2a3..7d4bffbfb 100644 --- a/src/content/reference/react-dom/hooks/useFormStatus.md +++ b/src/content/reference/react-dom/hooks/useFormStatus.md @@ -129,7 +129,7 @@ export async function submitForm(query) { "devDependencies": {} } ``` -</Sandpack> +</Sandpack> <Pitfall> @@ -151,7 +151,7 @@ function Form() { ```js function Submit() { // ✅ `pending`은 Submit 컴포넌트를 감싸는 폼에서 파생됩니다 - const { pending } = useFormStatus(); + const { pending } = useFormStatus(); return <button disabled={pending}>...</button>; } @@ -245,7 +245,7 @@ button { "devDependencies": {} } ``` -</Sandpack> +</Sandpack> --- diff --git a/src/content/reference/react-dom/preinit.md b/src/content/reference/react-dom/preinit.md index 49791b104..ffe254f47 100644 --- a/src/content/reference/react-dom/preinit.md +++ b/src/content/reference/react-dom/preinit.md @@ -54,10 +54,10 @@ The `preinit` function provides the browser with a hint that it should start dow * `href`: a string. The URL of the resource you want to download and execute. * `options`: an object. It contains the following properties: * `as`: a required string. The type of resource. Its possible values are `script` and `style`. - * `precedence`: a string. Required with stylesheets. Says where to insert the stylesheet relative to others. Stylesheets with higher precedence can override those with lower precedence. The possible values are `reset`, `low`, `medium`, `high`. + * `precedence`: a string. Required with stylesheets. Says where to insert the stylesheet relative to others. Stylesheets with higher precedence can override those with lower precedence. The possible values are `reset`, `low`, `medium`, `high`. * `crossOrigin`: a string. The [CORS policy](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin) to use. Its possible values are `anonymous` and `use-credentials`. It is required when `as` is set to `"fetch"`. * `integrity`: a string. A cryptographic hash of the resource, to [verify its authenticity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity). - * `nonce`: a string. A cryptographic [nonce to allow the resource](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce) when using a strict Content Security Policy. + * `nonce`: a string. A cryptographic [nonce to allow the resource](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce) when using a strict Content Security Policy. * `fetchPriority`: a string. Suggests a relative priority for fetching the resource. The possible values are `auto` (the default), `high`, and `low`. #### Returns {/*returns*/} diff --git a/src/content/reference/react-dom/preinitModule.md b/src/content/reference/react-dom/preinitModule.md index 5f9be6d50..6039970c9 100644 --- a/src/content/reference/react-dom/preinitModule.md +++ b/src/content/reference/react-dom/preinitModule.md @@ -56,7 +56,7 @@ The `preinitModule` function provides the browser with a hint that it should sta * `as`: a required string. It must be `'script'`. * `crossOrigin`: a string. The [CORS policy](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin) to use. Its possible values are `anonymous` and `use-credentials`. * `integrity`: a string. A cryptographic hash of the module, to [verify its authenticity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity). - * `nonce`: a string. A cryptographic [nonce to allow the module](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce) when using a strict Content Security Policy. + * `nonce`: a string. A cryptographic [nonce to allow the module](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce) when using a strict Content Security Policy. #### Returns {/*returns*/} diff --git a/src/content/reference/react-dom/preloadModule.md b/src/content/reference/react-dom/preloadModule.md index 44cb27a37..108701c26 100644 --- a/src/content/reference/react-dom/preloadModule.md +++ b/src/content/reference/react-dom/preloadModule.md @@ -67,7 +67,7 @@ function AppRoot() { #### 주의 사항 {/*caveats*/} * 동일한 `href`로 `preloadModule`을 여러 번 호출하는 것은 한 번 호출하는 것과 동일한 효과가 있습니다. -* 브라우저에서는 컴포넌트를 렌더링하는 중이거나, Effect, 이벤트 핸들러 등 어떤 상황에서도 `preloadModule`을 호출할 수 있습니다. +* 브라우저에서는 컴포넌트를 렌더링하는 중이거나, Effect, 이벤트 핸들러 등 어떤 상황에서도 `preloadModule`을 호출할 수 있습니다. * 서버 측 렌더링이나 서버 컴포넌트를 렌더링할 때, `preloadModule`은 컴포넌트를 렌더링하는 동안 호출하거나, 컴포넌트 렌더링에서 시작된 비동기 컨텍스트 내에서 호출할 때만 효과가 있습니다. 그 외의 호출은 무시됩니다. --- diff --git a/src/content/reference/react-dom/server/renderToPipeableStream.md b/src/content/reference/react-dom/server/renderToPipeableStream.md index 2f3e95334..0f3a78da4 100644 --- a/src/content/reference/react-dom/server/renderToPipeableStream.md +++ b/src/content/reference/react-dom/server/renderToPipeableStream.md @@ -401,7 +401,7 @@ const { pipe } = renderToPipeableStream(<App />, { onShellError(error) { response.statusCode = 500; response.setHeader('content-type', 'text/html'); - response.send('<h1>Something went wrong</h1>'); + response.send('<h1>Something went wrong</h1>'); }, onError(error) { console.error(error); @@ -433,8 +433,8 @@ function ProfilePage() { `Posts` 컴포넌트 또는 그 내부 어딘가에서 오류가 발생하면 React는 [이를 복구하려고 시도합니다.](/reference/react/Suspense#providing-a-fallback-for-server-errors-and-client-only-content) -1. 가장 가까운 `<Suspense>` 경계(`PostsGlimmer`)에 대한 로딩 폴백을 HTML로 방출합니다. -2. 더 이상 서버에서 `Posts` 콘텐츠를 렌더링하는 것을 "포기"합니다. +1. 가장 가까운 `<Suspense>` 경계(`PostsGlimmer`)에 대한 로딩 폴백을 HTML로 방출합니다. +2. 더 이상 서버에서 `Posts` 콘텐츠를 렌더링하는 것을 "포기"합니다. 3. 자바스크립트 코드가 클라이언트에서 로드되면 React는 클라이언트에서 `Posts` 렌더링을 *재시도*합니다. 클라이언트에서 `Posts` 렌더링을 *다시 시도해도* 실패하면 React는 클라이언트에서 에러를 던집니다. 렌더링 중에 발생하는 모든 에러와 마찬가지로, [가장 가까운 부모 에러 경계](/reference/react/Component#static-getderivedstatefromerror)에 따라 사용자에게 에러를 표시하는 방법이 결정됩니다. 실제로는 오류를 복구할 수 없다는 것이 확실해질 때까지 사용자에게 로딩 표시기가 표시된다는 의미입니다. @@ -460,7 +460,7 @@ const { pipe } = renderToPipeableStream(<App />, { onShellError(error) { response.statusCode = 500; response.setHeader('content-type', 'text/html'); - response.send('<h1>Something went wrong</h1>'); + response.send('<h1>Something went wrong</h1>'); }, onError(error) { console.error(error); @@ -486,7 +486,7 @@ const { pipe } = renderToPipeableStream(<App />, { onShellError(error) { response.statusCode = 500; response.setHeader('content-type', 'text/html'); - response.send('<h1>Something went wrong</h1>'); + response.send('<h1>Something went wrong</h1>'); }, onError(error) { didError = true; @@ -531,7 +531,7 @@ const { pipe } = renderToPipeableStream(<App />, { onShellError(error) { response.statusCode = getStatusCode(); response.setHeader('content-type', 'text/html'); - response.send('<h1>Something went wrong</h1>'); + response.send('<h1>Something went wrong</h1>'); }, onError(error) { didError = true; @@ -570,13 +570,13 @@ const { pipe } = renderToPipeableStream(<App />, { onShellError(error) { response.statusCode = 500; response.setHeader('content-type', 'text/html'); - response.send('<h1>Something went wrong</h1>'); + response.send('<h1>Something went wrong</h1>'); }, onAllReady() { if (isCrawler) { response.statusCode = didError ? 500 : 200; response.setHeader('content-type', 'text/html'); - pipe(response); + pipe(response); } }, onError(error) { diff --git a/src/content/reference/react-dom/server/renderToStaticMarkup.md b/src/content/reference/react-dom/server/renderToStaticMarkup.md index d44986bb7..af49f806a 100644 --- a/src/content/reference/react-dom/server/renderToStaticMarkup.md +++ b/src/content/reference/react-dom/server/renderToStaticMarkup.md @@ -37,7 +37,7 @@ const html = renderToStaticMarkup(<Page />); * `reactNode`: HTML로 렌더링할 React 노드입니다. 예를 들어, `<Page />`와 같은 JSX 노드입니다. * **optional** `options`: 서버 렌더링을 위한 객체입니다. * **optional** `identifierPrefix`: [`useId`.](/reference/react/useId)에 의해 생성된 ID에 대해 React가 사용하는 문자열 접두사입니다. 같은 페이지에서 여러 루트를 사용할 때 충돌을 피하기 위해 유용합니다. - + #### 반환값 {/*returns*/} HTML 문자열을 반환합니다. diff --git a/src/content/reference/react/Children.md b/src/content/reference/react/Children.md index 9ce29cb57..d1955b689 100644 --- a/src/content/reference/react/Children.md +++ b/src/content/reference/react/Children.md @@ -863,7 +863,7 @@ export default function App() { return ( <Row isHighlighted={index % 2 === 0}> <p>This is the {id} item.</p> - </Row> + </Row> ); }} /> diff --git a/src/content/reference/react/Component.md b/src/content/reference/react/Component.md index 9c8047539..367380d9f 100644 --- a/src/content/reference/react/Component.md +++ b/src/content/reference/react/Component.md @@ -129,7 +129,7 @@ class Counter extends Component { handleAgeChange = () => { this.setState({ - age: this.state.age + 1 + age: this.state.age + 1 }); }; @@ -1174,7 +1174,7 @@ export default class Counter extends Component { handleAgeChange = () => { this.setState({ - age: this.state.age + 1 + age: this.state.age + 1 }); }; @@ -1199,7 +1199,7 @@ export default class Counter extends Component { button { display: block; margin-top: 10px; } ``` -</Sandpack> +</Sandpack> <Pitfall> @@ -1283,7 +1283,7 @@ export default class ChatRoom extends Component { this.state.serverUrl, this.props.roomId ); - this.connection.connect(); + this.connection.connect(); } destroyConnection() { @@ -1496,7 +1496,7 @@ export default class Counter extends Component { handleAgeChange = (e) => { this.setState({ - age: this.state.age + 1 + age: this.state.age + 1 }); }; @@ -1663,7 +1663,7 @@ export default class ChatRoom extends Component { this.state.serverUrl, this.props.roomId ); - this.connection.connect(); + this.connection.connect(); } destroyConnection() { @@ -1852,7 +1852,7 @@ class Panel extends Component { <h1>{this.props.title}</h1> {this.props.children} </section> - ); + ); } } diff --git a/src/content/reference/react/Profiler.md b/src/content/reference/react/Profiler.md index cf6100acf..03c3e3174 100644 --- a/src/content/reference/react/Profiler.md +++ b/src/content/reference/react/Profiler.md @@ -125,7 +125,7 @@ React 트리를 `<Profiler>` 컴포넌트로 감싸서 렌더링 성능을 측 </App> ``` -`<Profiler>`는 가벼운 컴포넌트이지만 사용할 때마다 애플리케이션에 약간의 CPU 및 메모리 오버헤드가 추가되기 때문에 필요할 때만 사용해야 합니다. +`<Profiler>`는 가벼운 컴포넌트이지만 사용할 때마다 애플리케이션에 약간의 CPU 및 메모리 오버헤드가 추가되기 때문에 필요할 때만 사용해야 합니다. --- diff --git a/src/content/reference/react/PureComponent.md b/src/content/reference/react/PureComponent.md index 39b1c6806..7a58eddd6 100644 --- a/src/content/reference/react/PureComponent.md +++ b/src/content/reference/react/PureComponent.md @@ -204,6 +204,6 @@ label { <Note> -`PureComponent`와 달리 [`memo`](/reference/react/memo)는 새 state와 이전 state를 비교하지 않습니다. 함수 컴포넌트에서 동일한 state로 [`set` 함수](/reference/react/useState#setstate)를 호출하면 [기본적으로 `memo` 없이도 다시 렌더링 되지 않습니다.](/reference/react/memo#updating-a-memoized-component-using-state) +`PureComponent`와 달리 [`memo`](/reference/react/memo)는 새 state와 이전 state를 비교하지 않습니다. 함수 컴포넌트에서 동일한 state로 [`set` 함수](/reference/react/useState#setstate)를 호출하면 [기본적으로 `memo` 없이도 다시 렌더링 되지 않습니다.](/reference/react/memo#updating-a-memoized-component-using-state) </Note> diff --git a/src/content/reference/react/Suspense.md b/src/content/reference/react/Suspense.md index 9c0fa1a4c..4ca6cebbd 100644 --- a/src/content/reference/react/Suspense.md +++ b/src/content/reference/react/Suspense.md @@ -24,7 +24,7 @@ title: <Suspense> ### `<Suspense>` {/*suspense*/} #### Props {/*props*/} -* `children`: 궁극적으로 렌더링하려는 실제 UI입니다. `children`의 렌더링이 지연되면, Suspense는 `fallback`을 대신 렌더링합니다. +* `children`: 궁극적으로 렌더링하려는 실제 UI입니다. `children`의 렌더링이 지연되면, Suspense는 `fallback`을 대신 렌더링합니다. * `fallback`: 실제 UI가 로드되기 전까지 대신 렌더링 되는 대체 UI입니다. 올바른 React node 형식은 무엇이든 대체 UI로 활용할 수 있지만, 실제로는 보통 로딩 스피너나 스켈레톤처럼 간단한 placeholder를 활용합니다. Suspense는 `children`의 렌더링이 지연되면 자동으로 `fallback`으로 전환하고, 데이터가 준비되면 `children`으로 다시 전환합니다. 만약 `fallback`의 렌더링이 지연되면, 가장 가까운 부모 Suspense가 활성화됩니다. #### 주의 사항 {/*caveats*/} @@ -155,7 +155,7 @@ function use(promise) { reason => { promise.status = 'rejected'; promise.reason = reason; - }, + }, ); throw promise; } @@ -397,7 +397,7 @@ function use(promise) { reason => { promise.status = 'rejected'; promise.reason = reason; - }, + }, ); throw promise; } @@ -445,7 +445,7 @@ function use(promise) { reason => { promise.status = 'rejected'; promise.reason = reason; - }, + }, ); throw promise; } @@ -482,9 +482,9 @@ async function getBio() { setTimeout(resolve, 1500); }); - return `The Beatles were an English rock band, - formed in Liverpool in 1960, that comprised - John Lennon, Paul McCartney, George Harrison + return `The Beatles were an English rock band, + formed in Liverpool in 1960, that comprised + John Lennon, Paul McCartney, George Harrison and Ringo Starr.`; } @@ -734,7 +734,7 @@ function use(promise) { reason => { promise.status = 'rejected'; promise.reason = reason; - }, + }, ); throw promise; } @@ -782,7 +782,7 @@ function use(promise) { reason => { promise.status = 'rejected'; promise.reason = reason; - }, + }, ); throw promise; } @@ -819,9 +819,9 @@ async function getBio() { setTimeout(resolve, 500); }); - return `The Beatles were an English rock band, - formed in Liverpool in 1960, that comprised - John Lennon, Paul McCartney, George Harrison + return `The Beatles were an English rock band, + formed in Liverpool in 1960, that comprised + John Lennon, Paul McCartney, George Harrison and Ringo Starr.`; } @@ -1011,7 +1011,7 @@ function use(promise) { reason => { promise.status = 'rejected'; promise.reason = reason; - }, + }, ); throw promise; } @@ -1143,7 +1143,7 @@ export default function App() { ```js {2} <div style={{ - opacity: query !== deferredQuery ? 0.5 : 1 + opacity: query !== deferredQuery ? 0.5 : 1 }}> <SearchResults query={deferredQuery} /> </div> @@ -1239,7 +1239,7 @@ function use(promise) { reason => { promise.status = 'rejected'; promise.reason = reason; - }, + }, ); throw promise; } @@ -1519,7 +1519,7 @@ function use(promise) { reason => { promise.status = 'rejected'; promise.reason = reason; - }, + }, ); throw promise; } @@ -1563,7 +1563,7 @@ function use(promise) { reason => { promise.status = 'rejected'; promise.reason = reason; - }, + }, ); throw promise; } @@ -1610,9 +1610,9 @@ async function getBio() { setTimeout(resolve, 500); }); - return `The Beatles were an English rock band, - formed in Liverpool in 1960, that comprised - John Lennon, Paul McCartney, George Harrison + return `The Beatles were an English rock band, + formed in Liverpool in 1960, that comprised + John Lennon, Paul McCartney, George Harrison and Ringo Starr.`; } @@ -1734,7 +1734,7 @@ function Router() { function navigate(url) { startTransition(() => { - setPage(url); + setPage(url); }); } // ... @@ -1906,7 +1906,7 @@ function use(promise) { reason => { promise.status = 'rejected'; promise.reason = reason; - }, + }, ); throw promise; } @@ -1950,7 +1950,7 @@ function use(promise) { reason => { promise.status = 'rejected'; promise.reason = reason; - }, + }, ); throw promise; } @@ -1997,9 +1997,9 @@ async function getBio() { setTimeout(resolve, 500); }); - return `The Beatles were an English rock band, - formed in Liverpool in 1960, that comprised - John Lennon, Paul McCartney, George Harrison + return `The Beatles were an English rock band, + formed in Liverpool in 1960, that comprised + John Lennon, Paul McCartney, George Harrison and Ringo Starr.`; } @@ -2292,7 +2292,7 @@ function use(promise) { reason => { promise.status = 'rejected'; promise.reason = reason; - }, + }, ); throw promise; } @@ -2336,7 +2336,7 @@ function use(promise) { reason => { promise.status = 'rejected'; promise.reason = reason; - }, + }, ); throw promise; } @@ -2383,9 +2383,9 @@ async function getBio() { setTimeout(resolve, 500); }); - return `The Beatles were an English rock band, - formed in Liverpool in 1960, that comprised - John Lennon, Paul McCartney, George Harrison + return `The Beatles were an English rock band, + formed in Liverpool in 1960, that comprised + John Lennon, Paul McCartney, George Harrison and Ringo Starr.`; } diff --git a/src/content/reference/react/act.md b/src/content/reference/react/act.md index c01f3cd69..019a3a761 100644 --- a/src/content/reference/react/act.md +++ b/src/content/reference/react/act.md @@ -96,12 +96,12 @@ import Counter from './Counter'; it('can render and update a counter', async () => { container = document.createElement('div'); document.body.appendChild(container); - + // ✅ Render the component inside act(). await act(() => { ReactDOMClient.createRoot(container).render(<Counter />); }); - + const button = container.querySelector('button'); const label = container.querySelector('p'); expect(label.textContent).toBe('You clicked 0 times'); @@ -125,11 +125,11 @@ import Counter from './Counter'; it.only('can render and update a counter', async () => { const container = document.createElement('div'); document.body.appendChild(container); - + await act( async () => { ReactDOMClient.createRoot(container).render(<Counter />); }); - + // ✅ Dispatch the event inside act(). await act(async () => { button.dispatchEvent(new MouseEvent('click', { bubbles: true })); diff --git a/src/content/reference/react/cache.md b/src/content/reference/react/cache.md index cf9befad9..5f6ee0b89 100644 --- a/src/content/reference/react/cache.md +++ b/src/content/reference/react/cache.md @@ -194,7 +194,7 @@ async function MinimalWeatherCard({city}) { `AnimatedWeatherCard`와 `MinimalWeatherCard`가 같은 <CodeStep step={1}>city</CodeStep>를 렌더링할 때, <CodeStep step={2}>메모화된 함수</CodeStep>로 부터 같은 데이터의 스냅샷을 받게 됩니다. -`AnimatedWeatherCard`와 `MinimalWeatherCard`가 다른 <CodeStep step={1}>city</CodeStep>를 <CodeStep step={2}>`getTemperature`</CodeStep>의 인자로 받게 된다면, `fetchTemperature`는 두 번 호출되고 호출마다 다른 데이터를 받게 됩니다. +`AnimatedWeatherCard`와 `MinimalWeatherCard`가 다른 <CodeStep step={1}>city</CodeStep>를 <CodeStep step={2}>`getTemperature`</CodeStep>의 인자로 받게 된다면, `fetchTemperature`는 두 번 호출되고 호출마다 다른 데이터를 받게 됩니다. <CodeStep step={1}>city</CodeStep>가 캐시 키처럼 동작하게 됩니다. @@ -243,7 +243,7 @@ function Page({id}) { } ``` -`Page`를 렌더링할 때, 컴포넌트는 <CodeStep step={1}>`getUser`</CodeStep>를 호출하지만, 반환된 데이터를 사용하지 않는다는 점에 유의하세요. 이 초기 <CodeStep step={1}>`getUser`</CodeStep> 호출은 페이지가 다른 계산 작업을 수행하고 자식을 렌더링하는 동안 발생하는, 비동기 데이터베이스 쿼리를 시작합니다. +`Page`를 렌더링할 때, 컴포넌트는 <CodeStep step={1}>`getUser`</CodeStep>를 호출하지만, 반환된 데이터를 사용하지 않는다는 점에 유의하세요. 이 초기 <CodeStep step={1}>`getUser`</CodeStep> 호출은 페이지가 다른 계산 작업을 수행하고 자식을 렌더링하는 동안 발생하는, 비동기 데이터베이스 쿼리를 시작합니다. `Profile`을 렌더링할 때, <CodeStep step={2}>`getUser`</CodeStep>를 다시 호출합니다. 초기 <CodeStep step={1}>`getUser`</CodeStep> 호출이 이미 사용자 데이터에 반환되고 캐싱 되었다면, `Profile`이 <CodeStep step={2}>해당 데이터를 요청하고 기다릴 때</CodeStep>, 다른 원격 프로시저 호출 없이 쉽게 캐시에서 읽어올 수 있습니다. <CodeStep step={1}> 초기 데이터 요청</CodeStep>이 완료되지 않은 경우, 이 패턴으로 데이터를 미리 로드하면 데이터를 받아올 때 생기는 지연이 줄어듭니다. @@ -264,7 +264,7 @@ const getData = cache(fetchData); async function MyComponent() { getData(); - // ... some computational work + // ... some computational work await getData(); // ... } @@ -274,7 +274,7 @@ async function MyComponent() { 첫 번째 <CodeStep step={2}>`getData`</CodeStep> 호출은 `기다리지 않지만(await)` <CodeStep step={3}>두 번째</CodeStep>는 기다립니다. [`await`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/await) 는 자바스크립트 연산자로, 기다렸다가 확정된 Promise의 결과를 반환합니다. 첫 번째 <CodeStep step={2}>`getData`</CodeStep>은 단순히 조회할 두 번째 <CodeStep step={3}>`getData`</CodeStep>에 대한 Promise를 캐싱하기 위해 `fetch`를 실행합니다. -<CodeStep step={3}>두 번째 호출</CodeStep>에서 Promise가 여전히 <em>보류 중</em>이면, 결과를 기다리는 동안 `await`가 일시 중지됩니다. 이 최적화는 데이터 불러오기를 기다리는 동안 React가 계산 작업을 계속할 수 있게 해 <CodeStep step={3}>두 번째 호출</CodeStep>에 대한 대기 시간을 줄일 수 있게 합니다. +<CodeStep step={3}>두 번째 호출</CodeStep>에서 Promise가 여전히 <em>보류 중</em>이면, 결과를 기다리는 동안 `await`가 일시 중지됩니다. 이 최적화는 데이터 불러오기를 기다리는 동안 React가 계산 작업을 계속할 수 있게 해 <CodeStep step={3}>두 번째 호출</CodeStep>에 대한 대기 시간을 줄일 수 있게 합니다. _완료된_ 결과나 에러에 대한 Promise가 이미 정해진 경우, `await`는 즉시 값을 반환합니다. 두 결과 모두 성능상의 이점이 있습니다. </DeepDive> @@ -373,7 +373,7 @@ function App() { 'use client'; function WeatherReport({record}) { - const avgTemp = calculateAvg(record); + const avgTemp = calculateAvg(record); // ... } diff --git a/src/content/reference/react/cloneElement.md b/src/content/reference/react/cloneElement.md index 767585af2..99cc1c514 100644 --- a/src/content/reference/react/cloneElement.md +++ b/src/content/reference/react/cloneElement.md @@ -103,7 +103,7 @@ export default function List({ children }) { <div className="List"> {Children.map(children, (child, index) => cloneElement(child, { - isHighlighted: index === selectedIndex + isHighlighted: index === selectedIndex }) )} ``` @@ -124,15 +124,15 @@ export default function List({ children }) { <List> <Row title="Cabbage" - isHighlighted={true} + isHighlighted={true} /> <Row title="Garlic" - isHighlighted={false} + isHighlighted={false} /> <Row title="Apple" - isHighlighted={false} + isHighlighted={false} /> </List> ``` @@ -152,7 +152,7 @@ export default function App() { {products.map(product => <Row key={product.id} - title={product.title} + title={product.title} /> )} </List> @@ -169,7 +169,7 @@ export default function List({ children }) { <div className="List"> {Children.map(children, (child, index) => cloneElement(child, { - isHighlighted: index === selectedIndex + isHighlighted: index === selectedIndex }) )} <hr /> @@ -280,15 +280,15 @@ export default function List({ items, renderItem }) { <List> <Row title="Cabbage" - isHighlighted={true} + isHighlighted={true} /> <Row title="Garlic" - isHighlighted={false} + isHighlighted={false} /> <Row title="Apple" - isHighlighted={false} + isHighlighted={false} /> </List> ``` diff --git a/src/content/reference/react/createElement.md b/src/content/reference/react/createElement.md index ddf8dc12a..9d5e2f8e2 100644 --- a/src/content/reference/react/createElement.md +++ b/src/content/reference/react/createElement.md @@ -39,7 +39,7 @@ function Greeting({ name }) { #### 매개변수 {/*parameters*/} * `type`: `type` 인수는 유효한 React 컴포넌트여야 합니다. 예를 들어 태그 이름 문자열 (예: 'div', 'span') 또는 React 컴포넌트(함수, 클래스, [`Fragment`](/reference/react/Fragment) 같은 특수 컴포넌트)가 될 수 있습니다. - + * `props`: `props` 인수는 객체 또는 `null`이어야 합니다. `null`을 전달하면 빈 객체와 동일하게 처리됩니다. React는 전달한 `props`와 일치하는 프로퍼티를 가진 엘리먼트를 생성합니다. 전달한 `props` 객체의 `ref`와 `key`는 특수하기 때문에 생성한 `element`에서 `element.props.ref` 와 `element.props.key`는 사용할 수 *없다*는 점에 유의하세요. `element.ref` 또는 `element.key`로 사용할 수 있습니다. * **선택사항** `...children`: 0개 이상의 자식 노드. React 엘리먼트, 문자열, 숫자, [포탈](/reference/react-dom/createPortal), 빈 노드(`null`, `undefined`, `true`, `false`) 그리고 React 노드 배열을 포함한 모든 React 노드가 될 수 있습니다. diff --git a/src/content/reference/react/createFactory.md b/src/content/reference/react/createFactory.md index 725611449..2d5f423af 100644 --- a/src/content/reference/react/createFactory.md +++ b/src/content/reference/react/createFactory.md @@ -34,7 +34,7 @@ import { createFactory } from 'react'; const button = createFactory('button'); ``` -이후 JSX 없이 React 엘리먼트를 만들기 위해, 해당 함수를 사용할 수 있습니다. +이후 JSX 없이 React 엘리먼트를 만들기 위해, 해당 함수를 사용할 수 있습니다. ```js export default function App() { @@ -54,7 +54,7 @@ export default function App() { #### 반환값 {/*returns*/} -팩토리 함수를 반환합니다. 이 함수는 자식 인수의 리스트에 뒤이어, 첫 번째 인수로 `props` 객체를 받으며, 주어진 `types`, `props` 그리고 `자식`을 가진 React 엘리먼트를 반환합니다. +팩토리 함수를 반환합니다. 이 함수는 자식 인수의 리스트에 뒤이어, 첫 번째 인수로 `props` 객체를 받으며, 주어진 `types`, `props` 그리고 `자식`을 가진 React 엘리먼트를 반환합니다. --- @@ -134,7 +134,7 @@ export function createFactory(type) { ### `createFactory`를 `createElement`로 대체하기 {/*replacing-createfactory-with-createelement*/} -직접 옮겨와도 무방할 정도로 `createFactory`를 몇 개만 호출하고 있고 JSX를 사용하고 싶지 않다면, [`createElement`](/reference/react/createElement)를 실행하여 팩토리 함수를 대체할 수 있습니다. 예를 들어 이 코드는, +직접 옮겨와도 무방할 정도로 `createFactory`를 몇 개만 호출하고 있고 JSX를 사용하고 싶지 않다면, [`createElement`](/reference/react/createElement)를 실행하여 팩토리 함수를 대체할 수 있습니다. 예를 들어 이 코드는, ```js {1,3,6} diff --git a/src/content/reference/react/forwardRef.md b/src/content/reference/react/forwardRef.md index e849fca32..191125e5b 100644 --- a/src/content/reference/react/forwardRef.md +++ b/src/content/reference/react/forwardRef.md @@ -328,7 +328,7 @@ const FormField = forwardRef(function FormField({ label, isRequired }, ref) { ref={ref} label={label} value={value} - onChange={e => setValue(e.target.value)} + onChange={e => setValue(e.target.value)} /> {(isRequired && value === '') && <i>Required</i> diff --git a/src/content/reference/react/memo.md b/src/content/reference/react/memo.md index 687b766bd..e0437458a 100644 --- a/src/content/reference/react/memo.md +++ b/src/content/reference/react/memo.md @@ -34,7 +34,7 @@ const SomeComponent = memo(function SomeComponent(props) { #### 매개변수 {/*parameters*/} -* `Component`: memoize 하려는 컴포넌트입니다. `memo`는 이 컴포넌트를 수정하지 않고 대신 새로운 memoized 컴포넌트를 반환합니다. 함수와 [`forwardRef`](/reference/react/forwardRef) 컴포넌트를 포함한 모든 유효한 React 컴포넌트가 허용됩니다. +* `Component`: memoize 하려는 컴포넌트입니다. `memo`는 이 컴포넌트를 수정하지 않고 대신 새로운 memoized 컴포넌트를 반환합니다. 함수와 [`forwardRef`](/reference/react/forwardRef) 컴포넌트를 포함한 모든 유효한 React 컴포넌트가 허용됩니다. * **optional** `arePropsEqual`: 컴포넌트의 이전 props와 새로운 props의 두 가지 인수를 받는 함수입니다. 이전 props와 새로운 props가 동일한 경우, 즉 컴포넌트가 이전 props와 동일한 결과를 렌더링하고 새로운 props에서도 이전 props와 동일한 방식으로 동작하는 경우 `true`를 반환해야 합니다. 그렇지 않으면 `false`를 반환해야 합니다. 일반적으로 이 함수를 지정하지 않습니다. React는 기본적으로 [`Object.is`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/is)로 각 props를 비교합니다. @@ -221,7 +221,7 @@ export default function MyApp() { const [theme, setTheme] = useState('dark'); function handleClick() { - setTheme(theme === 'dark' ? 'light' : 'dark'); + setTheme(theme === 'dark' ? 'light' : 'dark'); } return ( diff --git a/src/content/reference/react/use.md b/src/content/reference/react/use.md index f3deb228a..901099326 100644 --- a/src/content/reference/react/use.md +++ b/src/content/reference/react/use.md @@ -74,7 +74,7 @@ import { use } from 'react'; function Button() { const theme = use(ThemeContext); - // ... + // ... ``` `use`는 전달한 <CodeStep step={1}>context</CodeStep>의 <CodeStep step={2}>context 값</CodeStep>을 반환합니다. context 값을 결정하기 위해 React는 컴포넌트 트리를 탐색하고 **위에서 가장 가까운 context provider**를 찾습니다. diff --git a/src/content/reference/react/useActionState.md b/src/content/reference/react/useActionState.md index f24569478..0a91375f4 100644 --- a/src/content/reference/react/useActionState.md +++ b/src/content/reference/react/useActionState.md @@ -80,7 +80,7 @@ Server Action과 함께 사용하는 경우, `useActionState`를 사용하여 hy #### 주의 사항 {/*caveats*/} * React 서버 컴포넌트를 지원하는 프레임워크와 함께 사용할 때, `useActionState`는 클라이언트에서 자바스크립트가 실행되기 이전에도 폼을 상호작용하도록 만들 수 있습니다. 서버 컴포넌트를 사용하지 않는다면 컴포넌트 지역 state와 동일합니다. -* `useActionState`에 전달한 함수는 첫 번째 인수로 이전 혹은 초기 state를 추가로 받습니다. 이를 통해 `useActionState`를 사용하지 않고 직접 폼 액션을 사용했을 경우와는 다른 시그니처를 가지게 됩니다. +* `useActionState`에 전달한 함수는 첫 번째 인수로 이전 혹은 초기 state를 추가로 받습니다. 이를 통해 `useActionState`를 사용하지 않고 직접 폼 액션을 사용했을 경우와는 다른 시그니처를 가지게 됩니다. --- diff --git a/src/content/reference/react/useCallback.md b/src/content/reference/react/useCallback.md index 7445e7c80..74481136c 100644 --- a/src/content/reference/react/useCallback.md +++ b/src/content/reference/react/useCallback.md @@ -123,7 +123,7 @@ function ProductPage({ productId, referrer, theme }) { orderDetails, }); } - + return ( <div className={theme}> {/* ... 그래서 ShippingForm의 props는 같은 값이 아니므로 매번 리렌더링 할 것입니다.*/} @@ -158,7 +158,7 @@ function ProductPage({ productId, referrer, theme }) { <Note> -**`useCallback`은 성능 최적화를 위한 용도로만 사용해야 합니다.** 만약 코드가 `useCallback` 없이 작동하지 않는다면 먼저 근본적인 문제를 찾아 해결해야 합니다. 그다음에 `useCallback`을 다시 추가할 수 있습니다. +**`useCallback`은 성능 최적화를 위한 용도로만 사용해야 합니다.** 만약 코드가 `useCallback` 없이 작동하지 않는다면 먼저 근본적인 문제를 찾아 해결해야 합니다. 그다음에 `useCallback`을 다시 추가할 수 있습니다. </Note> @@ -219,7 +219,7 @@ function useCallback(fn, dependencies) { `useCallback`으로 함수를 캐싱하는 것은 몇 가지 경우에만 가치 있습니다. -- [`memo`](/reference/react/memo)로 감싸진 컴포넌트에 prop으로 넘깁니다. 이 값이 변하지 않으면 리렌더링을 건너뛰고 싶습니다. memoization은 의존성이 변했을 때만 컴포넌트가 리렌더링하도록 합니다. +- [`memo`](/reference/react/memo)로 감싸진 컴포넌트에 prop으로 넘깁니다. 이 값이 변하지 않으면 리렌더링을 건너뛰고 싶습니다. memoization은 의존성이 변했을 때만 컴포넌트가 리렌더링하도록 합니다. - 넘긴 함수가 나중에 어떤 Hook의 의존성으로 사용됩니다. 예를 들어, `useCallback`으로 감싸진 다른 함수가 이 함수에 의존하거나, [`useEffect`](/reference/react/useEffect)에서 이 함수에 의존합니다. 다른 경우에서 `useCallback`으로 함수를 감싸는 것은 아무런 이익이 없습니다. 또한 이렇게 하는 것이 큰 불이익을 가져오지도 않으므로 일부 팀은 개별적인 경우를 따로 생각하지 않고, 가능한 한 많이 memoization하는 방식을 택합니다. 단점은 코드의 가독성이 떨어지는 것입니다. 또한, 모든 memoization이 효과적인 것은 아닙니다. "항상 새로운" 하나의 값이 있다면 전체 컴포넌트의 memoization을 깨기에 충분합니다. @@ -316,7 +316,7 @@ const ShippingForm = memo(function ShippingForm({ onSubmit }) { } function handleSubmit(e) { - e.preventDefault(); + e.preventDefault(); const formData = new FormData(e.target); const orderDetails = { ...Object.fromEntries(formData), @@ -386,7 +386,7 @@ button[type="button"] { 이 예시에서 `ShippingForm` 컴포넌트 또한 **인위적으로 느리게 만들었기 때문에** 렌더링하는 React 컴포넌트가 실제로 느릴 때 어떤 일이 일어나는 지 볼 수 있습니다. 카운터를 증가시키고 테마를 토글 해보세요. -이전 예시와 다르게 지금은 테마를 토글 하는 것도 느립니다! **이 버전에서는 `useCallback`을 호출하고 있지 않기** 때문에 `handleSubmit`은 항상 새로운 함수이고, 느려진 `ShippingForm` 컴포넌트는 리렌더링을 건너뛸 수 없습니다. +이전 예시와 다르게 지금은 테마를 토글 하는 것도 느립니다! **이 버전에서는 `useCallback`을 호출하고 있지 않기** 때문에 `handleSubmit`은 항상 새로운 함수이고, 느려진 `ShippingForm` 컴포넌트는 리렌더링을 건너뛸 수 없습니다. <Sandpack> @@ -663,7 +663,7 @@ button[type="button"] { 때때로 memoized 콜백에서 이전 상태를 기반으로 상태를 업데이트해야 할 때가 있습니다. -`handleAddTodo` 함수는 `todos`로부터 다음 할 일을 계산하기 때문에 이를 의존성으로 명시했습니다. +`handleAddTodo` 함수는 `todos`로부터 다음 할 일을 계산하기 때문에 이를 의존성으로 명시했습니다. ```js {6,7} function TodoList() { diff --git a/src/content/reference/react/useContext.md b/src/content/reference/react/useContext.md index 1182a1b9a..f930e223d 100644 --- a/src/content/reference/react/useContext.md +++ b/src/content/reference/react/useContext.md @@ -43,7 +43,7 @@ function MyComponent() { #### 주의 사항 {/*caveats*/} * 컴포넌트 내의 `useContext()` 호출은 **동일한** 컴포넌트에서 반환된 provider에 영향을 받지 않습니다. 해당하는 `<Context.Provider>` 는 `useContext()` 호출을 하는 컴포넌트 ***위에* 배치되어야 합니다.** -* React는 다른 `value`을 받는 provider로부터 시작해서 특정 context를 사용하는 모든 자식들을 **자동으로 리렌더링**합니다. 이전 값과 다음 값은 [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) 비교를 통해 비교됩니다. [`memo`](/reference/react/memo)로 리렌더링을 건너뛰어도 자식들이 새로운 context 값을 받는 것을 막지는 못합니다. +* React는 다른 `value`을 받는 provider로부터 시작해서 특정 context를 사용하는 모든 자식들을 **자동으로 리렌더링**합니다. 이전 값과 다음 값은 [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) 비교를 통해 비교됩니다. [`memo`](/reference/react/memo)로 리렌더링을 건너뛰어도 자식들이 새로운 context 값을 받는 것을 막지는 못합니다. * 빌드 시스템이 결과물에 중복 모듈을 생성하는 경우(심볼릭 링크에서 발생할 수 있음) context가 손상될 수 있습니다. context를 통해 무언가를 전달하는 것은 `===` 비교에 의해 결정되는 것처럼 컨텍스트를 제공하는 데 사용하는 `SomeContext`와 context를 읽는 데 사용하는 `SomeContext`가 ***정확하게* 동일한 객체**인 경우에만 작동합니다. --- @@ -60,7 +60,7 @@ import { useContext } from 'react'; function Button() { const theme = useContext(ThemeContext); - // ... + // ... ``` `useContext`는 전달한 <CodeStep step={1}>context</CodeStep> 에 대한 <CodeStep step={2}>context value </CodeStep>를 반환합니다. context 값을 결정하기 위해 React는 컴포넌트 트리를 검색하고 특정 context에 대해 **상위에서 가장 가까운 context provider**를 찾습니다. @@ -85,7 +85,7 @@ provider와 `Button`사이에 얼마나 많은 컴포넌트 레이어가 있는 <Pitfall> -`useContext()` 는 항상 호출하는 컴포넌트 *상위*에서 가장 가까운 provider를 찾습니다. 위쪽으로 찾고 `useContext()`를 호출하는 컴포넌트 안의 provider는 **고려하지 않습니다.** +`useContext()` 는 항상 호출하는 컴포넌트 *상위*에서 가장 가까운 provider를 찾습니다. 위쪽으로 찾고 `useContext()`를 호출하는 컴포넌트 안의 provider는 **고려하지 않습니다.** </Pitfall> @@ -845,7 +845,7 @@ export default function AddTask() { type: 'added', id: nextId++, text: text, - }); + }); }}>Add</button> </> ); @@ -1292,7 +1292,7 @@ export const LevelContext = createContext(0); context를 통해 객체와 함수를 포함한 모든 값을 전달할 수 있습니다. -```js [[2, 10, "{ currentUser, login }"]] +```js [[2, 10, "{ currentUser, login }"]] function MyApp() { const [currentUser, setCurrentUser] = useState(null); diff --git a/src/content/reference/react/useDeferredValue.md b/src/content/reference/react/useDeferredValue.md index 4b192b5ce..777351f63 100644 --- a/src/content/reference/react/useDeferredValue.md +++ b/src/content/reference/react/useDeferredValue.md @@ -189,7 +189,7 @@ function use(promise) { reason => { promise.status = 'rejected'; promise.reason = reason; - }, + }, ); throw promise; } @@ -403,7 +403,7 @@ function use(promise) { reason => { promise.status = 'rejected'; promise.reason = reason; - }, + }, ); throw promise; } @@ -632,7 +632,7 @@ function use(promise) { reason => { promise.status = 'rejected'; promise.reason = reason; - }, + }, ); throw promise; } diff --git a/src/content/reference/react/useEffect.md b/src/content/reference/react/useEffect.md index ce2ffb7d9..807251bb6 100644 --- a/src/content/reference/react/useEffect.md +++ b/src/content/reference/react/useEffect.md @@ -45,7 +45,7 @@ function ChatRoom({ roomId }) { #### 매개변수 {/*parameters*/} + `setup(설정)`: Effect의 로직이 포함된 함수입니다. 설정 함수는 선택적으로 *clean up(정리)* 함수를 반환할 수 있습니다. React는 컴포넌트가 DOM에 추가된 이후에 설정 함수를 실행합니다. 의존성의 변화에 따라 컴포넌트가 리렌더링이 되었을 경우, (설정 함수에 정리 함수를 추가했었다면) React는 이전 렌더링에 사용된 값으로 정리 함수를 실행한 후 새로운 값으로 설정 함수를 실행합니다. 컴포넌트가 DOM에서 제거된 경우에도 정리 함수를 실행합니다. - + + `dependencies` **선택사항** : `설정` 함수의 코드 내부에서 참조되는 모든 반응형 값들이 포함된 배열로 구성됩니다. 반응형 값에는 props와 state, 모든 변수 및 컴포넌트 body에 직접적으로 선언된 함수들이 포함됩니다. 린터가 [React 환경에 맞게 설정되어 있을 경우](/learn/editor-setup#linting), 린터는 모든 반응형 값들이 의존성에 제대로 명시되어 있는지 검증할 것입니다. 의존성 배열은 항상 일정한 수의 항목을 가지고 있어야 하며 `[dep1, dep2, dep3]`과 같이 작성되어야 합니다. React는 각각의 의존성들을 [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) 비교법을 통해 이전 값과 비교합니다. 의존성을 생략할 경우, Effect는 컴포넌트가 리렌더링될 때마다 실행됩니다. [인수에 의존성 배열을 추가했을 때, 빈 배열을 추가했을 때, 의존성을 추가하지 않았을 때의 차이를 확인해 보세요.](#examples-dependencies) #### 반환값 {/*returns*/} @@ -114,7 +114,7 @@ function ChatRoom({ roomId }) { **위의 예시를 통해 순서를 설명해 보겠습니다.** -위의 `ChatRoom` 컴포넌트가 화면에 추가되면 초기 `serverUrl`과 `roomId`를 이용해 채팅방과 연결될 것입니다. 리렌더링에 의해 `serverUrl` 또는 `roomId`가 변경된다면 (예를 들어 사용자가 드롭다운 메뉴를 이용해 다른 채팅방을 선택할 경우) *Effect는 이전 채팅방과의 연결을 해제하고 다음 채팅방과 연결합니다.* `ChatRoom` 컴포넌트가 화면에서 제거된다면 Effect는 마지막 채팅방과 이뤄진 연결을 해제할 것입니다. +위의 `ChatRoom` 컴포넌트가 화면에 추가되면 초기 `serverUrl`과 `roomId`를 이용해 채팅방과 연결될 것입니다. 리렌더링에 의해 `serverUrl` 또는 `roomId`가 변경된다면 (예를 들어 사용자가 드롭다운 메뉴를 이용해 다른 채팅방을 선택할 경우) *Effect는 이전 채팅방과의 연결을 해제하고 다음 채팅방과 연결합니다.* `ChatRoom` 컴포넌트가 화면에서 제거된다면 Effect는 마지막 채팅방과 이뤄진 연결을 해제할 것입니다. React는 **[버그를 발견하기 위해](/learn/synchronizing-with-effects#step-3-add-cleanup-if-needed) 개발모드에서 <CodeStep step={1}>설정</CodeStep>이 실행되기 전에 <CodeStep step={1}>설정</CodeStep>과 <CodeStep step={2}>정리</CodeStep>를 한 번 더 실행시킵니다.** 이는 스트레스 테스트의 하나로써 Effect의 로직이 정확하게 수행되고 있는지를 검증합니다. 만약 가시적인 이슈가 보인다면 정리 함수의 로직에 놓친 부분이 있는 것입니다. 정리 함수는 설정 함수의 어떠한 동작이라도 중지하거나 실행 취소를 할 수 있어야 하며, 사용자는 *설정* 함수가 한 번 호출될 때와 *설정* → *정리* → *설정* 순서로 호출될 때의 차이를 느낄 수 없어야 합니다. @@ -137,7 +137,7 @@ An Effect lets you [keep your component synchronized](/learn/synchronizing-with- #### 채팅 서버와 연결 {/*connecting-to-a-chat-server*/} -이 예시에서는 `ChatRoom` 컴포넌트의 Effect를 통해 `chat.js`로 정의된 외부 시스템과 연결을 유지합니다. "Open chat"을 누르면 `ChatRoom` 컴포넌트가 나타납니다. 이 샌드박스는 개발 모드에서 동작하므로 [추가적인 연결-연결해제 사이클](/learn/synchronizing-with-effects#step-3-add-cleanup-if-needed)이 동작합니다. 드롭다운 메뉴나 input을 이용해 `roomId` 또는 `serverUrl`를 변경하고 어떻게 Effect가 chat을 재연결하는지 확인해 보세요. "Close chat"을 눌러 Effect가 마지막에 연결되었던 chat을 연결 해제하는 것도 확인해 보세요. +이 예시에서는 `ChatRoom` 컴포넌트의 Effect를 통해 `chat.js`로 정의된 외부 시스템과 연결을 유지합니다. "Open chat"을 누르면 `ChatRoom` 컴포넌트가 나타납니다. 이 샌드박스는 개발 모드에서 동작하므로 [추가적인 연결-연결해제 사이클](/learn/synchronizing-with-effects#step-3-add-cleanup-if-needed)이 동작합니다. 드롭다운 메뉴나 input을 이용해 `roomId` 또는 `serverUrl`를 변경하고 어떻게 Effect가 chat을 재연결하는지 확인해 보세요. "Close chat"을 눌러 Effect가 마지막에 연결되었던 chat을 연결 해제하는 것도 확인해 보세요. <Sandpack> @@ -1083,7 +1083,7 @@ function ChatRoom({ roomId }) { // 이것은 반응형 값입니다 ```js {8} function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); - + useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); diff --git a/src/content/reference/react/useImperativeHandle.md b/src/content/reference/react/useImperativeHandle.md index f6dc7a9ee..63a24436f 100644 --- a/src/content/reference/react/useImperativeHandle.md +++ b/src/content/reference/react/useImperativeHandle.md @@ -4,7 +4,7 @@ title: useImperativeHandle <Intro> -`useImperativeHandle`은 [ref](/learn/manipulating-the-dom-with-refs)로 노출되는 핸들을 사용자가 직접 정의할 수 있게 해주는 React 훅입니다. +`useImperativeHandle`은 [ref](/learn/manipulating-the-dom-with-refs)로 노출되는 핸들을 사용자가 직접 정의할 수 있게 해주는 React 훅입니다. ```js useImperativeHandle(ref, createHandle, dependencies?) diff --git a/src/content/reference/react/useInsertionEffect.md b/src/content/reference/react/useInsertionEffect.md index 55558328d..f1bd6a3e8 100644 --- a/src/content/reference/react/useInsertionEffect.md +++ b/src/content/reference/react/useInsertionEffect.md @@ -45,7 +45,7 @@ function useCSS(rule) { #### 매개변수 {/*parameters*/} * `setup`: Effects 의 로직이 포함된 함수입니다. setup 함수는 선택적으로 *cleanup* 함수를 반환할 수도 있습니다. 컴포넌트가 DOM에 추가되기 전에, layout Effects 가 실행되기 전에, React는 setup 함수를 실행합니다. `dependencies`가 변경되어 다시 렌더링할 때마다, React는 먼저 이전 값으로 cleanup 함수(제공한 경우)를 실행한 다음 새 값으로 setup 함수를 실행합니다. 컴포넌트가 DOM에서 제거되기 전에 React는 cleanup 함수를 한 번 더 실행합니다. - + * **선택사항** `dependencies`: `setup` 코드 내에서 참조된 모든 반응형 값의 목록입니다. 반응형 값에는 props, state, 그리고 컴포넌트 본문에 직접 선언된 모든 변수와 함수가 포함됩니다. linter가 [React용으로 설정된](/learn/editor-setup#linting) 경우, 모든 반응형 값이 의존성으로 올바르게 지정되었는지 확인합니다. 의존성 목록에는 일정한 수의 항목이 있어야 하며 `[dep1, dep2, dep3]`와 같이 작성해야 합니다. React는 [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) 비교 알고리즘을 사용하여 각 의존성을 이전 값과 비교합니다. 의존성을 전혀 지정하지 않으면 컴포넌트를 다시 렌더링할 때마다 Effect가 다시 실행됩니다. #### 반환값 {/*returns*/} diff --git a/src/content/reference/react/useLayoutEffect.md b/src/content/reference/react/useLayoutEffect.md index d0cdc7a42..971a97225 100644 --- a/src/content/reference/react/useLayoutEffect.md +++ b/src/content/reference/react/useLayoutEffect.md @@ -48,8 +48,8 @@ function Tooltip() { #### 매개변수 {/*parameters*/} -* `setup`: Effect의 로직이 포함된 함수입니다. setup 함수는 선택적으로 *cleanup* 함수를 반환할 수도 있습니다. 컴포넌트가 DOM에 추가되기 전에 React는 setup 함수를 실행합니다. `dependencies`가 변경되어 다시 렌더링 될 때마다, React는 (cleanup 함수를 제공했다면) 먼저 이전 값으로 cleanup 함수를 실행한 다음, 새로운 값으로 setup 함수를 실행합니다. 컴포넌트가 DOM에서 제거되기 전에 React는 cleanup 함수를 한 번 더 실행합니다. - +* `setup`: Effect의 로직이 포함된 함수입니다. setup 함수는 선택적으로 *cleanup* 함수를 반환할 수도 있습니다. 컴포넌트가 DOM에 추가되기 전에 React는 setup 함수를 실행합니다. `dependencies`가 변경되어 다시 렌더링 될 때마다, React는 (cleanup 함수를 제공했다면) 먼저 이전 값으로 cleanup 함수를 실행한 다음, 새로운 값으로 setup 함수를 실행합니다. 컴포넌트가 DOM에서 제거되기 전에 React는 cleanup 함수를 한 번 더 실행합니다. + * **선택사항** `dependencies`: `setup`코드 내에서 참조된 모든 반응형 값의 목록입니다. 반응형 값에는 props, state, 그리고 컴포넌트 본문에 직접 선언된 모든 변수와 함수가 포함됩니다. linter가 [React용으로 설정된](/learn/editor-setup#linting) 경우, 모든 반응형 값이 의존성으로 올바르게 지정되었는지 확인합니다. 의존성 목록에는 일정한 수의 항목이 있어야 하며 `[dep1, dep2, dep3]`와 같이 작성해야 합니다. React는 [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) 비교 알고리즘을 사용하여 각 의존성을 이전 값과 비교합니다. 의존성을 전혀 지정하지 않으면 컴포넌트를 다시 렌더링할 때마다 Effect가 다시 실행됩니다. #### 반환값 {/*returns*/} @@ -59,7 +59,7 @@ function Tooltip() { #### 주의 사항 {/*caveats*/} * `useLayoutEffect`는 Hook이므로, **컴포넌트의 최상위 레벨** 또는 커스텀 Hook에서만 호출할 수 있습니다. 반복문이나 조건문 내에서 호출할 수 없습니다. 이 작업이 필요하다면 새로운 컴포넌트로 분리해서 Effect를 새 컴포넌트로 옮기세요. - + * Strict Mode가 켜져 있으면, React는 실제 첫 번째 setup 함수가 실행되기 이전에 **개발 모드에만 한정하여 한 번의 추가적인 setup + cleanup 사이클을 실행합니다.** 이는 cleanup 로직이 setup 로직을 완벽히 "반영"하고, setup 로직이 수행하는 작업을 중단하거나 되돌리는 지를 확인하는 스트레스 테스트입니다. 이로 인해 문제가 발생하면 [cleanup 함수를 구현하세요.](/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development) * 의존성 중에 컴포넌트 내부에서 정의된 객체나 함수가 있는 경우, **Effect 가 필요 이상으로 다시 실행될 위험이 있습니다.** 이를 해결하려면 불필요한 [객체 의존성](/reference/react/useEffect#removing-unnecessary-object-dependencies)이나 [함수 의존성](/reference/react/useEffect#removing-unnecessary-function-dependencies)을 제거하세요. [State 업데이트](/reference/react/useEffect#updating-state-based-on-previous-state-from-an-effect)나 [비 반응형 로직](/reference/react/useEffect#reading-the-latest-props-and-state-from-an-effect)을 effect 밖으로 빼낼 수 도 있습니다. @@ -720,7 +720,7 @@ export default function TooltipContainer({ children, x, y, contentRef }) { `useLayoutEffect`의 목적은 [레이아웃 정보를 사용해서](#measuring-layout-before-the-browser-repaints-the-screen) 컴포넌트를 렌더링하는 것입니다. 1. 초기 콘텐츠를 렌더링합니다. -2. *브라우저가 화면을 다시 그리기 전에* 레이아웃을 계산합니다. +2. *브라우저가 화면을 다시 그리기 전에* 레이아웃을 계산합니다. 3. 읽은 레이아웃 정보를 사용해서 최종 콘텐츠를 렌더링합니다. [서버 렌더링](/reference/react-dom/server)을 직접 사용하거나 프레임워크에서 사용하는 경우라면, React 앱은 서버에서 초기 렌더링을 해서 HTML을 만듭니다. 이를 통해 JavaScript 코드가 로드되기 전에 초기 HTML을 보여주게 됩니다. @@ -737,6 +737,6 @@ export default function TooltipContainer({ children, x, y, contentRef }) { - 또는 [해당 컴포넌트를 클라이언트 전용으로 만드세요.](/reference/react/Suspense#providing-a-fallback-for-server-errors-and-client-only-content) React가 가장 가까운 [`<Suspense>`](/reference/react/Suspense) 경계 안의 콘텐츠를 서버렌더링 동안 (스피너나 글리머같은) loading fallbck으로 대체 하게 합니다. -- 또는 `useLayoutEffect`가 있는 컴포넌트를 hydration 이후에만 렌더링할 수도 있습니다. 불리언 타입인 `isMounted` state를 초깃값인 `false`로 유지하다가, `useEffect` 호출되면 거기서 `true`로 값을 변경하세요. 그러면 렌더링 로직은 `return isMounted ? <RealContent /> : <FallbackContent />` 처럼 될 수 있습니다. 서버에서 렌더링하는 중이거나 hydration 동안 사용자는 `FallbackContent`를 볼 것이고 `FallbackContent`는 `useLayoutEffect`를 호출하지 않아야 합니다. 그 후에 React가 `FallbackContent`를 클라이언트 전용이면서 `useLayoutEffect`를 호출하는 `RealContent`로 변경할 겁니다. +- 또는 `useLayoutEffect`가 있는 컴포넌트를 hydration 이후에만 렌더링할 수도 있습니다. 불리언 타입인 `isMounted` state를 초깃값인 `false`로 유지하다가, `useEffect` 호출되면 거기서 `true`로 값을 변경하세요. 그러면 렌더링 로직은 `return isMounted ? <RealContent /> : <FallbackContent />` 처럼 될 수 있습니다. 서버에서 렌더링하는 중이거나 hydration 동안 사용자는 `FallbackContent`를 볼 것이고 `FallbackContent`는 `useLayoutEffect`를 호출하지 않아야 합니다. 그 후에 React가 `FallbackContent`를 클라이언트 전용이면서 `useLayoutEffect`를 호출하는 `RealContent`로 변경할 겁니다. - 컴포넌트를 외부 데이터 저장소와 동기화하고, 레이아웃 계산 외에 다른 이유로 `useLayoutEffect`에 의존하는 경우라면, 대신 [`useSyncExternalStore`](/reference/react/useSyncExternalStore)를 고려해 보세요. 이 Hook은 [서버 렌더링을 지원합니다.](/reference/react/useSyncExternalStore#adding-support-for-server-rendering) diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index 9b4be3e84..bfedc1a59 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -143,13 +143,13 @@ console.timeEnd('filter array'); #### 모든 곳에 useMemo를 추가해야 하나요? {/*should-you-add-usememo-everywhere*/} -이 사이트와 같이 대부분의 상호 작용이 거친 경우(페이지 또는 전체 섹션이 교체되는 것과 같이) 메모이제이션이 필요하지 않습니다. 반면, 앱이 그림 편집기와 비슷하고 대부분의 상호 작용이 세분화된 경우(도형 이동과 같은) 메모이제이션이 매우 유용할 수 있습니다. +이 사이트와 같이 대부분의 상호 작용이 거친 경우(페이지 또는 전체 섹션이 교체되는 것과 같이) 메모이제이션이 필요하지 않습니다. 반면, 앱이 그림 편집기와 비슷하고 대부분의 상호 작용이 세분화된 경우(도형 이동과 같은) 메모이제이션이 매우 유용할 수 있습니다. `useMemo`로 최적화하는 것은 몇몇 경우에만 유용합니다. - `useMemo`에 입력하는 계산이 눈에 띄게 느리고 종속성이 거의 변경되지 않는 경우. - [`memo`](/reference/react/memo)로 감싸진 컴포넌트에 prop로 전달할 경우. 값이 변경되지 않았다면 렌더링을 건너뛰고 싶을 것입니다. 메모이제이션을 사용하면 의존성이 동일하지 않은 경우에만 컴포넌트를 다시 렌더링할 수 있습니다. -- 전달한 값을 나중에 일부 Hook의 종속성으로 이용할 경우. 예를 들어, 다른 `useMemo`의 계산 값이 여기에 종속되어 있을 수 있습니다. 또는 [`useEffect`](/reference/react/useEffect)의 값에 종속되어 있을 수 있습니다. +- 전달한 값을 나중에 일부 Hook의 종속성으로 이용할 경우. 예를 들어, 다른 `useMemo`의 계산 값이 여기에 종속되어 있을 수 있습니다. 또는 [`useEffect`](/reference/react/useEffect)의 값에 종속되어 있을 수 있습니다. 이 외는 계산을 `useMemo`로 감싸는 것에 대한 이득이 없습니다. 그러나 그렇게 한다고 해서 크게 문제가 되는 것도 아니므로 일부 팀에서는 개별 사례에 대해 생각하지 않고 가능한 한 많이 메모하는 방식을 선택합니다. 이 접근 방식의 단점은 코드 가독성이 떨어진다는 것입니다. 또한, 모든 메모이제이션이 효과적인 것은 아닙니다. "항상 새로운" 단일 값만으로도 전체 컴포넌트에 대한 메모화가 깨질 수 있기 때문입니다. @@ -173,7 +173,7 @@ console.timeEnd('filter array'); 탭을 전환하면 느려진 `filterTodos`가 다시 실행되므로 느리게 느껴집니다. 이는 `tab`이 변경되었으므로 전체 계산이 *필수적으로* 다시 실행되기 때문에 나타나는 현상입니다. (왜 두 번 실행되는지 궁금하다면 [여기](#my-calculation-runs-twice-on-every-re-render)를 클릭해서 설명을 확인하세요.) -테마를 전환합니다. **인위적인 속도 저하에도 불구하고 빠른 이유는 `useMemo` 덕분입니다!** 느린 속도의 `filterTodos`는 마지막 렌더링 이후 (`useMemo`에 종속성으로 전달한)`todos`와 `tab`이 모두 변경되지 않았기 때문에 호출을 건너뛰었습니다. +테마를 전환합니다. **인위적인 속도 저하에도 불구하고 빠른 이유는 `useMemo` 덕분입니다!** 느린 속도의 `filterTodos`는 마지막 렌더링 이후 (`useMemo`에 종속성으로 전달한)`todos`와 `tab`이 모두 변경되지 않았기 때문에 호출을 건너뛰었습니다. <Sandpack> @@ -609,7 +609,7 @@ export default function TodoList({ todos, tab, theme }) { ``` -**`visibleTodos`연산을 `useMemo`로 감싸면 다시 렌더링 될 때마다 *같은* 값을 갖게 할 수 있습니다** (종속성이 변경되기 전까지). *특별한 이유가 없는 한* 연산을 `useMemo`로 감싸지 않아도 됩니다. 이 예시에서는 [`memo`](/reference/react/memo)로 감싸진 컴포넌트에 전달하면 재렌더링을 건너뛸 수 있기 때문입니다. 이 페이지에서 자세히 설명하는 `useMemo`를 추가해야 하는 몇 가지 다른 이유가 있습니다. +**`visibleTodos`연산을 `useMemo`로 감싸면 다시 렌더링 될 때마다 *같은* 값을 갖게 할 수 있습니다** (종속성이 변경되기 전까지). *특별한 이유가 없는 한* 연산을 `useMemo`로 감싸지 않아도 됩니다. 이 예시에서는 [`memo`](/reference/react/memo)로 감싸진 컴포넌트에 전달하면 재렌더링을 건너뛸 수 있기 때문입니다. 이 페이지에서 자세히 설명하는 `useMemo`를 추가해야 하는 몇 가지 다른 이유가 있습니다. <DeepDive> @@ -1122,7 +1122,7 @@ function ChatRoom({ roomId }) { serverUrl: 'https://localhost:1234', roomId: roomId } - + const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); @@ -1278,7 +1278,7 @@ React가 함수를 두 번 호출하므로 todo가 두 번 추가됩니다. 계 순수성에 대해 자세히 알아보려면 [컴포넌트 순수하게 유지하기](/learn/keeping-components-pure)를 읽어보세요. -또한 변경사항이 없는 [객체 업데이트](/learn/updating-objects-in-state) 및 [배열 업데이트](/learn/updating-arrays-in-state)에 대한 가이드도 확인해보세요. +또한 변경사항이 없는 [객체 업데이트](/learn/updating-objects-in-state) 및 [배열 업데이트](/learn/updating-arrays-in-state)에 대한 가이드도 확인해보세요. --- @@ -1363,7 +1363,7 @@ Object.is(temp1[2], temp2[2]); // ... 그리고 기타 모든 종속성들이 ### 반복문에서 각 목록 항목에 대해 `useMemo`를 호출해야 하는데 허용되지 않습니다. {/*i-need-to-call-usememo-for-each-list-item-in-a-loop-but-its-not-allowed*/} -`Chart` 컴포넌트가 [`memo`](/reference/react/memo)로 감싸져 있다고 가정해보겠습니다. `ReportList` 컴포넌트가 다시 렌더링 될 때 목록의 모든 `Chart`를 다시 렌더링하는 것을 생략하고 싶을 것입니다. 그러나 반복문에서 `useMemo`를 호출할 수 없습니다. +`Chart` 컴포넌트가 [`memo`](/reference/react/memo)로 감싸져 있다고 가정해보겠습니다. `ReportList` 컴포넌트가 다시 렌더링 될 때 목록의 모든 `Chart`를 다시 렌더링하는 것을 생략하고 싶을 것입니다. 그러나 반복문에서 `useMemo`를 호출할 수 없습니다. ```js {5-11} function ReportList({ items }) { diff --git a/src/content/reference/react/useReducer.md b/src/content/reference/react/useReducer.md index 9b45391f2..c055819fd 100644 --- a/src/content/reference/react/useReducer.md +++ b/src/content/reference/react/useReducer.md @@ -69,7 +69,7 @@ function handleClick() { // ... ``` -React는 현재 `state`와 `dispatch`를 통해 전달된 action을 제공받아 호출된 `reducer`의 반환값을 통해 다음 state값을 설정합니다. +React는 현재 `state`와 `dispatch`를 통해 전달된 action을 제공받아 호출된 `reducer`의 반환값을 통해 다음 state값을 설정합니다. #### 매개변수 {/*dispatch-parameters*/} @@ -199,7 +199,7 @@ Actions은 다양한 형태가 될 수 있습니다. 하지만 컨벤션에 따 ```js {5,9-12} function Form() { const [state, dispatch] = useReducer(reducer, { name: 'Taylor', age: 42 }); - + function handleButtonClick() { dispatch({ type: 'incremented_age' }); } @@ -292,7 +292,7 @@ export default function Form() { dispatch({ type: 'changed_name', nextName: e.target.value - }); + }); } return ( @@ -761,7 +761,7 @@ function TodoList({ username }) { #### 초기화 함수 전달 {/*passing-the-initializer-function*/} -이 예시에서는 초기화 단계에서만 동작하는 함수인 `createInitialState`를 초기화 함수로 전달합니다. 이 함수는 인풋에 입력 할 때 발생하는 리렌더링 상황 등에서는 호출되지 않습니다. +이 예시에서는 초기화 단계에서만 동작하는 함수인 `createInitialState`를 초기화 함수로 전달합니다. 이 함수는 인풋에 입력 할 때 발생하는 리렌더링 상황 등에서는 호출되지 않습니다. <Sandpack> diff --git a/src/content/reference/react/useState.md b/src/content/reference/react/useState.md index e19db6860..52d32168d 100644 --- a/src/content/reference/react/useState.md +++ b/src/content/reference/react/useState.md @@ -20,7 +20,7 @@ const [state, setState] = useState(initialState) ### `useState(initialState)` {/*usestate*/} -컴포넌트의 최상위 레벨에서 `useState`를 호출하여 [state 변수](/learn/state-a-components-memory)를 선언합니다. +컴포넌트의 최상위 레벨에서 `useState`를 호출하여 [state 변수](/learn/state-a-components-memory)를 선언합니다. ```js import { useState } from 'react'; @@ -79,7 +79,7 @@ function handleClick() { #### 주의 사항 {/*setstate-caveats*/} -* `set` 함수는 ***다음* 렌더링에 대한 state 변수만 업데이트합니다.** `set` 함수를 호출한 후에도 state 변수에는 여전히 호출 전 화면에 있던 [이전 값이 담겨 있습니다.](#ive-updated-the-state-but-logging-gives-me-the-old-value) +* `set` 함수는 ***다음* 렌더링에 대한 state 변수만 업데이트합니다.** `set` 함수를 호출한 후에도 state 변수에는 여전히 호출 전 화면에 있던 [이전 값이 담겨 있습니다.](#ive-updated-the-state-but-logging-gives-me-the-old-value) * 사용자가 제공한 새로운 값이 [`Object.is`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/is)에 의해 현재 `state`와 동일하다고 판정되면, React는 **컴포넌트와 그 자식들을 리렌더링하지 않습니다.** 이것이 바로 최적화입니다. 경우에 따라 React가 자식을 건너뛰기 전에 컴포넌트를 호출해야 할 수도 있지만, 코드에 영향을 미치지는 않습니다. @@ -607,8 +607,8 @@ export default function Form() { <br /> (located in {person.artwork.city}) </p> - <img - src={person.artwork.image} + <img + src={person.artwork.image} alt={person.artwork.title} /> </> @@ -1157,7 +1157,7 @@ function handleClick() { console.log(count); // 0 setCount(count + 1); // 1로 리렌더링 요청합니다. - console.log(count); // 아직 0입니다! + console.log(count); // 아직 0입니다! setTimeout(() => { console.log(count); // 여기도 0이고요! @@ -1225,16 +1225,16 @@ return <button onClick={(e) => handleClick(e)}>Click me</button> ```js {2,5-6,11-12} function TodoList() { - // 해당 함수형 컴포넌트는 렌더링 될 때마다 두 번 호출됩니다. + // 해당 함수형 컴포넌트는 렌더링 될 때마다 두 번 호출됩니다. const [todos, setTodos] = useState(() => { - // 해당 초기화 함수는 초기화 동안 두 번 호출됩니다. + // 해당 초기화 함수는 초기화 동안 두 번 호출됩니다. return createTodos(); }); function handleClick() { setTodos(prevTodos => { - // 해당 업데이터 함수는 클릭할 때마다 두 번 호출됩니다. + // 해당 업데이터 함수는 클릭할 때마다 두 번 호출됩니다. return [...prevTodos, createTodo()]; }); } diff --git a/src/content/reference/react/useSyncExternalStore.md b/src/content/reference/react/useSyncExternalStore.md index dd383c137..ef0b3692c 100644 --- a/src/content/reference/react/useSyncExternalStore.md +++ b/src/content/reference/react/useSyncExternalStore.md @@ -407,8 +407,8 @@ subscribe 함수는 컴포넌트 내부에 정의되므로 리렌더링할 때 ```js {4-7} function ChatIndicator() { const isOnline = useSyncExternalStore(subscribe, getSnapshot); - - // 🚩항상 다른 함수를 사용하므로 React는 렌더링할 때마다 다시 구독합니다. + + // 🚩항상 다른 함수를 사용하므로 React는 렌더링할 때마다 다시 구독합니다. function subscribe() { // ... } diff --git a/src/content/reference/rsc/server-actions.md b/src/content/reference/rsc/server-actions.md index cffaa1b6d..b8914e705 100644 --- a/src/content/reference/rsc/server-actions.md +++ b/src/content/reference/rsc/server-actions.md @@ -37,7 +37,7 @@ function EmptyNote () { async function createNoteAction() { // Server Action 'use server'; - + await db.notes.create(); } @@ -50,8 +50,8 @@ React가 `EmptyNote` 서버 컴포넌트를 렌더링할 때, `createNoteAction` ```js {5} "use client"; -export default function Button({onClick}) { - console.log(onClick); +export default function Button({onClick}) { + console.log(onClick); // {$$typeof: Symbol.for("react.server.reference"), $$id: 'createNoteAction'} return <button onClick={() => onClick()}>Create Empty Note</button> } @@ -123,7 +123,7 @@ function UpdateName() { } }) } - + return ( <form action={submitAction}> <input type="text" name="name" disabled={isPending}/> diff --git a/src/content/reference/rsc/server-components.md b/src/content/reference/rsc/server-components.md index 96676a2d1..04db179bf 100644 --- a/src/content/reference/rsc/server-components.md +++ b/src/content/reference/rsc/server-components.md @@ -40,7 +40,7 @@ function Page({page}) { setContent(data.content); }); }, [page]); - + return <div>{sanitizeHtml(marked(content))}</div>; } ``` @@ -64,7 +64,7 @@ import sanitizeHtml from 'sanitize-html'; // Not included in bundle async function Page({page}) { // NOTE: loads *during* render, when the app is built. const content = await file.readFile(`${page}.md`); - + return <div>{sanitizeHtml(marked(content))}</div>; } ``` @@ -108,7 +108,7 @@ function Note({id}) { setNote(data.note); }); }, [id]); - + return ( <div> <Author id={note.authorId} /> @@ -248,7 +248,7 @@ export default function Expandable({children}) { <p>this is the second note</p> </Expandable> <!--...--> - </div> + </div> </body> ``` @@ -265,8 +265,8 @@ import db from './database'; async function Page({id}) { // Will suspend the Server Component. const note = await db.notes.get(id); - - // NOTE: not awaited, will start here and await on the client. + + // NOTE: not awaited, will start here and await on the client. const commentsPromise = db.comments.get(note.id); return ( <div> diff --git a/src/content/reference/rsc/use-server.md b/src/content/reference/rsc/use-server.md index aae8cbf39..786ba40af 100644 --- a/src/content/reference/rsc/use-server.md +++ b/src/content/reference/rsc/use-server.md @@ -6,7 +6,7 @@ canary: true <Canary> -`'use server'`는 [React 서버 컴포넌트를 사용](/learn/start-a-new-react-project#bleeding-edge-react-frameworks)하거나 그와 호환되는 라이브러리를 만들 때만 필요합니다. +`'use server'`는 [React 서버 컴포넌트를 사용](/learn/start-a-new-react-project#bleeding-edge-react-frameworks)하거나 그와 호환되는 라이브러리를 만들 때만 필요합니다. </Canary> diff --git a/src/content/reference/rules/react-calls-components-and-hooks.md b/src/content/reference/rules/react-calls-components-and-hooks.md index 133d54662..708cd91f8 100644 --- a/src/content/reference/rules/react-calls-components-and-hooks.md +++ b/src/content/reference/rules/react-calls-components-and-hooks.md @@ -43,7 +43,7 @@ React가 렌더링을 조정하도록 하면 여러 이점이 있습니다. Hook은 컴포넌트나 Hook 내부에서만 호출되어야 합니다. Hook을 일반 값처럼 전달하지 마세요. -Hook은 컴포넌트에 React 기능을 추가할 수 있게 합니다. Hook은 항상 함수로 호출되어야 하며 일반 값처럼 전달하면 안 됩니다. Hook을 함수로 호출해야, 개발자가 컴포넌트를 독립적으로 이해할 수 있는 _로컬 추론_ 이 가능합니다. +Hook은 컴포넌트에 React 기능을 추가할 수 있게 합니다. Hook은 항상 함수로 호출되어야 하며 일반 값처럼 전달하면 안 됩니다. Hook을 함수로 호출해야, 개발자가 컴포넌트를 독립적으로 이해할 수 있는 _로컬 추론_ 이 가능합니다. 이 규칙을 어기면 React가 컴포넌트를 자동으로 최적화하지 못합니다. diff --git a/src/pages/_document.tsx b/src/pages/_document.tsx index 6849df35d..c03cba2a8 100644 --- a/src/pages/_document.tsx +++ b/src/pages/_document.tsx @@ -141,7 +141,7 @@ const MyDocument = () => { // An example of such content can be the keyboard shortcut displayed in the search bar document.documentElement.classList.add( window.navigator.platform.includes('Mac') - ? "platform-mac" + ? "platform-mac" : "platform-win" ); })(); diff --git a/src/utils/forwardRefWithAs.tsx b/src/utils/forwardRefWithAs.tsx index a0e73370d..354544a66 100644 --- a/src/utils/forwardRefWithAs.tsx +++ b/src/utils/forwardRefWithAs.tsx @@ -103,7 +103,7 @@ export function forwardRefWithAs<Props, ComponentType extends As>( } /* -Test components to make sure our dynamic As prop components work as intended +Test components to make sure our dynamic As prop components work as intended type PopupProps = { lol: string; children?: React.ReactNode | ((value?: number) => JSX.Element); From e894cee378285d5d10ac935987386ca313f8fd69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Sun, 29 Dec 2024 14:51:35 +0900 Subject: [PATCH 0430/1164] chore: create `.gitattributes` for consistent EOL handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `LF`를 사용하는 일관적인 EOL 핸들링을 위하여, `.gitattributes` 추가. --- .gitattributes | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..8a5a53391 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +# https://git-scm.com/docs/gitattributes + +# Ensure consistent EOL(LF) for all files that Git considers text files. +* text=auto eol=lf From 68e4587245ce0ddbf102780ced9dbac141ff067b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Sun, 29 Dec 2024 14:57:41 +0900 Subject: [PATCH 0431/1164] chore: create `.vscode/extensions.json` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vscode 사용자들을 위해 권장 설치사항 목록 추가. --- .vscode/extensions.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .vscode/extensions.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000..034db5d67 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "editorconfig.editorconfig" + ] +} From 95fcd9b7c7fa81d3538ae37d0f6cbe977eabb2f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Sun, 29 Dec 2024 15:04:42 +0900 Subject: [PATCH 0432/1164] chore: create `VScode.code-workspace` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 리포지토리에 `.code-workspace` 파일을 포함하면 팀 작업에서 일관성을 유지하고 설정을 간소화하며, 생산성을 높이는 데 유용합니다. --- VScode.code-workspace | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 VScode.code-workspace diff --git a/VScode.code-workspace b/VScode.code-workspace new file mode 100644 index 000000000..c7223d8ef --- /dev/null +++ b/VScode.code-workspace @@ -0,0 +1,7 @@ +{ + "folders": [ + { + "path": "." + } + ] +} From cb2e7f514fed6a7d9e5ac70e1db9f81f873b362b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Sun, 29 Dec 2024 15:38:31 +0900 Subject: [PATCH 0433/1164] chore: install `textlint-rule-allowed-uris` package as deps-dev for consistent markdown handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `https://ko.react.dev` 및 `http://ko.react.dev`로 시작하는 uri를 마크다운 문서에서 사용 금지하기 위하여 관련 플러그인 설치. --- .textlintrc | 5 - .textlintrc.js | 20 +++ package.json | 1 + src/content/learn/react-compiler.md | 6 +- src/content/reference/react/use.md | 6 +- src/content/reference/rules/index.md | 2 +- yarn.lock | 215 ++++++++++++++++++++++++++- 7 files changed, 241 insertions(+), 14 deletions(-) delete mode 100644 .textlintrc create mode 100644 .textlintrc.js diff --git a/.textlintrc b/.textlintrc deleted file mode 100644 index 474876784..000000000 --- a/.textlintrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "filters": { - "comments": true - } -} diff --git a/.textlintrc.js b/.textlintrc.js new file mode 100644 index 000000000..fc2a0b9a5 --- /dev/null +++ b/.textlintrc.js @@ -0,0 +1,20 @@ +module.exports = { + rules: { + 'allowed-uris': { + disallowed: { + /** + * Disallow URIs starting with the following strings: + * - https://ko.react.dev + * - http://ko.react.dev + * + * For example, + * `https://ko.react.dev/reference/rules` can be replaced with `/reference/rules`. + */ + links: [/https?:\/\/ko\.react\.dev/g], + }, + }, + }, + filters: { + comments: true, + }, +}; diff --git a/package.json b/package.json index 3e6a27bfe..2ac0fbf2b 100644 --- a/package.json +++ b/package.json @@ -102,6 +102,7 @@ "tailwindcss": "^3.4.1", "textlint": "^14.0.4", "textlint-filter-rule-comments": "^1.2.2", + "textlint-rule-allowed-uris": "^1.0.7", "textlint-tester": "^14.0.4", "typescript": "^4.0.2", "unist-util-visit": "^2.0.3", diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 588b2f071..6e0d3fc81 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -93,7 +93,7 @@ function TableContainer({ items }) { - React 컴파일러는 React 컴포넌트와 Hooks만 메모이제이션 하며, 모든 함수를 메모이제이션 하지 않습니다. - React 컴파일러의 메모이제이션은 여러 컴포넌트나 Hooks 사이에서 공유되지 않습니다. -따라서 `expensivelyProcessAReallyLargeArrayOfObjects`가 여러 다른 컴포넌트에서 사용되고 있다면 동일한 아이템이 전달되더라도 비용이 많이 드는 계산이 반복적으로 실행될 수 있습니다. 코드를 더 복잡하게 만들기 전에 먼저 [프로파일링](https://ko.react.dev/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive)을 통해 해당 계산이 실제로 비용이 많이 드는지 확인하는 것이 좋습니다. +따라서 `expensivelyProcessAReallyLargeArrayOfObjects`가 여러 다른 컴포넌트에서 사용되고 있다면 동일한 아이템이 전달되더라도 비용이 많이 드는 계산이 반복적으로 실행될 수 있습니다. 코드를 더 복잡하게 만들기 전에 먼저 [프로파일링](/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive)을 통해 해당 계산이 실제로 비용이 많이 드는지 확인하는 것이 좋습니다. </DeepDive> ### 컴파일러는 무엇을 가정하나요? {/*what-does-the-compiler-assume*/} @@ -102,7 +102,7 @@ React 컴파일러는 다음과 같이 가정합니다. 1. 올바르고 의미 있는 JavaScript 코드로 작성되었습니다. 2. nullable/optional 값과 속성에 접근하기 전에 그 값이 정의되어 있는지 테스트합니다. TypeScript를 사용하는 경우 [`strictNullChecks`](https://www.typescriptlang.org/ko/tsconfig/#strictNullChecks)을 활성화하여 수행합니다. 예를 들어 `if (object.nullableProperty) { object.nullableProperty.foo }`와 같이 처리하거나, 옵셔널 체이닝을 사용하여 `object.nullableProperty?.foo`와 같이 처리합니다. -3. [React의 규칙](https://ko.react.dev/reference/rules)을 따릅니다. +3. [React의 규칙](/reference/rules)을 따릅니다. React 컴파일러는 React의 많은 규칙을 정적으로 검증할 수 있으며, 에러가 감지되면 안전하게 컴파일을 건너뜁니다. 에러를 확인하려면 [`eslint-plugin-react-compiler`](https://www.npmjs.com/package/eslint-plugin-react-compiler)의 설치를 권장합니다. @@ -396,7 +396,7 @@ React 컴파일러 워킹 그룹에서도 회원으로 신청하여 피드백을 ### `(0 , _c) is not a function` 에러 {/*0--_c-is-not-a-function-error*/} -이 에러는 React 19 RC 이상을 사용하지 않을 경우 발생합니다. 이 문제를 해결하려면 먼저 [React 19 RC로 앱을 업그레이드](https://ko.react.dev/blog/2024/04/25/react-19-upgrade-guide)하세요. +이 에러는 React 19 RC 이상을 사용하지 않을 경우 발생합니다. 이 문제를 해결하려면 먼저 [React 19 RC로 앱을 업그레이드](/blog/2024/04/25/react-19-upgrade-guide)하세요. React 19로 업그레이드할 수 없는 경우, [워킹 그룹](https://github.com/reactwg/react-compiler/discussions/6)에서 설명한 대로 사용자 공간 캐시 함수 구현을 시도해 볼 수 있습니다. 그러나 가능하면 React 19로 업그레이드하는 것을 권장합니다. diff --git a/src/content/reference/react/use.md b/src/content/reference/react/use.md index 901099326..3861f0fc6 100644 --- a/src/content/reference/react/use.md +++ b/src/content/reference/react/use.md @@ -67,7 +67,7 @@ Promise와 함께 호출될 때 `use` Hook은 [`Suspense`](/reference/react/Susp ### `use`를 사용하여 context 참조하기 {/*reading-context-with-use*/} -[context](/learn/passing-data-deeply-with-context)가 `use`에 전달되면 [`useContext`](https://ko.react.dev/reference/react/useContext)와 유사하게 작동합니다. `useContext`는 컴포넌트의 최상위 수준에서 호출해야 하지만, `use`는 `if`와 같은 조건문이나 `for`와 같은 반복문 내부에서 호출할 수 있습니다. `use`는 유연하므로 `useContext`보다 선호됩니다. +[context](/learn/passing-data-deeply-with-context)가 `use`에 전달되면 [`useContext`](/reference/react/useContext)와 유사하게 작동합니다. `useContext`는 컴포넌트의 최상위 수준에서 호출해야 하지만, `use`는 `if`와 같은 조건문이나 `for`와 같은 반복문 내부에서 호출할 수 있습니다. `use`는 유연하므로 `useContext`보다 선호됩니다. ```js [[2, 4, "theme"], [1, 4, "ThemeContext"]] import { use } from 'react'; @@ -97,7 +97,7 @@ function Form() { provider와 `Button` 사이에 얼마나 많은 컴포넌트가 있는지는 중요하지 않습니다. `Form` 내부의 *어느 곳이든* `Button`이 `use(ThemeContext)`를 호출하면 `"dark"`를 값으로 받습니다. -[`useContext`](https://ko.react.dev/reference/react/useContext)와 달리, <CodeStep step={2}>`use`</CodeStep>는 <CodeStep step={1}>`if`</CodeStep>와 같은 조건문과 반복문 내부에서 호출할 수 있습니다. +[`useContext`](/reference/react/useContext)와 달리, <CodeStep step={2}>`use`</CodeStep>는 <CodeStep step={1}>`if`</CodeStep>와 같은 조건문과 반복문 내부에서 호출할 수 있습니다. ```js [[1, 2, "if"], [2, 3, "use"]] @@ -346,7 +346,7 @@ export default async function App() { } ``` -하지만 [서버 컴포넌트](https://ko.react.dev/reference/react/use-server)에서 `await`을 사용하면 `await` 문이 완료될 때까지 렌더링이 차단됩니다. 서버 컴포넌트에서 클라이언트 컴포넌트로 Promise를 prop으로 전달하면 Promise가 서버 컴포넌트의 렌더링을 차단하는 것을 방지할 수 있습니다. +하지만 [서버 컴포넌트](/reference/react/use-server)에서 `await`을 사용하면 `await` 문이 완료될 때까지 렌더링이 차단됩니다. 서버 컴포넌트에서 클라이언트 컴포넌트로 Promise를 prop으로 전달하면 Promise가 서버 컴포넌트의 렌더링을 차단하는 것을 방지할 수 있습니다. </DeepDive> diff --git a/src/content/reference/rules/index.md b/src/content/reference/rules/index.md index ceecaa7c0..586abda2b 100644 --- a/src/content/reference/rules/index.md +++ b/src/content/reference/rules/index.md @@ -28,7 +28,7 @@ React를 사용하여 UI를 표현하는 방법에 대해 더 알고 싶다면 [ * [컴포넌트는 멱등해야 합니다](/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent) – React 컴포넌트는 항상 입력 값(props, state, context)에 따라 동일한 출력을 반환한다고 가정합니다. * [사이드 이펙트는 렌더링 외부에서 실행되어야 합니다](/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) – [사이드 이펙트](/learn/keeping-components-pure#side-effects-unintended-consequences)는 React가 최상의 사용자 경험을 제공하기 위해 컴포넌트를 여러 번 렌더링할 수 있기 때문에 렌더링 중에 실행되어서는 안 됩니다. -* [Props와 state는 불변입니다](/reference/rules/components-and-hooks-must-be-pure#props-and-state-are-immutable) – 컴포넌트의 props와 state는 단일 렌더링에 대해 불변의 [스냅샷](https://ko.react.dev/learn/state-as-a-snapshot)입니다. 절대 이를 직접 변경하지 마세요. +* [Props와 state는 불변입니다](/reference/rules/components-and-hooks-must-be-pure#props-and-state-are-immutable) – 컴포넌트의 props와 state는 단일 렌더링에 대해 불변의 [스냅샷](/learn/state-as-a-snapshot)입니다. 절대 이를 직접 변경하지 마세요. * [Hook의 반환값과 인수는 불변입니다](/reference/rules/components-and-hooks-must-be-pure#return-values-and-arguments-to-hooks-are-immutable) – 값이 Hook에 전달되면 이를 수정해서는 안 됩니다. JSX의 props와 마찬가지로 Hook에 전달된 값도 불변입니다. * [JSX로 전달된 값은 불변입니다](/reference/rules/components-and-hooks-must-be-pure#values-are-immutable-after-being-passed-to-jsx) – JSX에 사용된 후에는 값을 변경하지 마세요. JSX가 생성되기 전에 변경을 수행하세요. diff --git a/yarn.lock b/yarn.lock index 6be6095b5..355c72f6e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1934,6 +1934,11 @@ astring@^1.8.0: resolved "https://registry.npmjs.org/astring/-/astring-1.8.3.tgz" integrity sha512-sRpyiNrx2dEYIMmUXprS8nlpRg2Drs8m9ElX9vVEXaCB4XEAJhKfs7IcX0IwShjuOAjLR6wzIrgoptz1n19i1A== +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + asyncro@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/asyncro/-/asyncro-3.0.0.tgz" @@ -1981,6 +1986,15 @@ axe-core@^4.3.5: resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz" integrity sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA== +axios@^1.7.4: + version "1.7.9" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.9.tgz#d7d071380c132a24accda1b2cfc1535b79ec650a" + integrity sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + axobject-query@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz" @@ -2053,6 +2067,11 @@ body-scroll-lock@^3.1.3: resolved "https://registry.npmjs.org/body-scroll-lock/-/body-scroll-lock-3.1.5.tgz" integrity sha512-Yi1Xaml0EvNA0OYWxXiYNqY24AfWkbA6w5vxE7GWxtKfzIbZM+Qw+aSmkgsbWzbHiy/RCSkUZBplVxTA+E4jJg== +boolbase@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== + boundary@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/boundary/-/boundary-2.0.0.tgz#169c8b1f0d44cf2c25938967a328f37e0a4e5efc" @@ -2247,6 +2266,35 @@ charenc@0.0.2: resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== +cheerio-select@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-2.1.0.tgz#4d8673286b8126ca2a8e42740d5e3c4884ae21b4" + integrity sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g== + dependencies: + boolbase "^1.0.0" + css-select "^5.1.0" + css-what "^6.1.0" + domelementtype "^2.3.0" + domhandler "^5.0.3" + domutils "^3.0.1" + +cheerio@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0.tgz#1ede4895a82f26e8af71009f961a9b8cb60d6a81" + integrity sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww== + dependencies: + cheerio-select "^2.1.0" + dom-serializer "^2.0.0" + domhandler "^5.0.3" + domutils "^3.1.0" + encoding-sniffer "^0.2.0" + htmlparser2 "^9.1.0" + parse5 "^7.1.2" + parse5-htmlparser2-tree-adapter "^7.0.0" + parse5-parser-stream "^7.1.2" + undici "^6.19.5" + whatwg-mimetype "^4.0.0" + chokidar@^3.4.0, chokidar@^3.5.3: version "3.5.3" resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" @@ -2358,6 +2406,13 @@ colorette@^2.0.16: resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz" integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g== +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + comma-separated-tokens@^1.0.0: version "1.0.8" resolved "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz" @@ -2484,6 +2539,22 @@ css-prefers-color-scheme@^3.1.1: dependencies: postcss "^7.0.5" +css-select@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.1.0.tgz#b8ebd6554c3637ccc76688804ad3f6a6fdaea8a6" + integrity sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg== + dependencies: + boolbase "^1.0.0" + css-what "^6.1.0" + domhandler "^5.0.2" + domutils "^3.0.1" + nth-check "^2.0.1" + +css-what@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" + integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== + cssdb@^4.4.0: version "4.4.0" resolved "https://registry.npmjs.org/cssdb/-/cssdb-4.4.0.tgz" @@ -2639,6 +2710,11 @@ define-properties@^1.2.0, define-properties@^1.2.1: has-property-descriptors "^1.0.0" object-keys "^1.1.1" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + depd@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" @@ -2700,6 +2776,36 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dom-serializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" + integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + entities "^4.2.0" + +domelementtype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== + +domhandler@^5.0.2, domhandler@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" + integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== + dependencies: + domelementtype "^2.3.0" + +domutils@^3.0.1, domutils@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.2.1.tgz#b39f4c390a1ae6f6a2c56a5f5a16d6438b6bce28" + integrity sha512-xWXmuRnN9OMP6ptPd2+H0cCbcYBULa5YDTbMm/2lvkWvNA3O4wcW+GvzooqBuNM8yy6pl3VIAeJTUUWUbfI5Fw== + dependencies: + dom-serializer "^2.0.0" + domelementtype "^2.3.0" + domhandler "^5.0.3" + dotenv@^16.0.3: version "16.0.3" resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz" @@ -2750,6 +2856,14 @@ encodeurl@~1.0.2: resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== +encoding-sniffer@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz#799569d66d443babe82af18c9f403498365ef1d5" + integrity sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg== + dependencies: + iconv-lite "^0.6.3" + whatwg-encoding "^3.1.1" + enquirer@^2.3.5: version "2.3.6" resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz" @@ -2757,6 +2871,11 @@ enquirer@^2.3.5: dependencies: ansi-colors "^4.1.1" +entities@^4.2.0, entities@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + error-ex@^1.2.0, error-ex@^1.3.1: version "1.3.2" resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" @@ -3459,6 +3578,11 @@ flatten@^1.0.2: resolved "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz" integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg== +follow-redirects@^1.15.6: + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + for-each@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" @@ -3466,6 +3590,15 @@ for-each@^0.3.3: dependencies: is-callable "^1.1.3" +form-data@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.1.tgz#ba1076daaaa5bfd7e99c1a6cb02aa0a5cff90d48" + integrity sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + format@^0.2.0: version "0.2.2" resolved "https://registry.npmjs.org/format/-/format-0.2.2.tgz" @@ -3897,6 +4030,16 @@ html-void-elements@^1.0.0: resolved "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz" integrity sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w== +htmlparser2@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-9.1.0.tgz#cdb498d8a75a51f739b61d3f718136c369bc8c23" + integrity sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.3" + domutils "^3.1.0" + entities "^4.5.0" + http-errors@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" @@ -3925,6 +4068,13 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@0.6.3, iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + ieee754@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" @@ -5487,7 +5637,7 @@ mime-types@2.1.13: dependencies: mime-db "~1.25.0" -mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@^2.1.12, mime-types@^2.1.35, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -5728,6 +5878,13 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" +nth-check@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" + integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== + dependencies: + boolbase "^1.0.0" + num2fraction@^1.2.2: version "1.2.2" resolved "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz" @@ -5998,6 +6155,28 @@ parse-numeric-range@^1.2.0: resolved "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz" integrity sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ== +parse5-htmlparser2-tree-adapter@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz#b5a806548ed893a43e24ccb42fbb78069311e81b" + integrity sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g== + dependencies: + domhandler "^5.0.3" + parse5 "^7.0.0" + +parse5-parser-stream@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz#d7c20eadc37968d272e2c02660fff92dd27e60e1" + integrity sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow== + dependencies: + parse5 "^7.0.0" + +parse5@^7.0.0, parse5@^7.1.2: + version "7.2.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.2.1.tgz#8928f55915e6125f430cc44309765bf17556a33a" + integrity sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ== + dependencies: + entities "^4.5.0" + parseurl@~1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" @@ -6570,6 +6749,11 @@ proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + punycode@^2.1.0: version "2.1.1" resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz" @@ -7118,7 +7302,7 @@ safe-regex-test@^1.0.3: es-errors "^1.3.0" is-regex "^1.1.4" -"safer-buffer@>= 2.1.2 < 3": +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -7682,6 +7866,16 @@ textlint-filter-rule-comments@^1.2.2: resolved "https://registry.yarnpkg.com/textlint-filter-rule-comments/-/textlint-filter-rule-comments-1.2.2.tgz#3a72c494994e068e0e4aaad0f24ea7cfe338503a" integrity sha512-AtyxreCPb3Hq/bd6Qd6szY1OGgnW34LOjQXAHzE8NoXbTUudQqALPdRe+hvRsf81rnmGLxBiCUXZbnbpIseFyw== +textlint-rule-allowed-uris@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/textlint-rule-allowed-uris/-/textlint-rule-allowed-uris-1.0.7.tgz#199edcc038817e771256c541aa975a077fa64472" + integrity sha512-cLFOc80dn3kMYlnsGjwoDEppxUaIw7A3fo35afEr1o7JDc1bSHcsymS3tVxJDDHfKBZk0AYE7hNrGDA8g+r6FQ== + dependencies: + ansi-colors "^4.1.3" + axios "^1.7.4" + cheerio "^1.0.0" + mime-types "^2.1.35" + textlint-tester@^14.0.4: version "14.0.4" resolved "https://registry.yarnpkg.com/textlint-tester/-/textlint-tester-14.0.4.tgz#ed1b4c65bbd2fe5f8f78bb02ebc6400bef393a7a" @@ -7974,6 +8168,11 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" +undici@^6.19.5: + version "6.21.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-6.21.0.tgz#4b3d3afaef984e07b48e7620c34ed8a285ed4cd4" + integrity sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw== + unherit@^1.0.4: version "1.1.3" resolved "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz" @@ -8306,6 +8505,18 @@ webpack-bundle-analyzer@^4.5.0: sirv "^1.0.7" ws "^7.3.1" +whatwg-encoding@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz#d0f4ef769905d426e1688f3e34381a99b60b76e5" + integrity sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ== + dependencies: + iconv-lite "0.6.3" + +whatwg-mimetype@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz#bc1bf94a985dc50388d54a9258ac405c3ca2fc0a" + integrity sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg== + which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz" From db2c0df023fcd822ac58e9bcc47cd81a3a2a519e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Sun, 29 Dec 2024 15:52:15 +0900 Subject: [PATCH 0434/1164] ci: update ci workflows to follow the latest react.dev source code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 최신 업데이트된 react.dev의 워크플로 반영. --- .github/workflows/analyze.yml | 18 +++++++++++++----- .github/workflows/site_lint.yml | 16 ++++++++++++---- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index 8330e30d2..555efe26b 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -11,18 +11,26 @@ jobs: analyze: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: '20.x' + cache: yarn + cache-dependency-path: yarn.lock - - name: Install dependencies - uses: bahmutov/npm-install@v1.7.10 + - name: Restore cached node_modules + uses: actions/cache@v4 + with: + path: '**/node_modules' + key: node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + + - name: Install deps + run: yarn install --frozen-lockfile - name: Restore next build - uses: actions/cache@v3 + uses: actions/cache@v4 id: restore-build-cache env: cache-name: cache-next-build diff --git a/.github/workflows/site_lint.yml b/.github/workflows/site_lint.yml index 34ca6d7b8..2b01231eb 100644 --- a/.github/workflows/site_lint.yml +++ b/.github/workflows/site_lint.yml @@ -14,14 +14,22 @@ jobs: name: Lint on node 20.x and ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Use Node.js 20.x - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 20.x + cache: yarn + cache-dependency-path: yarn.lock - - name: Install deps and build (with cache) - uses: bahmutov/npm-install@v1.8.32 + - name: Restore cached node_modules + uses: actions/cache@v4 + with: + path: '**/node_modules' + key: node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + + - name: Install deps + run: yarn install --frozen-lockfile - name: Lint codebase run: yarn ci-check From 4bc1d1f887e2069378796f66f883fa5aad690405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Sun, 29 Dec 2024 15:55:46 +0900 Subject: [PATCH 0435/1164] chore: bump lint-staged from 12.3.1 to 15.3.0 --- package.json | 2 +- yarn.lock | 471 +++++++++++++++++++++++++++------------------------ 2 files changed, 248 insertions(+), 225 deletions(-) diff --git a/package.json b/package.json index 2ac0fbf2b..dcaf8e055 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "gray-matter": "^4.0.2", "husky": "^7.0.4", "is-ci": "^3.0.1", - "lint-staged": ">=10", + "lint-staged": "^15.3.0", "mdast-util-to-string": "^1.1.0", "metro-cache": "0.72.2", "mocha": "^10.6.0", diff --git a/yarn.lock b/yarn.lock index 355c72f6e..50e3ad3b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1708,14 +1708,6 @@ acorn@^8.0.4: resolved "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz" integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== -aggregate-error@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz" - integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - ajv@^6.10.0, ajv@^6.12.4: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" @@ -1772,12 +1764,12 @@ ansi-colors@^4.1.3: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== -ansi-escapes@^4.3.0: - version "4.3.2" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== +ansi-escapes@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-7.0.0.tgz#00fc19f491bbb18e1d481b97868204f92109bfe7" + integrity sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw== dependencies: - type-fest "^0.21.3" + environment "^1.0.0" ansi-regex@^5.0.1: version "5.0.1" @@ -1808,6 +1800,11 @@ ansi-styles@^6.0.0: resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.0.tgz" integrity sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ== +ansi-styles@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + any-promise@^1.0.0: version "1.3.0" resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz" @@ -2099,6 +2096,13 @@ braces@^3.0.1, braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + browser-stdout@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" @@ -2221,6 +2225,11 @@ chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@~5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.4.1.tgz#1b48bf0963ec158dce2aacf69c093ae2dd2092d8" + integrity sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w== + character-entities-html4@^1.0.0: version "1.1.4" resolved "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz" @@ -2330,33 +2339,20 @@ clean-set@^1.1.2: resolved "https://registry.npmjs.org/clean-set/-/clean-set-1.1.2.tgz" integrity sha512-cA8uCj0qSoG9e0kevyOWXwPaELRPVg5Pxp6WskLMwerx257Zfnh8Nl0JBH59d7wQzij2CK7qEfJQK3RjuKKIug== -clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== - -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - -cli-truncate@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz" - integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== +cli-cursor@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-5.0.0.tgz#24a4831ecf5a6b01ddeb32fb71a4b2088b0dce38" + integrity sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw== dependencies: - slice-ansi "^3.0.0" - string-width "^4.2.0" + restore-cursor "^5.0.0" -cli-truncate@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz" - integrity sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA== +cli-truncate@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-4.0.0.tgz#6cc28a2924fee9e25ce91e973db56c7066e6172a" + integrity sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA== dependencies: slice-ansi "^5.0.0" - string-width "^5.0.0" + string-width "^7.0.0" client-only@0.0.1: version "0.0.1" @@ -2401,10 +2397,10 @@ color-name@~1.1.4: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -colorette@^2.0.16: - version "2.0.16" - resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz" - integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g== +colorette@^2.0.20: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== combined-stream@^1.0.8: version "1.0.8" @@ -2438,10 +2434,10 @@ commander@^7.2.0: resolved "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== -commander@^8.3.0: - version "8.3.0" - resolved "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz" - integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== +commander@~12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== concat-map@0.0.1: version "0.0.1" @@ -2646,7 +2642,7 @@ debug@^4.0.0, debug@^4.3.4: dependencies: ms "2.1.2" -debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.3: +debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: version "4.3.3" resolved "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz" integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== @@ -2660,6 +2656,13 @@ debug@^4.3.5: dependencies: ms "2.1.2" +debug@~4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + decamelize@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" @@ -2816,11 +2819,6 @@ duplexer@^0.1.2: resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== -eastasianwidth@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz" - integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== - editorconfig-checker@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/editorconfig-checker/-/editorconfig-checker-6.0.0.tgz#f9bdcbd13411aab9a208030f88051add97bff2f6" @@ -2841,6 +2839,11 @@ electron-to-chromium@^1.4.202: resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.241.tgz" integrity sha512-e7Wsh4ilaioBZ5bMm6+F4V5c11dh56/5Jwz7Hl5Tu1J7cnB+Pqx5qIF2iC7HPpfyQMqGSvvLP5bBAIDd2gAtGw== +emoji-regex@^10.3.0: + version "10.4.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.4.0.tgz#03553afea80b3975749cfcb36f776ca268e413d4" + integrity sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" @@ -2876,6 +2879,11 @@ entities@^4.2.0, entities@^4.5.0: resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== +environment@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/environment/-/environment-1.1.0.tgz#8e86c66b180f363c7ab311787e0259665f45a9f1" + integrity sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q== + error-ex@^1.2.0, error-ex@^1.3.1: version "1.3.2" resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" @@ -3351,20 +3359,25 @@ etag@~1.8.1: resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== -execa@^5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== +eventemitter3@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + +execa@~8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c" + integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg== dependencies: cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" + get-stream "^8.0.1" + human-signals "^5.0.0" + is-stream "^3.0.0" merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^4.1.0" + strip-final-newline "^3.0.0" express@^4.17.1: version "4.18.1" @@ -3506,6 +3519,13 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + finalhandler@1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz" @@ -3688,6 +3708,11 @@ get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-east-asian-width@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz#21b4071ee58ed04ee0db653371b55b4299875389" + integrity sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ== + get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz" @@ -3718,10 +3743,10 @@ get-stdin@^5.0.1: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" integrity sha512-jZV7n6jGE3Gt7fgSTJoz91Ak5MuTLwMwkoYdjxuJ/AmjIsE1UC03y/IWkZCQGEvVNS9qoRNwy5BCqxImv0FVeA== -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +get-stream@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" + integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== get-symbol-description@^1.0.0: version "1.0.0" @@ -4051,10 +4076,10 @@ http-errors@2.0.0: statuses "2.0.1" toidentifier "1.0.1" -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== +human-signals@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" + integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== husky@^7.0.4: version "7.0.4" @@ -4103,11 +4128,6 @@ imurmurhash@^0.1.4: resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - indexes-of@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz" @@ -4334,6 +4354,13 @@ is-fullwidth-code-point@^4.0.0: resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz" integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== +is-fullwidth-code-point@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz#9609efced7c2f97da7b60145ef481c787c7ba704" + integrity sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA== + dependencies: + get-east-asian-width "^1.0.0" + is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" @@ -4410,10 +4437,10 @@ is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: dependencies: call-bind "^1.0.7" -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== is-string@^1.0.5, is-string@^1.0.7: version "1.0.7" @@ -4613,53 +4640,48 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -lilconfig@2.0.4: - version "2.0.4" - resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz" - integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA== - lilconfig@^2.0.5, lilconfig@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz" integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== +lilconfig@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.3.tgz#a1bcfd6257f9585bf5ae14ceeebb7b559025e4c4" + integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw== + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -lint-staged@>=10: - version "12.3.1" - resolved "https://registry.npmjs.org/lint-staged/-/lint-staged-12.3.1.tgz" - integrity sha512-Ocht/eT+4/siWOZDJpNUKcKX2UeWW/pDbohJ4gRsrafAjBi79JK8kiNVk2ciIVNKdw0Q4ABptl2nr6uQAlRImw== - dependencies: - cli-truncate "^3.1.0" - colorette "^2.0.16" - commander "^8.3.0" - debug "^4.3.3" - execa "^5.1.1" - lilconfig "2.0.4" - listr2 "^4.0.1" - micromatch "^4.0.4" - normalize-path "^3.0.0" - object-inspect "^1.12.0" - string-argv "^0.3.1" - supports-color "^9.2.1" - yaml "^1.10.2" - -listr2@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/listr2/-/listr2-4.0.1.tgz" - integrity sha512-D65Nl+zyYHL2jQBGmxtH/pU8koPZo5C8iCNE8EoB04RwPgQG1wuaKwVbeZv9LJpiH4Nxs0FCp+nNcG8OqpniiA== - dependencies: - cli-truncate "^2.1.0" - colorette "^2.0.16" - log-update "^4.0.0" - p-map "^4.0.0" - rfdc "^1.3.0" - rxjs "^7.5.2" - through "^2.3.8" - wrap-ansi "^7.0.0" +lint-staged@^15.3.0: + version "15.3.0" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.3.0.tgz#32a0b3f2f2b8825950bd3b9fb093e045353bdfa3" + integrity sha512-vHFahytLoF2enJklgtOtCtIjZrKD/LoxlaUusd5nh7dWv/dkKQJY74ndFSzxCdv7g0ueGg1ORgTSt4Y9LPZn9A== + dependencies: + chalk "~5.4.1" + commander "~12.1.0" + debug "~4.4.0" + execa "~8.0.1" + lilconfig "~3.1.3" + listr2 "~8.2.5" + micromatch "~4.0.8" + pidtree "~0.6.0" + string-argv "~0.3.2" + yaml "~2.6.1" + +listr2@~8.2.5: + version "8.2.5" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-8.2.5.tgz#5c9db996e1afeb05db0448196d3d5f64fec2593d" + integrity sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ== + dependencies: + cli-truncate "^4.0.0" + colorette "^2.0.20" + eventemitter3 "^5.0.1" + log-update "^6.1.0" + rfdc "^1.4.1" + wrap-ansi "^9.0.0" load-json-file@^1.0.0: version "1.1.0" @@ -4725,15 +4747,16 @@ log-symbols@^4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" -log-update@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz" - integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== +log-update@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-6.1.0.tgz#1a04ff38166f94647ae1af562f4bd6a15b1b7cd4" + integrity sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w== dependencies: - ansi-escapes "^4.3.0" - cli-cursor "^3.1.0" - slice-ansi "^4.0.0" - wrap-ansi "^6.2.0" + ansi-escapes "^7.0.0" + cli-cursor "^5.0.0" + slice-ansi "^7.1.0" + strip-ansi "^7.1.0" + wrap-ansi "^9.0.0" longest-streak@^2.0.0, longest-streak@^2.0.1: version "2.0.4" @@ -5620,6 +5643,14 @@ micromatch@^4.0.5: braces "^3.0.2" picomatch "^2.3.1" +micromatch@~4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + mime-db@1.52.0, mime-db@^1.52.0: version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" @@ -5649,10 +5680,15 @@ mime@1.6.0: resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + +mimic-function@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/mimic-function/-/mimic-function-5.0.1.tgz#acbe2b3349f99b9deaca7fb70e48b83e94e67076" + integrity sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA== minimatch@^3.0.4: version "3.0.4" @@ -5871,12 +5907,12 @@ npm-run-all@^4.1.5: shell-quote "^1.6.1" string.prototype.padend "^3.0.0" -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== +npm-run-path@^5.1.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.3.0.tgz#e23353d0ebb9317f174e93417e4a4d82d0249e9f" + integrity sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ== dependencies: - path-key "^3.0.0" + path-key "^4.0.0" nth-check@^2.0.1: version "2.1.1" @@ -5900,7 +5936,7 @@ object-hash@^3.0.0: resolved "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz" integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== -object-inspect@^1.11.0, object-inspect@^1.12.0, object-inspect@^1.9.0: +object-inspect@^1.11.0, object-inspect@^1.9.0: version "1.12.0" resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz" integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== @@ -5994,12 +6030,19 @@ once@^1.3.0: dependencies: wrappy "1" -onetime@^5.1.0, onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== dependencies: - mimic-fn "^2.1.0" + mimic-fn "^4.0.0" + +onetime@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-7.0.0.tgz#9f16c92d8c9ef5120e3acd9dd9957cceecc1ab60" + integrity sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ== + dependencies: + mimic-function "^5.0.0" open@^7.4.2: version "7.4.2" @@ -6081,13 +6124,6 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" -p-map@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz" - integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== - dependencies: - aggregate-error "^3.0.0" - p-try@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz" @@ -6221,11 +6257,16 @@ path-key@^2.0.1: resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz" integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= -path-key@^3.0.0, path-key@^3.1.0: +path-key@^3.1.0: version "3.1.1" resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + path-parse@^1.0.6, path-parse@^1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" @@ -6290,6 +6331,11 @@ pidtree@^0.3.0: resolved "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz" integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== +pidtree@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" + integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== + pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" @@ -7173,13 +7219,13 @@ resolve@^2.0.0-next.3: is-core-module "^2.2.0" path-parse "^1.0.6" -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== +restore-cursor@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-5.1.0.tgz#0766d95699efacb14150993f55baf0953ea1ebe7" + integrity sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA== dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" + onetime "^7.0.0" + signal-exit "^4.1.0" retext-latin@^2.0.0: version "2.0.4" @@ -7218,10 +7264,10 @@ reusify@^1.0.4: resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rfdc@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz" - integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== +rfdc@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" + integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== rimraf@2.6.3: version "2.6.3" @@ -7259,13 +7305,6 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rxjs@^7.5.2: - version "7.5.2" - resolved "https://registry.npmjs.org/rxjs/-/rxjs-7.5.2.tgz" - integrity sha512-PwDt186XaL3QN5qXj/H9DGyHhP3/RYYgZZwqBv9Tv8rsAaiwFH1IsJJlcgD37J7UW5a6O67qX0KWKS3/pu0m4w== - dependencies: - tslib "^2.1.0" - sade@^1.7.3: version "1.8.1" resolved "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz" @@ -7447,10 +7486,10 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" -signal-exit@^3.0.2, signal-exit@^3.0.3: - version "3.0.6" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz" - integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== +signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== sirv@^1.0.7: version "1.0.19" @@ -7471,15 +7510,6 @@ slash@^3.0.0: resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slice-ansi@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz" - integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - slice-ansi@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz" @@ -7497,6 +7527,14 @@ slice-ansi@^5.0.0: ansi-styles "^6.0.0" is-fullwidth-code-point "^4.0.0" +slice-ansi@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-7.1.0.tgz#cd6b4655e298a8d1bdeb04250a433094b347b9a9" + integrity sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg== + dependencies: + ansi-styles "^6.2.1" + is-fullwidth-code-point "^5.0.0" + source-map-js@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz" @@ -7588,10 +7626,10 @@ strict-event-emitter@^0.4.3: resolved "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.4.6.tgz" integrity sha512-12KWeb+wixJohmnwNFerbyiBrAlq5qJLwIt38etRtKtmmHyDSoGlIqFE9wx+4IwG0aDjI7GV8tc8ZccjWZZtTg== -string-argv@^0.3.1: - version "0.3.1" - resolved "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz" - integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== +string-argv@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" + integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" @@ -7602,14 +7640,14 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^5.0.0: - version "5.1.0" - resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.0.tgz" - integrity sha512-7x54QnN21P+XL/v8SuNKvfgsUre6PXpN7mc77N3HlZv+f1SBRGmjxtOud2Z6FZ8DmdkD/IdjCaf9XXbnqmTZGQ== +string-width@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-7.2.0.tgz#b5bb8e2165ce275d4d43476dd2700ad9091db6dc" + integrity sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ== dependencies: - eastasianwidth "^0.2.0" - emoji-regex "^9.2.2" - strip-ansi "^7.0.1" + emoji-regex "^10.3.0" + get-east-asian-width "^1.0.0" + strip-ansi "^7.1.0" string.prototype.matchall@^4.0.6: version "4.0.6" @@ -7702,10 +7740,10 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" -strip-ansi@^7.0.1: - version "7.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz" - integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw== +strip-ansi@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== dependencies: ansi-regex "^6.0.1" @@ -7726,10 +7764,10 @@ strip-bom@^3.0.0: resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" @@ -7796,11 +7834,6 @@ supports-color@^8.1.1: dependencies: has-flag "^4.0.0" -supports-color@^9.2.1: - version "9.2.1" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-9.2.1.tgz" - integrity sha512-Obv7ycoCTG51N7y175StI9BlAXrmgZrFhZOb0/PyjHBher/NmsdBgbbQ1Inhq+gIhz6+7Gb+jWF2Vqi7Mf1xnQ== - supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" @@ -7932,11 +7965,6 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" -through@^2.3.8: - version "2.3.8" - resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - tiny-warning@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz" @@ -8064,11 +8092,6 @@ type-fest@^0.20.2: resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - type-is@~1.6.18: version "1.6.18" resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" @@ -8568,15 +8591,6 @@ workerpool@^6.5.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== -wrap-ansi@^6.2.0: - version "6.2.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz" - integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" @@ -8586,6 +8600,15 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-9.0.0.tgz#1a3dc8b70d85eeb8398ddfb1e4a02cd186e58b3e" + integrity sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q== + dependencies: + ansi-styles "^6.2.1" + string-width "^7.0.0" + strip-ansi "^7.1.0" + wrappy@1: version "1.0.2" resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" @@ -8623,16 +8646,16 @@ yallist@^4.0.0: resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@^1.10.2: - version "1.10.2" - resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== - yaml@^2.1.1: version "2.3.1" resolved "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz" integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ== +yaml@~2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.6.1.tgz#42f2b1ba89203f374609572d5349fb8686500773" + integrity sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg== + yargs-parser@^20.2.2, yargs-parser@^20.2.9: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" From 02d5a920b154d912bd8470f4522fb3724e26f871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Sun, 29 Dec 2024 20:37:48 +0900 Subject: [PATCH 0436/1164] docs: resolve conflicts in `sync-84f29eb2` --- src/content/community/acknowledgements.md | 6 +----- src/content/reference/react/useReducer.md | 12 +++--------- .../rules/components-and-hooks-must-be-pure.md | 6 +----- 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/src/content/community/acknowledgements.md b/src/content/community/acknowledgements.md index 02eced6a1..5726771b3 100644 --- a/src/content/community/acknowledgements.md +++ b/src/content/community/acknowledgements.md @@ -4,11 +4,7 @@ title: 감사의 말 <Intro> -<<<<<<< HEAD -React는 원래 [Jordan Walke](https://github.com/jordwalke)에 의해 만들어졌습니다. 오늘날 React에는 [작업을 전담하는 전임 팀](/community/team)과 천여 명이 넘는 [오픈 소스 기여자들](https://github.com/facebook/react/blob/main/AUTHORS)이 있습니다. -======= -React was originally created by [Jordan Walke.](https://github.com/jordwalke) Today, React has a [dedicated full-time team working on it](/community/team), as well as over a thousand [open source contributors.](https://github.com/facebook/react/graphs/contributors) ->>>>>>> 84f29eb20af17e9c154b9ad71c21af4c9171e4a2 +React는 원래 [Jordan Walke](https://github.com/jordwalke)에 의해 만들어졌습니다. 오늘날 React에는 [작업을 전담하는 전임 팀](/community/team)과 천여 명이 넘는 [오픈 소스 기여자들](https://github.com/facebook/react/graphs/contributors)이 있습니다. </Intro> diff --git a/src/content/reference/react/useReducer.md b/src/content/reference/react/useReducer.md index f3e62351f..5e169c23e 100644 --- a/src/content/reference/react/useReducer.md +++ b/src/content/reference/react/useReducer.md @@ -51,15 +51,9 @@ function MyComponent() { #### 주의 사항 {/*caveats*/} -<<<<<<< HEAD -* `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 함수가 순수 함수라면(그래야만 하듯이) 로직에 어떠한 영향도 미치지 않습니다. 호출 중 하나의 결과는 무시합니다. -======= -* `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. ->>>>>>> 84f29eb20af17e9c154b9ad71c21af4c9171e4a2 +* `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` 함수를 두번 호출합니다. 개발 환경에서만 한정된 동작이며, 배포<sup>Production</sup> 환경에는 영향을 미치지 않습니다. Reducer와 `init` 함수가 순수 함수라면(그래야만 하듯이) 로직에 어떠한 영향도 미치지 않습니다. 호출 중 하나의 결과는 무시합니다. --- diff --git a/src/content/reference/rules/components-and-hooks-must-be-pure.md b/src/content/reference/rules/components-and-hooks-must-be-pure.md index 072bfb6b6..cc1bf4fe7 100644 --- a/src/content/reference/rules/components-and-hooks-must-be-pure.md +++ b/src/content/reference/rules/components-and-hooks-must-be-pure.md @@ -194,11 +194,7 @@ function ProductDetailPage({ product }) { } ``` -<<<<<<< HEAD -`window.title`을 렌더링 외부에서 업데이트하는 한 가지 방법은 [컴포넌트를 `window`와 동기화하는 것](/learn/synchronizing-with-effects)입니다. -======= -One way to achieve the desired result of updating `document.title` outside of render is to [synchronize the component with `document`](/learn/synchronizing-with-effects). ->>>>>>> 84f29eb20af17e9c154b9ad71c21af4c9171e4a2 +원하는 결과를 얻기 위해 렌더링 외부에서 `document.title`을 업데이트하는 한 가지 방법은 [컴포넌트를 `document`와 동기화하는 것](/learn/synchronizing-with-effects)입니다. 컴포넌트를 여러 번 호출해도 안전하고 다른 컴포넌트의 렌더링에 영향을 주지 않는 한, React는 엄격한 함수형 프로그래밍의 의미에서 100% 순수하지 않아도 상관하지 않습니다. 더 중요한 것은 [컴포넌트가 반드시 멱등해야 한다는 것](/reference/rules/components-and-hooks-must-be-pure)입니다. From cbafdc4b1ca79f2afe62e625a9c4d0cecb0069d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Sun, 29 Dec 2024 20:47:26 +0900 Subject: [PATCH 0437/1164] =?UTF-8?q?docs:=20rename=20`react=20=ED=95=99?= =?UTF-8?q?=EC=8A=B5`=20to=20`react=20=ED=95=99=EC=8A=B5=ED=95=98=EA=B8=B0?= =?UTF-8?q?`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTING.md | 4 ++-- src/components/Layout/HomeContent.js | 2 +- src/sidebarLearn.json | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 327466732..8b45bbd42 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,9 +16,9 @@ React 문서 기여에 관심을 가져주셔서 감사합니다! 이 문서는 다양한 학습 스타일과 사용 사례를 고려하여 분할되어 있습니다. 본문을 수정할 때는 주변 글의 톤<sup>Tone</sup>과 스타일<sup>Style</sup>에 맞게 작성하도록 주의하세요. 새로운 글을 작성할 때는 같은 섹션에 있는 다른 글들과 톤을 맞추도록 하세요. 각 섹션의 의도와 동기는 아래에서 확인할 수 있습니다. -**[React 학습](https://ko.react.dev/learn)** 섹션은 기초 개념을 단계별로 소개하기 위해 만들어졌습니다. 여기서 제공되는 글들은 이전에 설명된 지식을 바탕으로 하므로, 글 간 앞뒤 개념이 중복되거나 꼬이지 않도록 주의하세요. 독자는 첫 번째 글부터 마지막 글까지 순서대로 읽으며 개념을 익힐 수 있어야 하며, 추가 설명을 위해 미리 앞선 개념들을 살펴보지 않도록 해야 합니다. 이런 이유로 상태<sup>State</sup>는 이벤트<sup>Event</sup>보다 먼저 설명되고, 'React로 사고하기' 파트에서 `ref`를 사용하지 않는 등 특정 순서가 정해져 있습니다. 동시에 'React 학습'은 React 개념에 대한 참고 자료 역할을 하므로, 개념들에 대한 정의와 상호 관계를 엄격하게 다루어야 합니다. +**[React 학습하기](https://ko.react.dev/learn)** 섹션은 기초 개념을 단계별로 소개하기 위해 만들어졌습니다. 여기서 제공되는 글들은 이전에 설명된 지식을 바탕으로 하므로, 글 간 앞뒤 개념이 중복되거나 꼬이지 않도록 주의하세요. 독자는 첫 번째 글부터 마지막 글까지 순서대로 읽으며 개념을 익힐 수 있어야 하며, 추가 설명을 위해 미리 앞선 개념들을 살펴보지 않도록 해야 합니다. 이런 이유로 상태<sup>State</sup>는 이벤트<sup>Event</sup>보다 먼저 설명되고, 'React로 사고하기' 파트에서 `ref`를 사용하지 않는 등 특정 순서가 정해져 있습니다. 동시에 'React 학습하기'는 React 개념에 대한 참고 자료 역할을 하므로, 개념들에 대한 정의와 상호 관계를 엄격하게 다루어야 합니다. -**[API 레퍼런스](https://ko.react.dev/reference/react)** 섹션은 개념이 아닌 API별로 정리되어 있으며, 가능한 한 모든 경우를 포함하는 것을 목표로 합니다. 'React 학습'에서 간단히 다뤘거나 생략한 예외 사항<sup>Edge Cases</sup> 혹은 권장 사항<sup>Recommendations</sup>은 해당 API의 레퍼런스 문서에 추가로 언급해야 합니다. +**[API 레퍼런스](https://ko.react.dev/reference/react)** 섹션은 개념이 아닌 API별로 정리되어 있으며, 가능한 한 모든 경우를 포함하는 것을 목표로 합니다. 'React 학습하기'에서 간단히 다뤘거나 생략한 예외 사항<sup>Edge Cases</sup> 혹은 권장 사항<sup>Recommendations</sup>은 해당 API의 레퍼런스 문서에 추가로 언급해야 합니다. **스스로 작성한 지침<sup>Instructions</sup>을 실천해 보세요.** diff --git a/src/components/Layout/HomeContent.js b/src/components/Layout/HomeContent.js index 6a7f46a70..5a5097321 100644 --- a/src/components/Layout/HomeContent.js +++ b/src/components/Layout/HomeContent.js @@ -174,7 +174,7 @@ export function HomeContent() { <Br /> 사용자 인터페이스 만들기 </Header> <Para> - React를 사용하면 컴포넌트라고 불리는 조각들을 사용하여 사용자 + React를 사용하면 컴포넌트라 불리는 조각들을 사용하여 사용자 인터페이스를 만들 수 있습니다. <Code>Thumbnail</Code>,{' '} <Code>LikeButton</Code>, 그리고 <Code>Video</Code> 같은 컴포넌트를 만들 수 있습니다. 그런 다음 전체 화면, 페이지 및 앱에서 이들을 diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index b1eaecf61..f318d9ab2 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -1,5 +1,5 @@ { - "title": "React 학습", + "title": "React 학습하기", "path": "/learn", "routes": [ { @@ -53,7 +53,7 @@ }, { "hasSectionHeader": true, - "sectionHeader": "React 학습" + "sectionHeader": "React 학습하기" }, { "title": "UI 표현하기", From e0f46187cd6e12e29cc34edfcb3df936604e5b4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Sun, 29 Dec 2024 21:40:53 +0900 Subject: [PATCH 0438/1164] docs: update Korean terminology for API reference and installation sections --- CONTRIBUTING.md | 2 +- src/components/Layout/Footer.tsx | 6 +- src/components/Layout/HomeContent.js | 95 ++++++++++--------- src/components/Layout/TopNav/TopNav.tsx | 2 +- .../blog/2023/03/16/introducing-react-dev.md | 8 +- src/content/learn/index.md | 2 +- src/content/learn/tutorial-tic-tac-toe.md | 2 +- src/sidebarHome.json | 2 +- src/sidebarLearn.json | 2 +- src/sidebarReference.json | 2 +- 10 files changed, 64 insertions(+), 59 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8b45bbd42..96229a467 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,7 +18,7 @@ React 문서 기여에 관심을 가져주셔서 감사합니다! **[React 학습하기](https://ko.react.dev/learn)** 섹션은 기초 개념을 단계별로 소개하기 위해 만들어졌습니다. 여기서 제공되는 글들은 이전에 설명된 지식을 바탕으로 하므로, 글 간 앞뒤 개념이 중복되거나 꼬이지 않도록 주의하세요. 독자는 첫 번째 글부터 마지막 글까지 순서대로 읽으며 개념을 익힐 수 있어야 하며, 추가 설명을 위해 미리 앞선 개념들을 살펴보지 않도록 해야 합니다. 이런 이유로 상태<sup>State</sup>는 이벤트<sup>Event</sup>보다 먼저 설명되고, 'React로 사고하기' 파트에서 `ref`를 사용하지 않는 등 특정 순서가 정해져 있습니다. 동시에 'React 학습하기'는 React 개념에 대한 참고 자료 역할을 하므로, 개념들에 대한 정의와 상호 관계를 엄격하게 다루어야 합니다. -**[API 레퍼런스](https://ko.react.dev/reference/react)** 섹션은 개념이 아닌 API별로 정리되어 있으며, 가능한 한 모든 경우를 포함하는 것을 목표로 합니다. 'React 학습하기'에서 간단히 다뤘거나 생략한 예외 사항<sup>Edge Cases</sup> 혹은 권장 사항<sup>Recommendations</sup>은 해당 API의 레퍼런스 문서에 추가로 언급해야 합니다. +**[API 참고서](https://ko.react.dev/reference/react)** 섹션은 개념이 아닌 API별로 정리되어 있으며, 가능한 한 모든 경우를 포함하는 것을 목표로 합니다. 'React 학습하기'에서 간단히 다뤘거나 생략한 예외 사항<sup>Edge Cases</sup> 혹은 권장 사항<sup>Recommendations</sup>은 해당 API의 레퍼런스 문서에 추가로 언급해야 합니다. **스스로 작성한 지침<sup>Instructions</sup>을 실천해 보세요.** diff --git a/src/components/Layout/Footer.tsx b/src/components/Layout/Footer.tsx index f912ba2ae..4b2dedd48 100644 --- a/src/components/Layout/Footer.tsx +++ b/src/components/Layout/Footer.tsx @@ -336,7 +336,7 @@ export function Footer() { 커뮤니티 </FooterLink> <FooterLink href="https://github.com/facebook/react/blob/main/CODE_OF_CONDUCT.md"> - Code of Conduct + 행동 강령 </FooterLink> <FooterLink href="/community/team">팀 소개</FooterLink> <FooterLink href="/community/docs-contributors"> @@ -347,7 +347,9 @@ export function Footer() { <div className="flex flex-col"> <FooterLink isHeader={true}>더 보기</FooterLink> <FooterLink href="/blog">블로그</FooterLink> - <FooterLink href="https://reactnative.dev/">React Native</FooterLink> + <FooterLink href="https://reactnative.dev/"> + React 네이티브 + </FooterLink> <FooterLink href="https://opensource.facebook.com/legal/privacy"> 개인 정보 보호 </FooterLink> diff --git a/src/components/Layout/HomeContent.js b/src/components/Layout/HomeContent.js index 5a5097321..7c7aa4c3f 100644 --- a/src/components/Layout/HomeContent.js +++ b/src/components/Layout/HomeContent.js @@ -162,7 +162,7 @@ export function HomeContent() { size="lg" className="w-full sm:w-auto justify-center" label="API Reference"> - API 레퍼런스 + API 참고서 </ButtonLink> </div> </div> @@ -177,8 +177,8 @@ export function HomeContent() { React를 사용하면 컴포넌트라 불리는 조각들을 사용하여 사용자 인터페이스를 만들 수 있습니다. <Code>Thumbnail</Code>,{' '} <Code>LikeButton</Code>, 그리고 <Code>Video</Code> 같은 컴포넌트를 - 만들 수 있습니다. 그런 다음 전체 화면, 페이지 및 앱에서 이들을 - 결합할 수 있습니다. + 만들어 보세요. 그런 다음 전체 화면, 페이지 및 앱에서 이들을 결합할 + 수 있습니다. </Para> </Center> <FullBleed> @@ -200,10 +200,10 @@ export function HomeContent() { <Br /> 컴포넌트 작성하기 </Header> <Para> - React 컴포넌트는 JavaScript 함수입니다. 조건부로 내용을 표시하려면{' '} - <Code>if</Code> 문을 사용할 수 있습니다. 목록을 표시하려면 배열에{' '} - <Code>map()</Code>을 사용할 수 있습니다. React를 배우는 것은 - 프로그래밍을 배우는 것입니다. + React 컴포넌트는 자바스크립트 함수입니다. 조건부로 내용을 + 표시하려면 <Code>if</Code> 문을 사용할 수 있습니다. 목록을 + 표시하려면 배열에 <Code>map()</Code>을 사용할 수 있습니다. React를 + 배우는 것은 프로그래밍을 배우는 것입니다. </Para> </Center> <FullBleed> @@ -211,9 +211,9 @@ export function HomeContent() { </FullBleed> <Center> <Para> - 이 마크업 구문을 JSX 라고 부릅니다. 이것은 React에 의해서 대중화된 - JavaScript 구문의 확장입니다. JSX 마크업을 관련된 렌더링 로직과 - 가까이 두면, React 컴포넌트를 쉽게 만들고 유지하고 삭제할 수 + 이 마크업 구문을 JSX라 부릅니다. 이것은 React에 의해서 대중화된 + 자바스크립트 구문의 확장입니다. JSX 마크업을 관련된 렌더링 로직과 + 가까이 두면, React 컴포넌트를 쉽게 만들고 관리하고 삭제할 수 있습니다. </Para> </Center> @@ -238,7 +238,7 @@ export function HomeContent() { <Center> <Para> 전체 페이지를 React로 빌드할 필요는 없습니다. React를 기존 HTML - 페이지에 추가하고, 어디에서나 상호작용하는 React 컴포넌트를 + 페이지에 추가하고, 페이지 어디에서나 상호작용하는 React 컴포넌트를 렌더링할 수 있습니다. </Para> <div className="flex justify-start w-full lg:justify-center"> @@ -255,13 +255,14 @@ export function HomeContent() { <Section background="right-card"> <Center> <Header> - 프레임워크를 통해서 + 프레임워크를 통해 <Br /> 풀스택으로 만들기 </Header> <Para> - React는 라이브러리입니다. 컴포넌트를 함께 묶을 수 있지만, 라우팅과 - 데이터를 가져오는 방법을 규정하지는 않습니다. React로 앱을 - 만들려면, <Link href="https://nextjs.org">Next.js</Link> 또는{' '} + React는 라이브러리입니다. 컴포넌트를 조합할 수 있도록 도와주지만, + 라우팅이나 데이터를 가져오는 방법을 규정하지는 않습니다. React로 + 완전한 앱을 만들려면,{' '} + <Link href="https://nextjs.org">Next.js</Link> 또는{' '} <Link href="https://remix.run">Remix</Link> 같은 풀스택 React 프레임워크를 추천합니다. </Para> @@ -271,10 +272,11 @@ export function HomeContent() { </FullBleed> <Center> <Para> - React는 아키텍처이기도 합니다. 이를 구현하는 프레임워크를 사용하면 - 서버에서 실행되는 비동기 컴포넌트에서 또는 빌드 도중에 데이터를 - 가져올 수 있습니다. 파일이나 데이터베이스에서 데이터를 읽고, 이를 - 상호작용하는 컴포넌트로 전달할 수 있습니다. + React는 아키텍처이기도 합니다. 이를 구현하는 프레임워크는 서버에서 + 실행되는 비동기 컴포넌트 혹은 빌드 중에 실행되는 비동기 + 컴포넌트에서 데이터를 가져올 수 있도록 합니다. 파일이나 + 데이터베이스에서 데이터를 읽고, 이를 상호작용하는 컴포넌트에 + 전달할 수 있습니다. </Para> <div className="flex justify-start w-full lg:justify-center"> <CTA @@ -293,7 +295,7 @@ export function HomeContent() { <Para> 사람들은 다양한 이유로 웹과 네이티브 앱을 좋아합니다. React는 동일한 기술을 사용하여 웹 앱과 네이티브 앱을 모두 만들 수 - 있습니다. 각 플랫폼에 강점을 활용하여 모든 플랫폼에서 적합한 + 있습니다. 각 플랫폼의 장점을 활용하여 모든 플랫폼에서 적합한 인터페이스를 구현할 수 있습니다. </Para> </div> @@ -311,12 +313,12 @@ export function HomeContent() { 웹에 충실하기 </h4> <p className="lg:text-xl leading-normal text-secondary"> - 사람들은 웹이 빠르게 로드되길 기대합니다. 서버에서 + 사람들은 웹 앱이 빠르게 로드되길 기대합니다. 서버에서 React를 사용하면 데이터를 가져오는 동안 HTML을 - 스트리밍하여 JavaScript 코드가 로드되기 전에 남은 내용을 - 점진적으로 채울 수 있습니다. 클라이언트에서 React는 표준 - web API를 사용하여 렌더링 중에도 UI를 반응적으로 유지할 - 수 있습니다. + 스트리밍하여 자바스크립트 코드가 로드되기 전에 남은 + 내용을 점진적으로 채울 수 있습니다. 클라이언트에서 + React는 표준 웹 API를 사용하여 렌더링 중에도 UI를 + 반응하도록 유지할 수 있습니다. </p> </div> </div> @@ -394,21 +396,22 @@ export function HomeContent() { </div> <div className="flex flex-col items-start justify-center pt-0 gap-3 px-2.5 lg:pt-8 lg:px-8"> <h4 className="leading-tight text-primary dark:text-primary-dark font-semibold text-3xl lg:text-4xl"> - 네이티브에서 사용하기 + 진정한 네이티브에서 사용하기 </h4> <p className="h-full lg:text-xl text-secondary dark:text-secondary-dark leading-normal"> - 사람들은 네이티브 앱이 플랫폼과 같은 모양처럼 - 느껴지기를 원합니다.{' '} + 사람들은 네이티브<sup>Native</sup> 앱이 해당 플랫폼의 + 모습과 느낌을 갖기를 기대합니다.{' '} <Link href="https://reactnative.dev"> React Native </Link> 와{' '} <Link href="https://github.com/expo/expo">Expo</Link> - 를 사용하면 React를 통하여 Android, iOS 등을 위한 앱을 - 빌드할 수 있습니다. UI들이 native이기 때문에 진짜 - native처럼 보입니다. 이것은 web view가 아닙니다. React - 컴포넌트들은 실제 Android, iOS 플랫폼에서 제공하는 - view를 렌더링합니다. + 를 사용하면 React를 통해 Android, iOS 등을 위한 앱을 + 빌드할 수 있습니다. UI가 진정한 네이티브이기 때문에 + 네이티브처럼 보이고 느껴집니다. 이것은 웹 뷰 + <sup>Web View</sup>가 아닙니다. React 컴포넌트들은 + 실제 Android, iOS 플랫폼에서 제공하는 뷰 + <sup>View</sup>를 렌더링합니다. </p> </div> </div> @@ -441,9 +444,9 @@ export function HomeContent() { <Br breakPointPrefix="xl" /> 업그레이드 하기 </Header> <Para> - React는 변화에 신중하게 접근합니다. 모든 React 커밋은 10억 명 - 이상의 사용자가 있는 비즈니스에 크리티컬한 영역에서 테스트 - 됩니다. Meta에서는 10만 개 이상의 React 컴포넌트가 모든 + React는 변화에 신중하게 접근합니다. 모든 React 커밋은 10억명 + 이상의 사용자가 있는 비즈니스의 크리티컬한 영역에서 테스트를 + 진행합니다. Meta에서는 10만 개 이상의 React 컴포넌트가 모든 마이그레이션 전략을 검증합니다. </Para> <div className="order-last pt-5"> @@ -495,9 +498,9 @@ export function HomeContent() { <Center> <Header>수백만 명이 있는 커뮤니티</Header> <Para> - 여러분은 혼자가 아닙니다. 200만 명이 넘는 개발자들이 React - 문서를 매달 방문합니다. React는 사람들과 팀이 동의할 수 있는 - 것입니다. + 여러분은 혼자가 아닙니다. 전세계의 200만 명이 넘는 개발자들이 + React 문서를 매달 방문합니다. React는 사람들과 팀이 동의할 수 + 있는 것입니다. </Para> </Center> </div> @@ -505,12 +508,12 @@ export function HomeContent() { <div className="mx-auto flex flex-col max-w-4xl"> <Center> <Para> - 이것이 바로 React가 라이브러리를 넘어 아키텍처, 심지어 - 에코시스템 그 이상인 이유입니다. React는 커뮤니티입니다. - 도움을 요청하고, 기회를 찾고, 새로운 친구를 만날 수 있는 - 곳입니다. 개발자와 디자이너, 초보자와 전문가, 연구원과 예술가, - 교사와 학생을 만날 수 있습니다. 모두의 배경은 다를 수 있지만, - React를 통해 함께 사용자 인터페이스를 만들 수 있습니다. + 이것이 바로 React가 단순한 라이브러리, 아키텍처, 혹은 생태계 + 그 이상인 이유입니다. React는 바로 커뮤니티입니다. 도움을 + 요청하고, 기회를 찾고, 새로운 친구를 만날 수 있는 곳입니다. + 개발자와 디자이너, 초보자와 전문가, 연구원과 예술가, 교사와 + 학생을 만날 수 있습니다. 배경은 모두 다를 수 있지만, React를 + 통해 함께 사용자 인터페이스를 만들 수 있습니다. </Para> </Center> </div> @@ -528,7 +531,7 @@ export function HomeContent() { <Logo className="uwu-hidden text-brand dark:text-brand-dark w-24 lg:w-28 mb-10 lg:mb-8 mt-12 h-auto mx-auto self-start" /> <Header> React 커뮤니티에 - <Br /> 오신 것을 환영합니다. + <Br /> 오신 것을 환영합니다 </Header> <ButtonLink href={'/learn'} diff --git a/src/components/Layout/TopNav/TopNav.tsx b/src/components/Layout/TopNav/TopNav.tsx index dab8dcb37..3d6e4b689 100644 --- a/src/components/Layout/TopNav/TopNav.tsx +++ b/src/components/Layout/TopNav/TopNav.tsx @@ -326,7 +326,7 @@ export default function TopNav({ <NavItem isActive={section === 'reference'} url="/reference/react"> - 레퍼런스 + API 참고서 </NavItem> <NavItem isActive={section === 'community'} url="/community"> 커뮤니티 diff --git a/src/content/blog/2023/03/16/introducing-react-dev.md b/src/content/blog/2023/03/16/introducing-react-dev.md index 15364878c..8b13cb55e 100644 --- a/src/content/blog/2023/03/16/introducing-react-dev.md +++ b/src/content/blog/2023/03/16/introducing-react-dev.md @@ -43,7 +43,7 @@ description: 오늘 React와 React 문서의 새로운 보금자리인 react.dev **새로운 문서는 Hooks를 사용한 React를 처음부터 가르칩니다.** 문서는 두 가지 주요 섹션으로 나뉘어져 있습니다. * **[React 배우기](/learn)** 는 React를 기초부터 스스로 학습할 수 있는 과정입니다. -* **[API 레퍼런스](/reference)** 는 모든 React API에 대한 세부 내용과 사용 예시를 제공합니다. +* **[API 참고서](/reference)** 는 모든 React API에 대한 세부 내용과 사용 예시를 제공합니다. 각 섹션에서 무슨 내용을 알 수 있는지 자세히 살펴보겠습니다. @@ -456,9 +456,9 @@ export default function PackingList() { 브라우저 공급업체에게 이 표현이 100% 과학적으로 정확하다는 확인을 받았습니다. -## 새로운, 상세한 API 레퍼런스 {/*a-new-detailed-api-reference*/} +## 새로운, 상세한 API 참고서 {/*a-new-detailed-api-reference*/} -[API 레퍼런스](/reference/react)에서, 이제 모든 React API는 전용 페이지를 가집니다. 모든 종류의 API들이 포함됩니다. +[API 참고서](/reference/react)에서, 이제 모든 React API는 전용 페이지를 가집니다. 모든 종류의 API들이 포함됩니다. - [`useState`](/reference/react/useState) 같은 내장 Hooks - [`<Suspense>`](/reference/react/Suspense) 같은 내장 컴포넌트 @@ -610,7 +610,7 @@ button { display: block; margin-top: 10px; } 또한 몇몇 API 페이지는 (일반적인 문제에 대한) [트러블슈팅](/reference/react/useEffect#troubleshooting)과 (더 이상 사용하지 않는 API와 관련된) [대안](/reference/react-dom/findDOMNode#alternatives)을 포함하고 있습니다. -이러한 접근 방식이 API 레퍼런스를 단순히 인자를 찾는 용도뿐만 아니라, 각 API가 어떤 다양한 작업을 수행할 수 있는지, 어떻게 다른 API와 연결되어 있는지를 확인하는 데 유용하게 될 것을 기대합니다. +이러한 접근 방식이 API 참고서를 단순히 인자를 찾는 용도뿐만 아니라, 각 API가 어떤 다양한 작업을 수행할 수 있는지, 어떻게 다른 API와 연결되어 있는지를 확인하는 데 유용하게 될 것을 기대합니다. ## 다음은 무엇인가요? {/*whats-next*/} diff --git a/src/content/learn/index.md b/src/content/learn/index.md index a28e615ad..dfe86ba5e 100644 --- a/src/content/learn/index.md +++ b/src/content/learn/index.md @@ -382,7 +382,7 @@ button { ## Hook 사용하기 {/*using-hooks*/} -`use`로 시작하는 함수를 *Hook*이라고 합니다. `useState`는 React에서 제공하는 내장 Hook입니다. 다른 내장 Hook은 [API 레퍼런스](/reference/react)에서 찾아볼 수 있습니다. 또한 기존의 것들을 조합하여 자신만의 Hook을 작성할 수도 있습니다. +`use`로 시작하는 함수를 *Hook*이라고 합니다. `useState`는 React에서 제공하는 내장 Hook입니다. 다른 내장 Hook은 [API 참고서](/reference/react)에서 찾아볼 수 있습니다. 또한 기존의 것들을 조합하여 자신만의 Hook을 작성할 수도 있습니다. Hook은 다른 함수보다 더 제한적입니다. 컴포넌트(또는 다른 Hook)의 *상단*에서만 Hook을 호출할 수 있습니다. 조건이나 반복에서 `useState`를 사용하고 싶다면 새 컴포넌트를 추출하여 그곳에 넣으세요. diff --git a/src/content/learn/tutorial-tic-tac-toe.md b/src/content/learn/tutorial-tic-tac-toe.md index 7eec48733..516255153 100644 --- a/src/content/learn/tutorial-tic-tac-toe.md +++ b/src/content/learn/tutorial-tic-tac-toe.md @@ -1361,7 +1361,7 @@ const nextSquares = ['X', null, null, null, null, null, null, null, null]; 불변성을 사용하면 복잡한 기능을 훨씬 쉽게 구현할 수 있습니다. 우리는 이 자습서의 뒷부분에서 게임의 진행 과정을 검토하고 과거 움직임으로 "돌아가기"를 할 수 있는 "시간 여행" 기능을 구현할 예정입니다. 특정 작업을 실행 취소하고 다시 실행하는 기능은 이 게임에만 국한된 것이 아닌 앱의 일반적인 요구사항입니다. 직접적인 데이터 변경을 피하면 이전 버전의 데이터를 그대로 유지하여 나중에 재사용(또는 초기화)할 수 있습니다. -불변성을 사용하는 것의 또 다른 장점이 있습니다. 기본적으로 부모 컴포넌트의 state가 변경되면 모든 자식 컴포넌트가 자동으로 다시 렌더링 됩니다. 여기에는 변경 사항이 없는 자식 컴포넌트도 포함됩니다. 리렌더링 자체가 사용자에게 보이는 것은 아니지만 성능상의 이유로 트리의 영향을 받지 않는 부분의 리렌더링을 피하는 것이 좋습니다. 불변성을 사용하면 컴포넌트가 데이터의 변경 여부를 저렴한 비용으로 판단할 수 있습니다. [`memo` API 레퍼런스](/reference/react/memo)에서 React가 컴포넌트를 다시 렌더링할 시점을 선택하는 방법에 대해 살펴볼 수 있습니다. +불변성을 사용하는 것의 또 다른 장점이 있습니다. 기본적으로 부모 컴포넌트의 state가 변경되면 모든 자식 컴포넌트가 자동으로 다시 렌더링 됩니다. 여기에는 변경 사항이 없는 자식 컴포넌트도 포함됩니다. 리렌더링 자체가 사용자에게 보이는 것은 아니지만 성능상의 이유로 트리의 영향을 받지 않는 부분의 리렌더링을 피하는 것이 좋습니다. 불변성을 사용하면 컴포넌트가 데이터의 변경 여부를 저렴한 비용으로 판단할 수 있습니다. [`memo` API 참고서](/reference/react/memo)에서 React가 컴포넌트를 다시 렌더링할 시점을 선택하는 방법에 대해 살펴볼 수 있습니다. ### 순서 정하기 {/*taking-turns*/} diff --git a/src/sidebarHome.json b/src/sidebarHome.json index 5fb212184..3b018bcc1 100644 --- a/src/sidebarHome.json +++ b/src/sidebarHome.json @@ -11,7 +11,7 @@ "path": "/learn" }, { - "title": "설치", + "title": "설치하기", "path": "/learn/installation" }, { diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index f318d9ab2..c4dcbca8f 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -21,7 +21,7 @@ ] }, { - "title": "설치", + "title": "설치하기", "path": "/learn/installation", "routes": [ { diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 1b3dd82db..6b0542762 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -1,5 +1,5 @@ { - "title": "API 레퍼런스", + "title": "API 참고서", "path": "/reference/react", "routes": [ { From 3c58b51897a02ea1005c11d273735c0f2ab4b325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Sun, 29 Dec 2024 21:47:01 +0900 Subject: [PATCH 0439/1164] refactor: translate text `Learn`, `Reference` and more in `TopNav.tsx` --- src/components/Layout/TopNav/TopNav.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Layout/TopNav/TopNav.tsx b/src/components/Layout/TopNav/TopNav.tsx index 3d6e4b689..296155b93 100644 --- a/src/components/Layout/TopNav/TopNav.tsx +++ b/src/components/Layout/TopNav/TopNav.tsx @@ -408,20 +408,20 @@ export default function TopNav({ <Suspense fallback={null}> <div className="ps-3 xs:ps-5 xs:gap-0.5 xs:text-base overflow-x-auto flex flex-row lg:hidden text-base font-bold text-secondary dark:text-secondary-dark"> <NavItem isActive={section === 'learn'} url="/learn"> - Learn + 학습하기 </NavItem> <NavItem isActive={section === 'reference'} url="/reference/react"> - Reference + API 참고서 </NavItem> <NavItem isActive={section === 'community'} url="/community"> - Community + 커뮤니티 </NavItem> <NavItem isActive={section === 'blog'} url="/blog"> - Blog + 블로그 </NavItem> </div> <div From 815606db58dfe45562a50aec164a6885c2f1c771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Sun, 29 Dec 2024 21:52:00 +0900 Subject: [PATCH 0440/1164] refactor: update `sidebarLearn.json` --- src/sidebarLearn.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index c4dcbca8f..43729ef11 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -65,7 +65,7 @@ "path": "/learn/your-first-component" }, { - "title": "컴포넌트 import 및 export하기", + "title": "컴포넌트 Import 및 Export하기", "path": "/learn/importing-and-exporting-components" }, { @@ -77,7 +77,7 @@ "path": "/learn/javascript-in-jsx-with-curly-braces" }, { - "title": "컴포넌트에 props 전달하기", + "title": "컴포넌트에 Props 전달하기", "path": "/learn/passing-props-to-a-component" }, { @@ -116,7 +116,7 @@ "path": "/learn/render-and-commit" }, { - "title": "스냅샷으로서의 state", + "title": "스냅샷으로서의 State", "path": "/learn/state-as-a-snapshot" }, { @@ -124,11 +124,11 @@ "path": "/learn/queueing-a-series-of-state-updates" }, { - "title": "객체 state 업데이트하기", + "title": "객체 State 업데이트하기", "path": "/learn/updating-objects-in-state" }, { - "title": "배열 state 업데이트하기", + "title": "배열 State 업데이트하기", "path": "/learn/updating-arrays-in-state" } ] From d3ff085e687a26b61bb495a30821219c4d27d360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Sun, 29 Dec 2024 22:49:55 +0900 Subject: [PATCH 0441/1164] =?UTF-8?q?refactor:=20translate=20`Previous`=20?= =?UTF-8?q?and=20`Next`=20to=20`=EC=9D=B4=EC=A0=84`=20and=20`=EB=8B=A4?= =?UTF-8?q?=EC=9D=8C`=20in=20`DocsFooter.tsx`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 문서 하단부 Footer에서 Previous 및 Next로 표현되던 텍스트 한국어로 수정. --- src/components/DocsFooter.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/DocsFooter.tsx b/src/components/DocsFooter.tsx index 5f2330e7e..68e9cf7ec 100644 --- a/src/components/DocsFooter.tsx +++ b/src/components/DocsFooter.tsx @@ -30,7 +30,7 @@ export const DocsPageFooter = memo<DocsPageFooterProps>( <div className="grid grid-cols-1 gap-4 py-4 mx-auto max-w-7xl md:grid-cols-2 md:py-12"> {prevRoute?.path ? ( <FooterLink - type="Previous" + type="이전" title={prevRoute.title} href={prevRoute.path} /> @@ -40,7 +40,7 @@ export const DocsPageFooter = memo<DocsPageFooterProps>( {nextRoute?.path ? ( <FooterLink - type="Next" + type="다음" title={nextRoute.title} href={nextRoute.path} /> @@ -63,7 +63,7 @@ function FooterLink({ }: { href: string; title: string; - type: 'Previous' | 'Next'; + type: '이전' | '다음'; }) { return ( <NextLink @@ -71,12 +71,12 @@ function FooterLink({ className={cn( 'flex gap-x-4 md:gap-x-6 items-center w-full md:min-w-80 md:w-fit md:max-w-md px-4 md:px-5 py-6 border-2 border-transparent text-base leading-base text-link dark:text-link-dark rounded-lg group focus:text-link dark:focus:text-link-dark focus:bg-highlight focus:border-link dark:focus:bg-highlight-dark dark:focus:border-link-dark focus:border-opacity-100 focus:border-2 focus:ring-1 focus:ring-offset-4 focus:ring-blue-40 active:ring-0 active:ring-offset-0 hover:bg-gray-5 dark:hover:bg-gray-80', { - 'flex-row-reverse justify-self-end text-end': type === 'Next', + 'flex-row-reverse justify-self-end text-end': type === '다음', } )}> <IconNavArrow className="inline text-tertiary dark:text-tertiary-dark group-focus:text-link dark:group-focus:text-link-dark" - displayDirection={type === 'Previous' ? 'start' : 'end'} + displayDirection={type === '이전' ? 'start' : 'end'} /> <div className="flex flex-col overflow-hidden"> <span className="text-sm font-bold tracking-wide no-underline uppercase text-secondary dark:text-secondary-dark group-focus:text-link dark:group-focus:text-link-dark group-focus:text-opacity-100"> From f92b23cb6bd90efb55c17696b3e13b3f7bad6b22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Sun, 29 Dec 2024 22:53:38 +0900 Subject: [PATCH 0442/1164] docs: update `installation.md` --- src/content/learn/installation.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/content/learn/installation.md b/src/content/learn/installation.md index 27a39d122..edec4eb31 100644 --- a/src/content/learn/installation.md +++ b/src/content/learn/installation.md @@ -4,7 +4,7 @@ title: 설치하기 <Intro> -React는 처음부터 점진적으로 적용할 수 있도록 설계되었으며 필요한 만큼 React를 사용할 수 있습니다. React를 맛보기로 접해보려거나 간단한 HTML 페이지에 약간의 상호작용을 추가하거나 복잡한 React 기반의 앱을 시작하고자 하는 경우, 이 섹션을 참고하세요. +React는 처음부터 점진적으로 적용할 수 있도록 설계되었으며 필요한 만큼 React를 사용할 수 있습니다. React를 맛보기로 접해보려거나, 간단한 HTML 페이지에 약간의 상호작용을 추가하거나, 복잡한 React 기반의 앱을 시작하고자 하는 경우, 이 섹션을 참고하세요. </Intro> @@ -37,7 +37,7 @@ export default function App() { 직접 편집하거나 오른쪽 상단의 "Fork" 버튼을 눌러 새 탭에서 열 수 있습니다. -React 문서의 대부분 페이지에는 이와 같은 샌드박스가 있습니다. React 문서 외에도 [CodeSandbox](https://codesandbox.io/s/new), [StackBlitz](https://stackblitz.com/fork/react), [CodePen.](https://codepen.io/pen?template=QWYVwWN) 등의 온라인 샌드박스에서 React를 지원합니다. +React 문서의 대부분 페이지에는 이와 같은 샌드박스가 있습니다. React 문서 외에도 [CodeSandbox](https://codesandbox.io/s/new), [StackBlitz](https://stackblitz.com/fork/react), [CodePen](https://codepen.io/pen?template=QWYVwWN) 등의 온라인 샌드박스에서 React를 지원합니다. ### 로컬 환경에서 React 시도하기 {/*try-react-locally*/} @@ -49,9 +49,8 @@ React로 완전히 앱이나 웹사이트를 구축하고 싶다면, [새로운 ## 기존 프로젝트에 React 추가하기 {/*add-react-to-an-existing-project*/} -기존 앱이나 웹사이트에서 React를 적용하고 싶다면, [기존 프로젝트에 React를 추가](/learn/add-react-to-an-existing-project)하세요. +기존 앱이나 웹사이트에 React를 적용하고 싶다면, [기존 프로젝트에 React를 추가](/learn/add-react-to-an-existing-project)하세요. ## 다음 단계 {/*next-steps*/} -React 개념 중 가장 중요한 개념들을 살펴보기 위해 [빠른 시작 가이드](/learn)로 이동하세요. - +React의 개념 중 가장 중요한 개념들을 살펴보기 위해 [빠르게 시작하기](/learn)로 이동하세요. From 822ab3093782ff092c6fc3e1b98e27b20aa0740a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Sun, 29 Dec 2024 23:00:18 +0900 Subject: [PATCH 0443/1164] =?UTF-8?q?refactor:=20translate=20`deep=20dive`?= =?UTF-8?q?=20to=20`=EC=9E=90=EC=84=B8=ED=9E=88=20=EC=82=B4=ED=8E=B4?= =?UTF-8?q?=EB=B3=B4=EA=B8=B0`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MDX/ExpandableExample.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MDX/ExpandableExample.tsx b/src/components/MDX/ExpandableExample.tsx index 29116c1b1..d643f98e7 100644 --- a/src/components/MDX/ExpandableExample.tsx +++ b/src/components/MDX/ExpandableExample.tsx @@ -71,7 +71,7 @@ function ExpandableExample({children, excerpt, type}: ExpandableExampleProps) { {isDeepDive && ( <> <IconDeepDive className="inline me-2 dark:text-purple-30 text-purple-40" /> - Deep Dive + 자세히 살펴보기 </> )} {isExample && ( From ff9f6987075f8573038b6e489467f891586fc532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Sun, 29 Dec 2024 23:43:04 +0900 Subject: [PATCH 0444/1164] docs: update `start-a-new-react-project.md` --- .../learn/start-a-new-react-project.md | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/content/learn/start-a-new-react-project.md b/src/content/learn/start-a-new-react-project.md index e6b4dca74..48956ab35 100644 --- a/src/content/learn/start-a-new-react-project.md +++ b/src/content/learn/start-a-new-react-project.md @@ -4,38 +4,39 @@ title: 새로운 React 프로젝트 시작하기 <Intro> -React를 전체적으로 적용한 애플리케이션이나 사이트를 새롭게 작성하고 싶다면, 커뮤니티에서 React 기반 프레임워크 중 하나를 사용하는 것이 좋습니다. +React로 새로운 앱이나 새로운 웹사이트를 완전히 작성하고 싶다면, 커뮤니티에서 React 기반 프레임워크 중 하나를 사용하는 것이 좋습니다. </Intro> +프레임워크 없이 React를 사용할 수 있습니다. 그러나 대부분의 애플리케이션이나 사이트들이 결국에는 코드 분할<sup>Code-Splitting</sup>, 라우팅<sup>Routing</sup>, 데이터 가져오기<sup>Data Fetching</sup>, 그리고 HTML 생성에 대한 해결책을 찾고 있다는 것을 발견했습니다. 이러한 문제들은 UI 라이브러리들의 공통적인 문제이며 React만의 문제는 아닙니다. -프레임워크 없이 React를 사용할 수 있습니다. 그러나 대부분에 애플리케이션이나 사이트들이 결국에는 코드 분할, routing, 데이터 fetching, 그리고 HTML 생성에 대한 해결책을 찾고 있다는것을 발견했습니다. 이러한 문제들은 UI 라이브러리들의 기본적인 문제이며 React 만의 문제는 아닙니다. - -프레임워크로 시작하면 React를 빠르게 시작할 수 있고, 나중에 자체 프레임워크를 구축하는 것을 피할 수 있습니다. +프레임워크로 시작하면 React를 빠르게 시작할 수 있고, 나중에 자체적인 프레임워크를 구축하는 것을 피할 수 있습니다. <DeepDive> #### 프레임워크 없이 React 를 사용할 수 있나요? {/*can-i-use-react-without-a-framework*/} -물론 React를 프레임워크 없이 사용할 수 있습니다. [기존 페이지의 일부분에 React 사용하기](/learn/add-react-to-an-existing-project#using-react-for-a-part-of-your-existing-page)를 활용해 보세요. **하지만, 새로운 애플리케이션이나 사이트 전체를 React로 구축하는 경우에는 프레임워크 사용을 권장합니다.** +물론 React를 프레임워크 없이 사용할 수 있습니다. [기존 페이지의 일부분에 React 사용하기](/learn/add-react-to-an-existing-project#using-react-for-a-part-of-your-existing-page)를 살펴보세요. **하지만, 새로운 애플리케이션이나 사이트 전체를 React로 구축하는 경우에는 프레임워크의 사용을 권장합니다.** -이유가 여기 있습니다. +이유는 아래와 같습니다. -라우팅이나 데이터 페칭과 같은 기능이 처음엔 필요하지 않더라도, 이를 위한 라이브러리 사용은 필요할 수도 있습니다. JavaScript 번들은 날마다 새로운 기능들이 더해지고, 모든 각각의 라우팅 코드를 어떻게 분할해야 할지 고민해야 하는 순간이 오게 됩니다. 데이터 페칭은 날로 복잡해지고, 아마 서버-클라이언트 네트워크의 워터폴이 애플리케이션의 속도를 느리게 만드는 순간도 직면하게 될 겁니다. 성능이 좋지 않은 네트워크 환경이나 저사양의 단말기를 이용하는 사용자들이 늘어남에 따라 서버 혹은 빌드 시간에 컴포넌트에서 HTML을 일찍 생성하여 내용을 먼저 표시할 필요가 생길 수도 있습니다. 일부 코드의 설정을 변경하여 서버에서 혹은 빌드되는 동안 실행시키는 것은 매우 까다로운 작업이 될 수 있습니다. +라우팅<sup>Routing</sup>이나 데이터 가져오기<sup>Data Fetching</sup>와 같은 기능이 처음엔 필요하지 않더라도, 이를 위한 라이브러리의 사용은 필요할 수도 있습니다. 자바스크립트<sup>JavaScript</sup> 번들은 날마다 새로운 기능들이 더해지고, 각각의 라우팅 코드를 어떻게 분할해야 할지 고민해야 하는 순간이 오게 됩니다. 데이터 가져오기<sup>Data Fetching</sup>는 날로 복잡해지고, 아마 서버-클라이언트 네트워크의 워터폴<sup>Waterfall</sup>이 애플리케이션의 속도를 느리게 하는 순간도 직면하게 될 겁니다. 성능이 좋지 않은 네트워크 환경이나 저사양의 단말기를 이용하는 사용자들이 늘어남에 따라, 서버에서 혹은 빌드 시간에 컴포넌트에서 HTML을 생성하여 내용<sup>Content</sup>을 빠르게 표시해야할 필요가 생길 수도 있습니다. 일부 코드의 설정을 변경하여 서버에서 혹은 빌드되는 동안 실행시키는 것은 매우 까다로운 작업이 될 수 있습니다. -**이 문제는 React에 국한된 것은 아닙니다. 이러한 이유로 Svelte에는 SvelteKit가 있고, Vue에는 Nuxt가 존재합니다.** 자체 서비스에서 이러한 문제를 해결하기 위해서는 라우터와 데이터 페칭 라이브러리를 번들러와 통합할 필요가 있습니다. 초기 세팅을 구동하는 건 그다지 어렵지 않지만, 애플리케이션이 시간이 지남에 따라 성장함에도 불구하고 빠르게 로드되게 만드는 데에는 많은 세부 사항들이 연관되어 있습니다. 가능한 한 적은 양의 애플리케이션 코드를 전송하지만 페이지에 필요한 데이터와 함께 단일 클라이언트-서버의 왕복으로 이루어지게 하고 싶을 수 있습니다. JavaScript 코드가 실행되기도 전에 페이지에 상호작용을 할 수 있도록 점진적인 개선을 하고 싶어질 수도 있습니다. 마케팅 목적의 완전히 정적인 HTML 파일들이 속한 폴더를 생성하여 JavaScript 가 비활성화된 환경에서도 이를 작동하게 하고 싶을 수도 있습니다. 이러한 기능들을 구현하는 것은 실제로 많은 작업을 요합니다. +**이러한 문제가 React에만 국한된 것은 아닙니다. 이것이 바로 Svelte에 SvelteKit이 존재하고, Vue에는 Nuxt가 있는 이유입니다.** 자체 서비스에서 이러한 문제를 해결하기 위해서는 라우터<sup>Router</sup>와 데이터 가져오기<sup>Data Fetching</sup> 라이브러리를 번들러와 통합할 필요가 있습니다. 초기 세팅을 구동하는 건 그다지 어렵지 않지만, 시간이 지나면서 앱이 커져도 빠르게 로드되는 앱을 만드는 데에는 많은 세부 사항들이 포함됩니다. 앱 코드의 최소한의 양만 전송하되, 페이지에 필요한 데이터를 병렬로 처리하면서 클라이언트-서버 간의 단일 왕복<sup>Single Roundtrip</sup>으로 이를 처리하고 싶을 수도 있습니다. 자바스크립트 코드가 실행되기도 전에 페이지가 상호작용 할 수 있도록 점진적인 개선을 하고 싶을 수도 있습니다. 마케팅 목적의 완전히 정적인 HTML 파일들이 속한 폴더를 생성하여 자바스크립트가 비활성화된 환경에서도 이를 작동하게 하고 싶을 수도 있습니다. 이러한 기능들을 구현하는 것은 실제로 많은 작업을 요합니다. -**이 페이지의 React 프레임워크들은 추가 작업 없이도 기본적으로 이런 문제를 해결합니다.** 이들은 매우 간소화된 상태로 시작할 수 있고 애플레케이션의 필요에 따라 확장이 가능합니다. 각각의 React 프레임워크들은 커뮤니티가 있어 질문에 대한 답을 얻고 도구를 업그레이드하는 것은 더 쉬워집니다. 또한 프레임워크들은 코드에 구조를 제공하며, 다른 프로젝트들간의 맥락과 스킬을 유지하는 데에 도움이 됩니다. 반대로, 맞춤 설정을 사용하면 지원되지 않는 의존성 버전에 빠질 수 있으며, 결국엔 커뮤니티나 업그레이드 경로가 없는 자체 프레임워크를 만들게 될 수도 있습니다. (그리고 과거에서처럼 우연히 고안된 것들이 될 수 있습니다.) +**현재 페이지의 React 프레임워크들은 추가 작업 없이도 기본적으로 이러한 문제들을 해결합니다.** 이들은 매우 간소화된 상태로 시작할 수 있고 애플리케이션의 필요에 따라 확장이 가능합니다. 각각의 React 프레임워크들은 커뮤니티가 있어 질문에 대한 답을 얻고 도구를 업그레이드하는 것이 더 쉬워집니다. 또한 프레임워크들은 코드에 구조를 제공하며, 다른 프로젝트들간의 맥락과 스킬을 유지하는 데에 도움이 됩니다. 반대로, 맞춤 설정을 사용하면 지원되지 않는 의존성<sup>Dependency</sup> 버전에 빠질 수 있으며, 결국엔 커뮤니티나 업그레이드 경로가 없는 자체 프레임워크를 만들게 될 수도 있습니다. (그리고 만약 이전에 우리가 만든 것들과 비슷하다면, 더 엉성하게 설계된 것일 수 있습니다.) -애플리케이션이 이러한 프레임워크들의 지원을 잘 받지 못하는 특수한 제약에 놓여 있거나, 스스로 이러한 문제들을 해결하고 싶다면 React를 사용하여 자체 맞춤 설정을 적용할 수 있습니다. npm에서 `react` 와 `react-dom` 를 채택하고, [Vite](https://vitejs.dev/) 나 [Parcel](https://parceljs.org/) 같은 번들러를 활용하여 맞춤 빌드 프로세스를 정립한 다음, 라우팅, 정적 생성 혹은 서버 사이드 렌더링 등 필요에 따라 다른 도구를 추가할 수 있습니다. +애플리케이션이 이러한 프레임워크들의 지원을 잘 받지 못하는 특수한 제약에 놓여 있거나, 스스로 이러한 문제들을 해결하고 싶다면 React를 사용하여 자체 맞춤 설정을 적용할 수 있습니다. npm에서 `react` 와 `react-dom`을 설치하고, [Vite](https://vitejs.dev/) 나 [Parcel](https://parceljs.org/) 같은 번들러를 활용하여 맞춤 빌드 프로세스를 정립한 다음, 라우팅<sup>Routing</sup>, 정적 생성<sup>Static Generation</sup> 혹은 서버 사이드 렌더링<sup>SSR, Server Side Rendering</sup> 등 필요에 따라 다른 도구들을 추가할 수 있습니다. </DeepDive> ## 프로덕션 수준의 React 프레임워크 {/*production-grade-react-frameworks*/} -이 프레임워크들은 프로덕션에서 애플리케이션을 배포하고 확장하는 데에 필요한 모든 기능을 지원하며 [풀스택 아키텍처 비전](#which-features-make-up-the-react-teams-full-stack-architecture-vision) 을 지원하는 방향으로 발전하고 있습니다. 모든 프레임워크들은 활발한 커뮤니티의 지원을 받는 오픈소스이며, 자체 서버나 호스팅 제공자에 배포할 수 있습니다. 만일 이 목록에 포함되길 원하는 프레임워크 저자가 있다면, [여기에서 알려주세요.](https://github.com/reactjs/react.dev/issues/new?assignees=&labels=type%3A+framework&projects=&template=3-framework.yml&title=%5BFramework%5D%3A+) +아래 프레임워크들은 프로덕션에서 애플리케이션을 배포하고 확장하는 데에 필요한 모든 기능을 지원하며 [풀스택 아키텍처 비전](#which-features-make-up-the-react-teams-full-stack-architecture-vision)을 지원하는 방향으로 발전하고 있습니다. 모든 프레임워크들은 활발한 커뮤니티의 지원을 받는 오픈 소스이며, 자체 서버나 호스팅 제공자에 배포할 수 있습니다. 만일 이 목록에 포함되길 원하는 프레임워크의 저자가 있다면, [여기에서 알려주세요.](https://github.com/reactjs/react.dev/issues/new?assignees=&labels=type%3A+framework&projects=&template=3-framework.yml&title=%5BFramework%5D%3A+) + +### Next.js {/*nextjs-pages-router*/} -**[Next.js' Pages Router](https://nextjs.org/)는 풀스택 React 프레임워크입니다.** 다재다능한 도구이며, 정적인 블로그부터 복잡한 동적 애플리케이션까지 다양한 크기의 React 애플리케이션을 만들 수 있습니다. 새로운 Next.js 프로젝트를 작성하려면 터미널에서 다음을 실행하세요. +**[Next.js의 Pages Router](https://nextjs.org/)는 풀스택 React 프레임워크입니다.** 다재다능한 도구이며, 정적인 블로그부터 복잡한 동적 애플리케이션까지 다양한 크기의 React 애플리케이션을 만들 수 있습니다. 새로운 Next.js 프로젝트를 작성하려면 터미널에서 다음을 실행하세요. <TerminalBlock> npx create-next-app@latest @@ -43,7 +44,7 @@ npx create-next-app@latest Next.js를 처음 사용하는 분이라면 [Next.js 배우기 코스](https://nextjs.org/learn)를 읽어보세요. -Next.js는 [Vercel](https://vercel.com/)이 관리합니다. 어느 Node.js 서버, 서버리스 호스팅 또는 직접 소유한 서버 어느 곳에라도 [Next.js 애플리케이션을 배포](https://nextjs.org/docs/app/building-your-application/deploying)할 수 있습니다. Next.js 는 서버가 필요없는 [static export](https://nextjs.org/docs/pages/building-your-application/deploying/static-exports) 도 제공합니다. +Next.js는 [Vercel](https://vercel.com/)이 관리합니다. 어떤 Node.js 서버, 서버리스 호스팅 또는 직접 소유한 서버 어느 곳에서라도 [Next.js 애플리케이션을 배포](https://nextjs.org/docs/app/building-your-application/deploying)할 수 있습니다. Next.js는 서버가 필요없는 [정적 내보내기<sup>Static Exports</sup>](https://nextjs.org/docs/pages/building-your-application/deploying/static-exports) 도 제공합니다. ### Remix {/*remix*/} @@ -55,7 +56,7 @@ npx create-remix Remix를 처음 사용하는 분이라면 Remix [블로그 자습서](https://remix.run/docs/en/main/tutorials/blog) (짧은 문서)와 [애플리케이션 자습서](https://remix.run/docs/en/main/tutorials/jokes) (긴 문서)를 참고하세요. -Remix는 [Shopify](https://www.shopify.com/)가 관리합니다. Remix 프로젝트를 작성할 때는 [배포할 대상을 선택](https://remix.run/docs/en/main/guides/deployment)해야 합니다. Remix 애플리케이션은 어느 Node.js 서버나 서버리스 호스팅에라도 [어댑터](https://remix.run/docs/en/main/other-api/adapter)를 사용하거나 직접 작성하여 배포할 수 있습니다. +Remix는 [Shopify](https://www.shopify.com/)가 관리합니다. Remix 프로젝트를 작성할 때는 [배포할 대상을 선택](https://remix.run/docs/en/main/guides/deployment)해야 합니다. Remix 애플리케이션은 어떤 Node.js 서버나 서버리스 호스팅에라도 [어댑터<sup>Adapter</sup>](https://remix.run/docs/en/main/other-api/adapter)를 사용하거나 직접 작성하여 배포할 수 있습니다. ### Gatsby {/*gatsby*/} @@ -83,22 +84,22 @@ Expo는 [Expo (기업)](https://expo.dev/about)이 관리합니다. Expo를 사 ## Bleeding-edge React frameworks {/*bleeding-edge-react-frameworks*/} -React를 지속적으로 개선할 방법을 찾아가는 과정에서, 우리는 React를 프레임워크(특히 라우팅, 번들링, 서버 기술)와 더 밀접하게 통합하는 것이 React 사용자가 더 나은 앱을 만드는 데 도움을 줄 수 있는 가장 큰 기회라는 것을 깨달았습니다. Next.js 팀은 [React 서버 컴포넌트](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components)와 같은 가장 최신의 React 기능을 프레임워크에 구애받지 않는 형태로 연구, 개발, 통합, 테스트하는 데에 협력하기로 합의했습니다. +React를 지속적으로 개선할 방법을 찾아가는 과정에서, 우리는 React를 프레임워크(특히 라우팅, 번들링, 서버 기술)와 더 밀접하게 통합하는 것이 React 사용자에게 더 나은 앱을 만드는 데 도움을 줄 수 있는 가장 큰 기회라는 것을 깨달았습니다. Next.js 팀은 [React 서버 컴포넌트](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components)와 같은 가장 최신의 React 기능을 프레임워크에 구애받지 않는 형태로 연구, 개발, 통합, 테스트하는 데에 협력하기로 합의했습니다. -이러한 기능들은 매일 프로덕션 수준에 근접하고 있으며 다른 번들러 및 프레임워크 개발자들과 이를 통합하기 위해 협의 중입니다. 희망으로는 1, 2년 후에 이 페이지에 나열된 모든 프레임워크가 이러한 기능을 지원했으면 합니다. (이러한 기능을 실험해 보기 위해 우리와 협력하고 싶은 프레임워크 개발자가 있다면 알려주세요!) +이러한 기능들은 매일 프로덕션 수준에 근접하고 있으며, 다른 번들러 및 프레임워크 개발자들과 이를 통합하기 위해 협의 중입니다. 바라건데 1, 2년 후에 이 페이지에 나열된 모든 프레임워크가 이러한 기능을 지원했으면 합니다. (이러한 기능을 실험해 보기 위해 우리와 협력하고 싶은 프레임워크 개발자가 있다면 알려주세요!) ### Next.js (App Router) {/*nextjs-app-router*/} -**[Next.js's App Router](https://nextjs.org/docs)는 React 팀의 풀스택 아키텍처 비전을 구현하기 위해 재설계된 Next.js API입니다.** 이를 통해 서버에서 또는 빌드 중에 실행되는 비동기 컴포넌트에서 데이터를 가져올 수 있습니다. +**[Next.js의 App Router](https://nextjs.org/docs)는 React 팀의 풀스택 아키텍처 비전을 구현하기 위해 재설계된 Next.js API입니다.** 이를 통해 서버에서 또는 빌드 중에 실행되는 비동기 컴포넌트에서 데이터를 가져올 수 있습니다. -Next.js는 [Vercel](https://vercel.com/)이 관리합니다. 어느 Node.js 서버, 서버리스 호스팅 또는 직접 소유한 서버 어느 곳에라도 [Next.js 애플리케이션을 배포](https://nextjs.org/docs/app/building-your-application/deploying)할 수 있습니다. Next.js 는 서버가 필요없는 [static export](https://nextjs.org/docs/pages/building-your-application/deploying/static-exports) 도 제공합니다. +Next.js는 [Vercel](https://vercel.com/)이 관리합니다. 어떤 Node.js 서버, 서버리스 호스팅 또는 직접 소유한 서버 어느 곳에라도 [Next.js 애플리케이션을 배포](https://nextjs.org/docs/app/building-your-application/deploying)할 수 있습니다. Next.js 는 서버가 필요없는 [정적 내보내기<sup>Static Exports</sup>](https://nextjs.org/docs/pages/building-your-application/deploying/static-exports)도 제공합니다. <DeepDive> #### React 팀의 풀스택 아키텍처 비전을 구현한 기능은 무엇인가요? {/*which-features-make-up-the-react-teams-full-stack-architecture-vision*/} -Next.js의 App Router 번들러는 공식 [React 서버 컴포넌트 명세](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md) 전체를 구현했습니다. 이를 통해 빌드 시간, 서버 전용, 대화형 컴포넌트를 하나의 React 트리에서 혼합할 수 있습니다. +Next.js의 App Router 번들러는 공식 [React 서버 컴포넌트 명세](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md) 전체를 구현했습니다. 이를 통해 빌드 시간<sup>Build-Time</sup>, 서버 전용<sup>Server-Only</sup>, 그리고 대화형<sup>Interactive</sup> 컴포넌트를 하나의 React 트리<sup>Tree</sup>에서 혼합할 수 있습니다. 예를 들어, 데이터베이스나 파일을 읽는 `async` 함수로 서버 전용 React 컴포넌트를 작성할 수 있습니다. 그런 다음 이를 통해 데이터를 대화형 컴포넌트로 전달할 수 있습니다. @@ -108,7 +109,7 @@ async function Talks({ confId }) { // 1. 서버에 있으므로 데이터 계층과 통신할 수 있습니다. API 엔드포인트가 필요하지 않습니다. const talks = await db.Talks.findAll({ confId }); - // 2. 렌더링 로직을 얼마든지 추가할 수 있습니다. JavaScript 번들 크기가 커지지 않습니다. + // 2. 렌더링 로직을 얼마든지 추가할 수 있습니다. 자바스크립트 번들 크기가 커지지 않습니다. const videos = talks.map(talk => talk.video); // 3. 브라우저에서 실행될 컴포넌트에 데이터를 전달합니다. @@ -116,7 +117,7 @@ async function Talks({ confId }) { } ``` -Next.js의 App Router는 또한 Suspense를 사용하는 데이터 통신과도 잘 어울립니다. 이를 통해 React 트리에서 사용자 인터페이스의 다른 부분에 대한 로딩 상태(스켈레톤 플레이스홀더와 같은)를 직접 지정할 수 있습니다. +Next.js의 App Router는 또한 Suspense를 사용하는 데이터 통신과도 잘 어울립니다. 이를 통해 React 트리에서 사용자 인터페이스의 다른 부분에 대한 로딩 상태(스켈레톤<sup>Skeleton</sup> 플레이스홀더<sup>Placeholder</sup>와 같은)를 직접 지정할 수 있습니다. ```js <Suspense fallback={<TalksLoading />}> @@ -124,6 +125,6 @@ Next.js의 App Router는 또한 Suspense를 사용하는 데이터 통신과도 </Suspense> ``` -서버 컴포넌트와 Suspense는 Next.js의 기능이 아닌 React의 기능입니다. 하지만 프레임워크 수준에서 이를 채택하려면 많은 노력과 비교적 복잡한 구현 작업이 필요합니다. 현재 기준으로는 Next.js의 App Router가 가장 완벽한 구현입니다. React 팀은 차세대 프레임워크에서는 이러한 기능을 구현하기 쉽도록 번들러 개발자와 공동으로 노력하고 있습니다. +서버 컴포넌트와 Suspense는 Next.js의 기능이 아닌 React의 기능입니다. 하지만 프레임워크 수준에서 이를 채택하려면 많은 노력과 비교적 복잡한 구현 작업이 필요합니다. 현재로서는 Next.js의 App Router가 가장 완벽한 구현입니다. React 팀은 차세대 프레임워크에서는 이러한 기능을 구현하기 쉽도록 번들러 개발자와 함께 노력하고 있습니다. </DeepDive> From b16e4a21fcbe8b156849afb3e0a98f8367883fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Mon, 30 Dec 2024 00:18:22 +0900 Subject: [PATCH 0445/1164] docs: update `add-react-to-an-existing-project.md` --- src/components/Layout/Footer.tsx | 4 +- .../learn/add-react-to-an-existing-project.md | 51 ++++++++++--------- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/components/Layout/Footer.tsx b/src/components/Layout/Footer.tsx index 4b2dedd48..ed5324d45 100644 --- a/src/components/Layout/Footer.tsx +++ b/src/components/Layout/Footer.tsx @@ -347,9 +347,7 @@ export function Footer() { <div className="flex flex-col"> <FooterLink isHeader={true}>더 보기</FooterLink> <FooterLink href="/blog">블로그</FooterLink> - <FooterLink href="https://reactnative.dev/"> - React 네이티브 - </FooterLink> + <FooterLink href="https://reactnative.dev/">React Native</FooterLink> <FooterLink href="https://opensource.facebook.com/legal/privacy"> 개인 정보 보호 </FooterLink> diff --git a/src/content/learn/add-react-to-an-existing-project.md b/src/content/learn/add-react-to-an-existing-project.md index c79c0d7f7..37852b95c 100644 --- a/src/content/learn/add-react-to-an-existing-project.md +++ b/src/content/learn/add-react-to-an-existing-project.md @@ -4,57 +4,57 @@ title: 기존 프로젝트에 React 추가하기 <Intro> -기존 프로젝트와 일부 상호작용 요소를 추가하고 싶다면, React에 프로젝트를 다시 작성할 필요가 없습니다. 기존의 스택에 React를 추가하고 어디에서나 상호작용할 수 있는 React 컴포넌트를 렌더링하세요. +기존 프로젝트에 상호작용 요소를 일부 추가하고 싶다면, React로 다시 작성할 필요가 없습니다. 기존 스택에 React를 추가하고 상호작용할 수 있는 React 컴포넌트를 어디에서나 렌더링하세요. </Intro> <Note> -**로컬 개발환경에 [Node.js](https://nodejs.org/en/)를 설치해야 합니다.** 온라인에서 [try React](/learn/installation#try-react)를 실행하거나 간단한 HTML에서도 React를 사용할 수 있지만, 현실적으로 개발을 위해 사용하는 대부분의 JavaScript 도구는 Node.js가 필요합니다. +**로컬 개발 환경에 [Node.js](https://nodejs.org/en/)를 설치해야 합니다.** 온라인에서 [React](/learn/installation#try-react)를 시도하거나 간단한 HTML에서 React를 사용할 수도 있지만, 현실적인 개발을 위해 사용하는 대부분의 자바스크립트 도구에는 Node.js가 필요합니다. </Note> -## 기존 웹사이트의 전체 하위 경로에 React 사용하기 {/*using-react-for-an-entire-subroute-of-your-existing-website*/} +## 기존 웹사이트의 하위 경로 전체에 React 사용하기 {/*using-react-for-an-entire-subroute-of-your-existing-website*/} -`example.com`이라는 또 다른 서버 기술 (Rails와 같은) 로 빌드한 기존 웹 앱이 있고, `example.com/some-app/`으로 시작하는 모든 경로를 React로 완전히 구현하고 싶다고 가정해 보겠습니다. +`example.com`이라는 또 다른 서버 기술(Rails와 같은)로 빌드한 기존 웹 앱이 있고, `example.com/some-app/`으로 시작하는 모든 경로를 React로 완전히 구현하고 싶다고 가정하겠습니다. 다음과 같이 설정하는 것을 추천합니다. 1. [React 기반 프레임워크](/learn/start-a-new-react-project) 중 하나를 사용하여 **앱의 React 부분을 빌드하세요.** -2. 사용하는 프레임워크 설정에서 **`/some-app` 을 *기본 경로*로 명시하세요.** (방법은 다음과 같습니다. [Next.js](https://nextjs.org/docs/api-reference/next.config.js/basepath), [Gatsby](https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting/path-prefix/)) -3. **서버 또는 프록시를 구성**하여 `/some-app/` 아래의 모든 요청이 React 애플리케이션에서 처리되도록 하세요. +2. 사용하는 프레임워크 설정에서 **`/some-app` 을 *기본 경로*<sup>*Base Path*</sup>로 명시하세요**. (이때, [Next.js](https://nextjs.org/docs/api-reference/next.config.js/basepath), [Gatsby](https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting/path-prefix/)를 사용하세요!) +3. **서버 또는 프록시를 구성**하여 `/some-app/` 하위의 모든 요청이 React 애플리케이션에서 처리되도록 하세요. -이는 앱의 React 부분이 이러한 프레임워크에 내장된 [최고의 사례들로부터 이점을 얻을 수 있습니다.](/learn/start-a-new-react-project#can-i-use-react-without-a-framework) +이는 앱의 React 부분이 이러한 프레임워크에 내장된 [최고의 사례들<sup>Best Practices</sup>로부터 이점을 얻을 수 있습니다.](/learn/start-a-new-react-project#can-i-use-react-without-a-framework) -많은 React 기반의 프레임워크는 풀스택이며 React 앱이 서버를 활용할 수 있도록 합니다. 그러나 서버에서 JavaScript를 실행할 수 없거나 실행하고 싶지 않은 경우에도 동일한 접근방식을 사용할 수 있습니다. 이러한 경우에는 HTML/CSS/JS 내보내기(Next.js의 경우 [`next export` output](https://nextjs.org/docs/advanced-features/static-html-export), Gatsby의 경우 기본값)를 `/some-app/`에서 대신 제공하세요. +많은 React 기반의 프레임워크는 풀스택이며 React 앱이 서버를 활용할 수 있도록 합니다. 그러나 서버에서 자바스크립트를 실행할 수 없거나 실행하고 싶지 않은 경우에도 동일한 접근방식을 사용할 수 있습니다. 이러한 경우에는 HTML/CSS/JS 내보내기(Next.js의 경우 [`next export` output](https://nextjs.org/docs/advanced-features/static-html-export), Gatsby의 경우 기본값)를 `/some-app/`에서 대신 제공하세요. ## 기존 페이지의 일부분에 React 사용하기 {/*using-react-for-a-part-of-your-existing-page*/} -이미 다른 기술(Rails와 같은 서버 기술 또는 Backbone과 같은 클라이언트 기술)로 빌드된 기존 페이지가 있고 해당 페이지 어딘가에 상호작용할 수 있는 React 컴포넌트를 렌더링하고 싶다고 가정해 봅시다. 이는 React 컴포넌트를 통합하는 일반적인 방식입니다.-- 실제로 수년 동안 Meta에서 대부분의 React 사용을 이런 식으로 하였습니다! +이미 다른 기술(Rails와 같은 서버 기술 또는 Backbone과 같은 클라이언트 기술)로 빌드된 기존 페이지가 있고, 해당 페이지 어딘가에 상호작용할 수 있는 React 컴포넌트를 렌더링하고 싶다고 가정하겠습니다. 이는 React 컴포넌트를 통합하는 일반적인 방식입니다. 실제로 수년 동안 Meta에서 대부분의 React 사용을 이런 식으로 하였습니다! 이 방식은 두 가지 단계로 수행할 수 있습니다. -1. [JSX 문법](/learn/writing-markup-with-jsx)을 사용할 수 있게 **JavaScript 환경을 설정**하고 [`import`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/import) / [`export`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/export) 문법을 통해 코드를 모듈로 분리한 다음 [npm](https://www.npmjs.com/) 패키지 레지스트리의 패키지(예시: React)를 사용하세요. +1. [JSX 구문](/learn/writing-markup-with-jsx)을 사용할 수 있게 **자바스크립트 환경을 설정**하고, [`import`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/import) / [`export`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/export) 구문을 통해 코드를 모듈로 분리한 다음, [npm](https://www.npmjs.com/) 패키지 레지스트리에서 패키지(예시: React)를 사용하세요. -2. 해당 페이지에서 보고 싶은 곳에 **React 컴포넌트를 렌더링하세요.** +2. 해당 페이지에서 원하는 위치에 **React 컴포넌트를 렌더링하세요.** 정확한 접근 방식은 기존 페이지의 설정에 따라 다르기 때문에, 몇 가지 세부 사항을 함께 살펴보겠습니다. -### 1단계 : 모듈 JavaScript 환경 설정하기 {/*step-1-set-up-a-modular-javascript-environment*/} +### 1단계: 모듈 자바스크립트 환경 설정하기 {/*step-1-set-up-a-modular-javascript-environment*/} -모듈 JavaScript 환경은 모든 코드를 한 파일에 작성하는 것이 아닌 각각의 React 컴포넌트를 개별 파일로 작성할 수 있게 합니다. 또한 React 자체를 포함한 다른 개발자들이 [npm](https://www.npmjs.com/) 레지스트리에 배포한 모든 훌륭한 패키지들을 사용할 수 있습니다. 이 방법은 기존 설정에 따라 다르게 진행될 것입니다. +모듈 자바스크립트 환경은 모든 코드를 한 파일에 작성하는 것이 아닌, 각각의 React 컴포넌트를 개별 파일로 작성할 수 있게 합니다. 또한 (React 자체를 포함한) 다른 개발자들이 [npm](https://www.npmjs.com/) 레지스트리에 배포한 훌륭한 패키지들을 모두 사용할 수 있습니다. 이 작업을 수행하는 방법은 기존 설정에 따라 다릅니다. -* **이미 애플리케이션이 `import` 문법을 이용해 파일로 분리하고 있다면** 기존에 가지고 있는 설정을 이용해 보세요. JS 코드에서 `<div />`를 작성하면 문법 오류가 발생하는지 확인해 보세요. 문법 오류가 발생한다면 [Babel을 이용한 JavaScript 코드 변환](https://babeljs.io/setup)이 필요할 수 있으며 JSX를 사용하려면 [Babel React 프리셋](https://babeljs.io/docs/babel-preset-react)을 활성화해야 할 수 있습니다. +* **이미 애플리케이션이 `import` 문을 이용해 파일로 분리하고 있다면** 기존에 가지고 있는 설정을 이용해 보세요. JS 코드에서 `<div />`를 작성하면 문법 오류가 발생하는지 확인해 보세요. 문법 오류가 발생한다면 [Babel을 이용한 자바스크립트 코드 변환](https://babeljs.io/setup)이 필요할 수 있으며, JSX를 사용하려면 [Babel React 프리셋](https://babeljs.io/docs/babel-preset-react)을 활성화해야 할 수도 있습니다. -* **애플리케이션이 JavaScript 모듈을 컴파일하기 위한 기존 설정이 없다면,** [Vite](https://vitejs.dev/)를 이용하여 설정하세요. Vite 커뮤니티는 Rails, Django, Laravel을 포함한 [다양한 백엔드 프레임워크와의 통합](https://github.com/vitejs/awesome-vite#integrations-with-backends)을 지원하고 있습니다. 사용 중인 백엔드 프레임워크가 목록에 없다면 [이 가이드를 참고하여](https://vitejs.dev/guide/backend-integration.html) Vite 빌드를 백엔드와 수동으로 통합하세요. +* **애플리케이션이 자바스크립트 모듈을 컴파일하기 위한 기존 설정이 없다면,** [Vite](https://vitejs.dev/)를 이용하여 설정하세요. Vite 커뮤니티는 Rails, Django, Laravel을 포함한 [다양한 백엔드 프레임워크와의 통합](https://github.com/vitejs/awesome-vite#integrations-with-backends)을 지원하고 있습니다. 사용 중인 백엔드 프레임워크가 목록에 없다면 [가이드를 참고하여](https://vitejs.dev/guide/backend-integration.html) Vite 빌드를 백엔드와 수동으로 통합하세요. -설정이 제대로 작동하는지 확인하려면 프로젝트 폴더에서 아래 커맨드를 실행하세요. +설정이 제대로 동작하는지 확인하려면 프로젝트 폴더에서 아래 명령어를 실행하세요. <TerminalBlock> npm install react react-dom </TerminalBlock> -그리고 메인 JavaScript 파일(`index.js` 혹은 `main.js`라고 불리는 파일일 수 있습니다.)의 최상단에 다음 코드 라인을 추가하세요. +그리고 메인 자바스크립트 파일(`index.js` 혹은 `main.js`라는 파일일 수 있습니다.)의 최상단에 다음 코드 라인을 추가하세요. <Sandpack> @@ -81,17 +81,18 @@ root.render(<h1>Hello, world</h1>); </Sandpack> -페이지의 전체 내용이 "Hello, world!"로 바뀌었다면 모든 것이 정상적으로 작동하고 있는 겁니다! 계속해서 읽어보세요. +페이지의 전체 내용이 "Hello, world!"로 바뀌었다면 모든 것이 정상적으로 동작하고 있는 겁니다! 계속해서 읽어보세요. <Note> -처음으로 기존 프로젝트에 모듈 JavaScript 환경을 통합하기는 다소 어려워 보일 수 있으나 그만한 가치가 있는 일입니다! 어려움을 겪는 부분이 있다면 우리의 [커뮤니티 리소스](/community)나 [Vite 채팅](https://chat.vitejs.dev/)을 이용해 보세요. +처음으로 기존 프로젝트에 모듈 자바스크립트 환경을 통합하기는 다소 어려워 보일 수 있으나, 그만한 가치가 있는 일입니다! 어려움을 겪는 부분이 있다면 [커뮤니티 리소스](/community)나 [Vite 채팅](https://chat.vitejs.dev/)을 이용해 보세요. </Note> -### 2단계 : 페이지 어디에서든 React 컴포넌트 렌더링하기 {/*step-2-render-react-components-anywhere-on-the-page*/} -이전 단계에서는, 메인 파일 최상단에 이 코드를 넣었습니다. +### 2단계: 페이지 어디에서든 React 컴포넌트 렌더링하기 {/*step-2-render-react-components-anywhere-on-the-page*/} + +이전 단계에서는, 메인 파일 최상단에 아래 코드를 넣었습니다. ```js import { createRoot } from 'react-dom/client'; @@ -108,7 +109,7 @@ root.render(<h1>Hello, world</h1>); 이 코드를 삭제하세요. -대신 React 컴포넌트를 HTML의 특정 위치에 렌더링하고 싶을 것입니다. HTML 페이지를 열고(또는 이를 생성하는 서버 템플릿) HTML 태그에 고유한 `id` 어트리뷰트를 추가하세요. +대신 React 컴포넌트를 HTML의 특정 위치에 렌더링하고 싶을 것입니다. HTML 페이지를 열고(또는 이를 생성하는 서버 템플릿) HTML 태그에 고유한 [`id`](https://developer.mozilla.org/ko/docs/Web/HTML/Global_attributes/id) 어트리뷰트를 추가하세요. ```html <!-- ... html의 어딘가 ... --> @@ -116,7 +117,7 @@ root.render(<h1>Hello, world</h1>); <!-- ... 더 많은 html ... --> ``` -이렇게 하면 [`document.getElementById`](https://developer.mozilla.org/ko/docs/Web/API/Document/getElementById)로 HTML 엘리먼트를 찾아서 [`createRoot`](/reference/react-dom/client/createRoot)에 전달함으로써 해당 요소 내부에 React 컴포넌트를 렌더링할 수 있습니다. +이렇게 하면 [`document.getElementById`](https://developer.mozilla.org/ko/docs/Web/API/Document/getElementById)로 HTML 엘리먼트를 찾아 [`createRoot`](/reference/react-dom/client/createRoot)에 전달함으로써 해당 요소 내부에 React 컴포넌트를 렌더링할 수 있습니다. <Sandpack> @@ -147,10 +148,10 @@ root.render(<NavigationBar />); </Sandpack> -기존에 존재하던 'index.html'의 원본 HTML 컨텐츠가 그대로 남아있는 것을 확인할 수 있습니다. 하지만 이제는 `<nav id="navigation">` 안에 개발자가 직접 작성한 `NavigationBar` React 컴포넌트가 나타납니다. 기존 HTML 페이지에서 React 컴포넌트가 렌더링 되는 것에 대하여 더 알아보려면 [`createRoot` 사용법 문서](/reference/react-dom/client/createRoot#rendering-a-page-partially-built-with-react)를 읽어보세요. +기존에 존재하던 `index.html`의 원본 HTML 컨텐츠가 그대로 남아있는 것을 확인할 수 있습니다. 하지만 이제는 `<nav id="navigation">` 안에 개발자가 직접 작성한 `NavigationBar` React 컴포넌트가 나타납니다. 기존 HTML 페이지에서 React 컴포넌트가 렌더링 되는 것에 대하여 더 알아보려면 [`createRoot` 사용법 문서](/reference/react-dom/client/createRoot#rendering-a-page-partially-built-with-react)를 읽어보세요. 기존 프로젝트에서 React를 도입할 때, 일반적으로 작은 상호작용 컴포넌트(예시: 버튼)에서 시작하여 점진적으로 "상위 구조로 확장하면서" 결국에는 전체 페이지가 React로 빌드될 때까지 이 과정을 반복하게 됩니다. 이 지점에 도달한다면 React의 장점을 최대한 활용하기 위해 [React 프레임워크](/learn/start-a-new-react-project)로 마이그레이션하는 것을 권장합니다. ## 기존 네이티브 모바일 앱에서 React Native 사용하기 {/*using-react-native-in-an-existing-native-mobile-app*/} -[React Native](https://reactnative.dev/) 역시 기존 네이티브 앱에 점진적으로 통합할 수 있습니다. 안드로이드(Java 또는 Kotlin)나 iOS(Objective-C 또는 Swift) 앱을 개발하고 있다면,[이 가이드를 참고하여](https://reactnative.dev/docs/integration-with-existing-apps) React Native 화면을 추가해보세요. +[React Native](https://reactnative.dev/) 역시 기존 네이티브 앱에 점진적으로 통합할 수 있습니다. 안드로이드(Java 또는 Kotlin)나 iOS(Objective-C 또는 Swift) 앱을 개발하고 있다면, [가이드를 참고하여](https://reactnative.dev/docs/integration-with-existing-apps) React Native 화면을 추가해보세요. From ba07b3d9dd31671756875e4cb7be2cbe15533b32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Mon, 30 Dec 2024 01:27:43 +0900 Subject: [PATCH 0446/1164] docs: resolve conflict and update `react-compiler.md` --- src/content/learn/react-compiler.md | 285 +++++----------------------- 1 file changed, 48 insertions(+), 237 deletions(-) diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 503bc1e11..5f66d54f8 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -3,50 +3,31 @@ title: React 컴파일러 --- <Intro> -<<<<<<< HEAD -이 페이지는 새로운 실험적 React 컴파일러에 대한 소개와 이를 성공적으로 시도하는 방법을 제공합니다. -======= -This page will give you an introduction to React Compiler and how to try it out successfully. ->>>>>>> 84f29eb20af17e9c154b9ad71c21af4c9171e4a2 +이 페이지는 React 컴파일러에 대한 소개와 이를 성공적으로 시도하는 방법을 제공합니다. </Intro> <Wip> -이 문서는 아직 작업 중입니다. 더 많은 정보는 [React 컴파일러 워킹 그룹 저장소](https://github.com/reactwg/react-compiler/discussions)에서 확인할 수 있으며, React 컴파일러가 더 안정화되면 이 문서에 반영될 것입니다. +이 문서는 아직 작업 중입니다. 더 많은 정보는 [React 컴파일러 워킹 그룹 저장소](https://github.com/reactwg/react-compiler/discussions)에서 확인할 수 있으며, React 컴파일러가 더욱 안정화되면 이 문서에 반영될 것입니다. </Wip> <YouWillLearn> -<<<<<<< HEAD * 컴파일러 시작하기 -* 컴파일러 및 eslint 플러그인 설치 +* 컴파일러 및 ESLint 플러그인 설치 * 문제 해결 -======= -* Getting started with the compiler -* Installing the compiler and ESLint plugin -* Troubleshooting ->>>>>>> 84f29eb20af17e9c154b9ad71c21af4c9171e4a2 </YouWillLearn> <Note> -<<<<<<< HEAD -React 컴파일러는 커뮤니티로부터 초기 피드백을 받기 위해 오픈소스로 공개한 새로운 실험적 컴파일러입니다. 아직 안정적이지 않으며 프로덕션 환경에서는 완전히 준비되지 않았습니다. -React 컴파일러는 React 19 RC를 필요로 합니다. React 19로 업그레이드할 수 없는 경우 [워킹 그룹](https://github.com/reactwg/react-compiler/discussions/6)에 설명된 대로 사용자 공간 캐시 함수 구현을 시도해 볼 수 있습니다. 그러나 이 방법은 권장하지 않으며 가능한 한 React 19로 업그레이드하는 것이 좋습니다. -</Note> - -React 컴파일러는 빌드 타임 전용 도구로 React 앱을 자동으로 최적화합니다. 순수 JavaScript로 동작하며 [React의 규칙](/reference/rules)을 이해하므로 코드를 다시 작성할 필요가 없습니다. - -컴파일러에는 에디터 내에서 분석 결과를 보여주는 [eslint 플러그인](#installing-eslint-plugin-react-compiler)도 포함되어 있습니다. 이 플러그인은 컴파일러와 독립적으로 실행되며, 앱에서 컴파일러를 사용하지 않는 경우에도 사용할 수 있습니다. 모든 React 개발자에게 코드베이스의 품질을 향상하기 위해 이 eslint 플러그인을 사용할 것을 권장합니다. -======= -React Compiler is a new compiler currently in Beta, that we've open sourced to get early feedback from the community. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you’ve followed the [Rules of React](/reference/rules). +React 컴파일러는 커뮤니티로부터 초기 피드백을 받기 위해 오픈소스로 공개한 베타<sup>Beta</sup> 버전의 새로운 컴파일러입니다. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you’ve followed the [Rules of React](/reference/rules). The latest Beta release can be found with the `@beta` tag, and daily experimental releases with `@experimental`. </Note> -React Compiler is a new compiler that we've open sourced to get early feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. +React 컴파일러는 커뮤니티로부터 초기 피드백을 받기 위해 오픈소스로 공개한 새로운 컴파일러입니다. React 컴파일러는 빌드 타임 전용 도구로 React 앱을 자동으로 최적화합니다. 순수 자바스크립트로 동작하며, [React의 규칙](/reference/rules)을 이해하므로 코드를 다시 작성할 필요가 없습니다. -The compiler also includes an [ESLint plugin](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. +컴파일러에는 에디터 내에서 분석 결과를 보여주는 [ESLint 플러그인](#installing-eslint-plugin-react-compiler)도 포함되어 있습니다. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. The compiler is currently released as `beta`, and is available to try out on React 17+ apps and libraries. To install the Beta: @@ -61,37 +42,32 @@ yarn add -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta </TerminalBlock> If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions. ->>>>>>> 84f29eb20af17e9c154b9ad71c21af4c9171e4a2 ### 컴파일러는 무엇을 하나요? {/*what-does-the-compiler-do*/} -React 컴파일러는 애플리케이션을 최적화하기 위해 코드를 자동으로 메모이제이션합니다. 이미 `useMemo`, `useCallback`, `React.memo`와 같은 API를 통해 적용하는 메모이제이션에 익숙할 것입니다. 이러한 API를 사용하면 React에 입력이 변경되지 않았다면 특정 부분을 다시 계산할 필요가 없다고 알릴 수 있어 업데이트 시 작업을 줄일 수 있습니다. 이 방법은 강력하지만 메모이제이션을 적용하는 것을 잊거나 잘못 적용할 수도 있습니다. 이 경우 React가 _의미 있는_ 변경 사항이 없는 UI 일부를 확인해야 하므로 효율적이지 않을 수 있습니다. +React 컴파일러는 애플리케이션을 최적화하기 위해 코드를 자동으로 메모이제이션<sup>Memoization</sup>합니다. 이미 `useMemo`, `useCallback`, `React.memo`와 같은 API를 통한 메모이제이션에 익숙할 것입니다. 이러한 API를 사용하면 React에게 입력이 변경되지 않았다면 특정 부분을 다시 계산할 필요가 없다고 알릴 수 있어 업데이트 시 작업량을 줄일 수 있습니다. 이 방법은 강력하지만 메모이제이션을 적용하는 것을 잊거나 잘못 적용할 수도 있습니다. 이 경우 React가 _의미 있는_ 변경 사항이 없는 UI 일부를 확인해야 하므로 효율적이지 않을 수 있습니다. -컴파일러는 JavaScript와 React의 규칙에 대한 지식을 활용하여 자동으로 컴포넌트와 Hooks 내의 값 또는 값 그룹을 메모이제이션 합니다. 규칙 위반을 감지할 경우 해당 컴포넌트 또는 Hooks를 건너뛰고 다른 코드를 안전하게 컴파일합니다. +컴파일러는 자바스크립트와 React의 규칙에 대한 지식을 활용하여 자동으로 컴포넌트와 Hook 내부의 값 또는 값 그룹을 메모이제이션 합니다. 규칙 위반을 감지할 경우 해당 컴포넌트 또는 Hook을 건너뛰고 다른 코드를 안전하게 컴파일합니다. -<<<<<<< HEAD -이미 코드베이스에 메모이제이션이 잘 되어 있다면, 컴파일러를 통해 주요 성능 향상을 기대하기 어려울 수 있습니다. 그러나 실제로 성능 문제를 일으키는 올바른 의존성을 메모이제이션 하는 것은 수작업으로 처리하기 까다로울 수 있습니다. -======= <Note> React Compiler can statically detect when Rules of React are broken, and safely opt-out of optimizing just the affected components or hooks. It is not necessary for the compiler to optimize 100% of your codebase. </Note> -If your codebase is already very well-memoized, you might not expect to see major performance improvements with the compiler. However, in practice memoizing the correct dependencies that cause performance issues is tricky to get right by hand. ->>>>>>> 84f29eb20af17e9c154b9ad71c21af4c9171e4a2 +이미 코드베이스에 메모이제이션이 잘 되어 있다면, 컴파일러를 통해 주요 성능 향상을 기대하기 어려울 수 있습니다. 그러나 실제로 성능 문제를 일으키는 올바른 의존성<sup>dependencies</sup>을 메모이제이션 하는 것은 직접 처리하기 까다로울 수 있습니다. <DeepDive> -#### React Compiler은 어떤 것을 메모이제이션 하나요? {/*what-kind-of-memoization-does-react-compiler-add*/} +#### React Compiler는 어떤 것을 메모이제이션 하나요? {/*what-kind-of-memoization-does-react-compiler-add*/} React 컴파일러의 초기 릴리즈는 주로 **업데이트 성능 개선**(기존 컴포넌트의 리렌더링)에 초점을 맞추었으므로 다음 두 가지 사용 사례에 중점을 두고 있습니다. 1. **컴포넌트의 연쇄적인 리렌더링 건너뛰기** - * `<Parent />`를 리렌더링하면 `<Parent />`만이 변경되었음에도 불구하고 그 컴포넌트 트리 내의 많은 컴포넌트가 리렌더링되는 경우 + * `<Parent />`를 리렌더링하면 `<Parent />`만이 변경되었음에도 불구하고 그 컴포넌트 트리 내의 여러 컴포넌트가 리렌더링되는 경우. 2. **React 외부에서의 비용이 많이 드는 계산 건너뛰기** - * 데이터가 필요한 컴포넌트나 Hook 내에서 `expensivelyProcessAReallyLargeArrayOfObjects()`를 호출하는 경우 + * 데이터가 필요한 컴포넌트나 Hook 내에서 `expensivelyProcessAReallyLargeArrayOfObjects()`를 호출하는 경우. #### 리렌더링 최적화 {/*optimizing-re-renders*/} -React는 props, state, context와 같은 현재 state에 대한 함수로 UI를 표현할 수 있도록 해줍니다. `useMemo()`, `useCallback()`, `React.memo()`로 수동 메모이제이션을 적용하지 않은 경우에 현재 구현에서 컴포넌트의 state가 변경되면, React는 해당 컴포넌트와 _하위 모든 자식 컴포넌트_ 를 리렌더링합니다. 예를 들어 다음 예시에서는 `<FriendList>`의 state가 변경될 때마다 `<MessageButton>`이 리렌더링됩니다. +React는 Props, State, Context와 같은 현재 State에 대한 함수로 UI를 표현할 수 있도록 해줍니다. `useMemo()`, `useCallback()`, 또는 `React.memo()`로 수동 메모이제이션을 적용하지 않은 경우에 현재 구현에서 컴포넌트의 State가 변경되면, React는 해당 컴포넌트와 <em>하위 모든 자식 컴포넌트</em>를 리렌더링합니다. 예를 들어 다음 예시에서는 `<FriendList>`의 State가 변경될 때마다 `<MessageButton>`이 리렌더링됩니다. ```javascript function FriendList({ friends }) { @@ -110,21 +86,21 @@ function FriendList({ friends }) { ); } ``` -[_React 컴파일러 플레이그라운드에서 이 예시를 확인하세요_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) +[_React 컴파일러 플레이그라운드에서 이 예시를 확인하세요_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA). -React 컴파일러는 상태 변경 시 앱에서 관련된 부분만 리렌더링되도록 수동 메모이제이션과 동등한 기능을 자동으로 적용합니다. 이를 "세분화된 반응성(fine-grained reactivity)"이라고도 부릅니다. 위 예시에서 React 컴파일러는 `friends`가 변경되더라도 `<FriendListCard />`의 반환 값이 재사용될 수 있음을 결정하고, JSX를 재생성하지 않고 `<MessageButton>`의 리렌더링도 피할 수 있습니다. +React 컴파일러는 상태 변경 시 앱에서 관련된 부분만 리렌더링되도록 수동 메모이제이션과 동등한 기능을 자동으로 적용합니다. 이를 "세분화된 반응성<sup>Fine-Grained Reactivity</sup>"이라고도 부릅니다. 위 예시에서 React 컴파일러는 `friends`가 변경되더라도 `<FriendListCard />`의 반환 값이 재사용될 수 있음을 결정하고, JSX를 재생성하지 않고 `<MessageButton>`의 리렌더링도 피할 수 있습니다. #### 비용이 많이 드는 계산 메모이제이션 {/*expensive-calculations-also-get-memoized*/} 컴파일러는 렌더링 도중 비용이 많이 드는 계산에 대해 자동으로 메모이제이션을 적용할 수도 있습니다. ```js -// 컴포넌트나 Hook이 아니기 때문에 React 컴파일러에 의해 **메모이제이션 되지 않습니다** +// 컴포넌트나 Hook이 아니기 때문에 React 컴파일러에 의해 **메모이제이션 되지 않습니다.** function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } -// 컴포넌트이기 때문에 React 컴파일러에 의해 메모이제이션 됩니다 +// 컴포넌트이기 때문에 React 컴파일러에 의해 메모이제이션 됩니다. function TableContainer({ items }) { - // 이 함수 호출은 메모이제이션 될 것입니다 + // 이 함수 호출은 메모이제이션 될 것입니다. const data = expensivelyProcessAReallyLargeArrayOfObjects(items); // ... } @@ -133,78 +109,31 @@ function TableContainer({ items }) { 그러나 `expensivelyProcessAReallyLargeArrayOfObjects`가 실제로 비용이 많이 드는 함수라면 다음과 같은 이유로 React 외부에서 해당 함수의 별도 메모이제이션을 고려해야 할 수도 있습니다. -- React 컴파일러는 React 컴포넌트와 Hooks만 메모이제이션 하며, 모든 함수를 메모이제이션 하지 않습니다. -- React 컴파일러의 메모이제이션은 여러 컴포넌트나 Hooks 사이에서 공유되지 않습니다. +- React 컴파일러는 React 컴포넌트와 Hook만 메모이제이션 하며, 모든 함수를 메모이제이션 하지 않습니다. +- React 컴파일러의 메모이제이션은 여러 컴포넌트나 Hook 사이에서 공유되지 않습니다. 따라서 `expensivelyProcessAReallyLargeArrayOfObjects`가 여러 다른 컴포넌트에서 사용되고 있다면 동일한 아이템이 전달되더라도 비용이 많이 드는 계산이 반복적으로 실행될 수 있습니다. 코드를 더 복잡하게 만들기 전에 먼저 [프로파일링](/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive)을 통해 해당 계산이 실제로 비용이 많이 드는지 확인하는 것이 좋습니다. </DeepDive> -<<<<<<< HEAD -### 컴파일러는 무엇을 가정하나요? {/*what-does-the-compiler-assume*/} - -React 컴파일러는 다음과 같이 가정합니다. - -1. 올바르고 의미 있는 JavaScript 코드로 작성되었습니다. -2. nullable/optional 값과 속성에 접근하기 전에 그 값이 정의되어 있는지 테스트합니다. TypeScript를 사용하는 경우 [`strictNullChecks`](https://www.typescriptlang.org/ko/tsconfig/#strictNullChecks)을 활성화하여 수행합니다. 예를 들어 `if (object.nullableProperty) { object.nullableProperty.foo }`와 같이 처리하거나, 옵셔널 체이닝을 사용하여 `object.nullableProperty?.foo`와 같이 처리합니다. -3. [React의 규칙](/reference/rules)을 따릅니다. - -React 컴파일러는 React의 많은 규칙을 정적으로 검증할 수 있으며, 에러가 감지되면 안전하게 컴파일을 건너뜁니다. 에러를 확인하려면 [`eslint-plugin-react-compiler`](https://www.npmjs.com/package/eslint-plugin-react-compiler)의 설치를 권장합니다. - ### 컴파일러를 시도해 봐야 하나요? {/*should-i-try-out-the-compiler*/} 컴파일러가 여전히 실험적이며 다양한 결함이 있다는 점을 유의하세요. Meta와 같은 회사에서는 이미 프로덕션 환경에서 사용하였지만, 앱의 프로덕션에 컴파일러를 점진적으로 도입할지는 코드베이스의 건강 상태와 [React의 규칙](/reference/rules)을 얼마나 잘 따랐는지에 따라 다를 것입니다. -======= -### Should I try out the compiler? {/*should-i-try-out-the-compiler*/} - -Please note that the compiler is still in Beta and has many rough edges. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). ->>>>>>> 84f29eb20af17e9c154b9ad71c21af4c9171e4a2 -**지금 당장 컴파일러를 사용하기에 급급할 필요는 없습니다. 안정적인 릴리즈에 도달할 때까지 기다려도 괜찮습니다.** 하지만 앱에서 작은 실험을 통해 컴파일러를 시도해 보고 [피드백을 제공](#reporting-issues)하여 컴파일러 개선에 도움을 줄 수 있습니다. +**지금 당장 컴파일러를 사용하기에 급급할 필요는 없습니다. 안정적인 릴리즈에 도달할 때까지 기다려도 괜찮습니다.** 하지만 앱에서의 작은 실험을 통해 컴파일러를 시도해 보고 [피드백을 제공](#reporting-issues)하여 컴파일러 개선에 도움을 줄 수 있습니다. ## 시작하기 {/*getting-started*/} -이 문서 외에도 [React 컴파일러 워킹 그룹](https://github.com/reactwg/react-compiler)을 확인하여 컴파일러에 대한 추가 정보와 논의를 참조하는 것을 권장합니다. - -<<<<<<< HEAD -### 호환성 확인 {/*checking-compatibility*/} - -컴파일러를 설치하기 전에, 먼저 코드베이스가 호환되는지 확인할 수 있습니다. - -<TerminalBlock> -npx react-compiler-healthcheck@experimental -</TerminalBlock> - -이 스크립트는 다음 작업을 수행합니다. - -- 성공적으로 최적화할 수 있는 컴포넌트 수 확인: 숫자가 높을수록 좋습니다. -- `<StrictMode>` 사용 여부 확인: 이를 활성화하고 준수할 경우 [React의 규칙](/reference/rules)을 잘 따르는 가능성이 높습니다. -- 호환되지 않는 라이브러리 사용 여부 확인: 알려진 라이브러리 중에서 컴파일러와 호환되지 않는 라이브러리를 확인합니다. - -예시: - -<TerminalBlock> -Successfully compiled 8 out of 9 components. -StrictMode usage not found. -Found no usage of incompatible libraries. -</TerminalBlock> +현재 문서 외에도 [React 컴파일러 워킹 그룹](https://github.com/reactwg/react-compiler)을 확인하여 컴파일러에 대한 추가 정보와 논의를 참조하는 것을 권장합니다. ### `eslint-plugin-react-compiler` 설치 {/*installing-eslint-plugin-react-compiler*/} -React 컴파일러는 eslint 플러그인도 지원합니다. eslint 플러그인은 컴파일러와 **독립적으로** 사용할 수 있습니다. 즉 컴파일러를 사용하지 않더라도 eslint 플러그인을 사용할 수 있습니다. -======= -### Installing eslint-plugin-react-compiler {/*installing-eslint-plugin-react-compiler*/} - -React Compiler also powers an ESLint plugin. The ESLint plugin can be used **independently** of the compiler, meaning you can use the ESLint plugin even if you don't use the compiler. ->>>>>>> 84f29eb20af17e9c154b9ad71c21af4c9171e4a2 +React 컴파일러는 ESLint 플러그인도 지원합니다. ESLint 플러그인은 컴파일러와 **독립적으로** 사용할 수 있습니다. 즉, 컴파일러를 사용하지 않더라도 ESLint 플러그인을 사용할 수 있습니다. <TerminalBlock> npm install -D eslint-plugin-react-compiler@beta </TerminalBlock> -<<<<<<< HEAD -그런 다음, eslint 구성 파일에 추가하세요. -======= -Then, add it to your ESLint config: +그런 다음, ESLint 설정<sup>Config</sup> 파일에 추가하세요. ```js import reactCompiler from 'eslint-plugin-react-compiler' @@ -222,7 +151,6 @@ export default [ ``` Or, in the deprecated eslintrc config format: ->>>>>>> 84f29eb20af17e9c154b9ad71c21af4c9171e4a2 ```js module.exports = { @@ -235,24 +163,19 @@ module.exports = { } ``` -<<<<<<< HEAD -eslint 플러그인은 에디터에서 React 규칙 위반 사항을 표시합니다. 이 경우 컴파일러가 해당 컴포넌트나 Hook의 최적화를 건너뛰었음을 의미합니다. 이것은 완전히 정상적인 동작이며, 컴파일러는 이를 복구하고 코드베이스의 다른 컴포넌트를 계속해서 최적화할 수 있습니다. - -**모든 eslint 위반 사항을 즉시 수정할 필요는 없습니다.** 자신의 속도에 맞춰 해결하면서 최적화되는 컴포넌트와 Hooks의 수를 늘릴 수 있지만, 컴파일러를 사용하기 전에 모든 것을 수정해야 할 필요는 없습니다. -======= -The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. +ESLint 플러그인은 에디터에서 React의 규칙 위반 사항을 표시합니다. 이 경우 컴파일러가 해당 컴포넌트나 Hook의 최적화를 건너뛰었음을 의미합니다. 이것은 완전히 정상적인 동작이며, 컴파일러는 이를 복구하고 코드베이스의 다른 컴포넌트를 계속해서 최적화할 수 있습니다. <Note> -**You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized, but it is not required to fix everything before you can use the compiler. +**모든 eslint 위반 사항을 즉시 수정할 필요는 없습니다.** 자신의 속도에 맞춰 해결하면서 최적화되는 컴포넌트와 Hook의 수를 늘릴 수 있지만, 컴파일러를 사용하기 전에 모든 것을 수정해야 할 필요는 없습니다. </Note> ->>>>>>> 84f29eb20af17e9c154b9ad71c21af4c9171e4a2 ### 코드베이스에 컴파일러 적용하기 {/*using-the-compiler-effectively*/} #### 기존 프로젝트 {/*existing-projects*/} -컴파일러는 [React의 규칙](/reference/rules)을 따르는 함수 컴포넌트와 Hooks를 컴파일하는 것을 목표로 설계되었습니다. 또한 이러한 규칙을 위반하는 코드도 해당 컴포넌트나 Hooks를 건너뛰는 방식으로 처리할 수 있습니다. 그러나 JavaScript의 유연한 특성으로 인해 컴파일러가 가능한 모든 위반 사항을 잡아내지는 못하며, 가끔 거짓 양성(false positive)으로 컴파일할 수 있습니다. 즉 컴파일러는 React의 규칙을 위반하는 컴포넌트나 Hook을 실수로 컴파일할 수 있어 정의되지 않은 동작으로 이어질 수 있습니다. -따라서 기존 프로젝트에서 컴파일러를 성공적으로 도입하려면, 먼저 제품 코드의 작은 디렉터리에서 실행해 보는 것이 좋습니다. 이를 위해 컴파일러를 특정 디렉터리 세트에서만 실행하도록 구성할 수 있습니다. +컴파일러는 [React의 규칙](/reference/rules)을 따르는 함수 컴포넌트와 Hook을 컴파일하는 것을 목표로 설계되었습니다. 또한 이러한 규칙을 위반하는 코드도 해당 컴포넌트나 Hook을 건너뛰는 방식으로 처리할 수 있습니다. 그러나 자바스크립트의 유연한 특성으로 인해 컴파일러가 가능한 모든 위반 사항을 잡아내지는 못하며, 가끔 거짓 음성<sup>False Negatives</sup>으로 컴파일할 수 있습니다. 즉, 컴파일러는 React의 규칙을 위반하는 컴포넌트나 Hook을 실수로 컴파일할 수 있어 정의되지 않은 동작으로 이어질 수 있습니다. + +따라서 기존 프로젝트에서 컴파일러를 성공적으로 도입하려면, 먼저 제품 코드의 작은 디렉토리에서 실행해 보는 것이 좋습니다. 이를 위해 컴파일러를 특정 디렉토리 집합<sup>Set</sup>에서만 실행하도록 구성할 수 있습니다. ```js {3} const ReactCompilerConfig = { @@ -262,33 +185,12 @@ const ReactCompilerConfig = { }; ``` -<<<<<<< HEAD -드물지만 때에 따라서는 `compilationMode: "annotation"` 옵션을 사용하여 컴파일러를 "opt-in" 모드로 설정할 수도 있습니다. 이 모드에서는 컴파일러가 `"use memo"` 지시어로 주석 처리된 컴포넌트와 Hooks만 컴파일합니다. `annotation` 모드는 초기 사용자를 돕기 위한 임시 모드로, `"use memo"` 지시어를 장기적으로 사용할 의도는 없음을 유의하세요. - -```js {2,7} -const ReactCompilerConfig = { - compilationMode: "annotation", -}; - -// src/app.jsx -export default function App() { - "use memo"; - // ... -} -``` - 컴파일러를 도입하는 데 더 자신감을 가지게 되면, 다른 디렉터리에 대한 커버리지를 확대하고 점진적으로 전체 앱에 적용할 수 있습니다. -======= -When you have more confidence with rolling out the compiler, you can expand coverage to other directories as well and slowly roll it out to your whole app. ->>>>>>> 84f29eb20af17e9c154b9ad71c21af4c9171e4a2 #### 새로운 프로젝트 {/*new-projects*/} -새 프로젝트를 시작할 경우, 기본 동작으로 전체 코드베이스에 컴파일러를 활성화할 수 있습니다. +새 프로젝트를 시작할 경우, 기본 동작으로 전체 코드베이스에서 컴파일러를 활성화할 수 있습니다. -<<<<<<< HEAD -## 사용 방법 {/*installation*/} -======= ### Using React Compiler with React 17 or 18 {/*using-react-compiler-with-react-17-or-18*/} React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17. @@ -325,7 +227,6 @@ Library code can often require more complex patterns and usage of escape hatches Similarly to apps, it is not necessary to fully compile 100% of your components or hooks to see benefits in your library. A good starting point might be to identify the most performance sensitive parts of your library and ensuring that they don't break the [Rules of React](/reference/rules), which you can use `eslint-plugin-react-compiler` to identify. ## Usage {/*installation*/} ->>>>>>> 84f29eb20af17e9c154b9ad71c21af4c9171e4a2 ### Babel {/*usage-with-babel*/} @@ -335,7 +236,7 @@ npm install babel-plugin-react-compiler@beta 컴파일러에는 빌드 파이프라인에서 사용할 수 있는 Babel 플러그인이 포함되어 있습니다. -설치 후에 Babel 구성 파일에 추가하세요. 파이프라인에서 컴파일러가 **먼저** 실행되는 것이 매우 중요합니다. +설치 후 Babel 설정<sup>Config</sup> 파일에 추가하세요. 파이프라인에서 컴파일러가 **먼저** 실행되는 것이 가장 중요합니다. ```js {7} // babel.config.js @@ -351,7 +252,7 @@ module.exports = function () { }; ``` -`babel-plugin-react-compiler`는 다른 Babel 플러그인보다 먼저 실행되어야 합니다. 이는 컴파일러가 사운드 분석(sound analysis)을 위해 입력 소스 정보를 필요로 하기 때문입니다. +`babel-plugin-react-compiler`는 다른 Babel 플러그인보다 먼저 실행되어야 합니다. 이는 컴파일러가 사운드 분석<sup>Sound Analysis</sup>을 위해 입력 소스 정보를 필요로 하기 때문입니다. ### Vite {/*usage-with-vite*/} @@ -379,40 +280,7 @@ export default defineConfig(() => { ### Next.js {/*usage-with-nextjs*/} -<<<<<<< HEAD -Next.js에는 React 컴파일러를 활성화하는 실험적인 구성이 있습니다. 이 구성은 자동으로 Babel이 `babel-plugin-react-compiler`와 함께 설정되도록 보장합니다. - -- React 19 릴리즈 후보 버전을 사용하는 Next.js 카나리(Canary) 버전을 설치하세요. -- `babel-plugin-react-compiler`를 설치하세요. - -<TerminalBlock> -npm install next@canary babel-plugin-react-compiler@experimental -</TerminalBlock> - -그런 다음 `next.config.js`에서 실험적 옵션을 설정하세요. - -```js {4,5,6} -// next.config.js -/** @type {import('next').NextConfig} */ -const nextConfig = { - experimental: { - reactCompiler: true, - }, -}; - -module.exports = nextConfig; -``` - -실험적 옵션을 사용하면 React 컴파일러의 지원을 다음과 같은 곳에서 보장합니다. - -- 앱 라우터 (App Router) -- 페이지 라우터 (Pages Router) -- Webpack (기본) -- Turbopack (`--turbo` 옵션을 통해 활성화) - -======= Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. ->>>>>>> 84f29eb20af17e9c154b9ad71c21af4c9171e4a2 ### Remix {/*usage-with-remix*/} `vite-plugin-babel`을 설치하고 컴파일러의 Babel 플러그인을 추가하세요. @@ -433,7 +301,7 @@ export default defineConfig({ babel({ filter: /\.[jt]sx?$/, babelConfig: { - presets: ["@babel/preset-typescript"], // TypeScript를 사용하는 경우 + presets: ["@babel/preset-typescript"], // TypeScript를 사용하는 경우. plugins: [ ["babel-plugin-react-compiler", ReactCompilerConfig], ], @@ -445,52 +313,11 @@ export default defineConfig({ ### Webpack {/*usage-with-webpack*/} -<<<<<<< HEAD -다음과 같이 React 컴파일러를 위한 자체 로더를 만들 수 있습니다. - -```js -const ReactCompilerConfig = { /* ... */ }; -const BabelPluginReactCompiler = require('babel-plugin-react-compiler'); - -function reactCompilerLoader(sourceCode, sourceMap) { - // ... - const result = transformSync(sourceCode, { - // ... - plugins: [ - [BabelPluginReactCompiler, ReactCompilerConfig], - ], - // ... - }); - - if (result === null) { - this.callback( - Error( - `Failed to transform "${options.filename}"` - ) - ); - return; - } - - this.callback( - null, - result.code, - result.map === null ? undefined : result.map - ); -} - -module.exports = reactCompilerLoader; -``` - -### Expo {/*usage-with-expo*/} - -Expo 앱에서 React Compiler 를 활용하거나 사용하기 위해서는 [Expo's docs](https://docs.expo.dev/preview/react-compiler/) 를 참고해주세요. -======= A community Webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). ### Expo {/*usage-with-expo*/} Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. ->>>>>>> 84f29eb20af17e9c154b9ad71c21af4c9171e4a2 ### Metro (React Native) {/*usage-with-react-native-metro*/} @@ -498,55 +325,39 @@ React Native는 Metro를 통해 Babel을 사용하므로 설치 지침은 [Babel ### Rspack {/*usage-with-rspack*/} -Rspack 앱에서 React Compiler 를 활용하거나 사용하기 위해서는 [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) 를 참고해주세요. +Rspack 앱에서 React 컴파일러를 활용하거나 사용하기 위해서는 [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler)를 참고해주세요. ### Rsbuild {/*usage-with-rsbuild*/} -Rsbuild 앱에서 React Compiler 를 활용하거나 사용하기 위해서는 [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) 를 참고해주세요. +Rsbuild 앱에서 React 컴파일러를 활용하거나 사용하기 위해서는 [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler)를 참고해주세요. ## Troubleshooting {/*troubleshooting*/} 문제를 보고하려면 먼저 [React 컴파일러 플레이그라운드](https://playground.react.dev/)에서 최소한의 재현 사례를 만들어 버그 보고서에 포함하세요. [facebook/react](https://github.com/facebook/react/issues) 저장소에서 이슈를 열 수 있습니다. -React 컴파일러 워킹 그룹에서도 회원으로 신청하여 피드백을 제공할 수 있습니다. [가입에 대한 자세한 내용은 README](https://github.com/reactwg/react-compiler)에서 확인하세요. - -<<<<<<< HEAD -### `(0 , _c) is not a function` 에러 {/*0--_c-is-not-a-function-error*/} +React 컴파일러 워킹 그룹에서도 회원으로 지원하여 피드백을 제공할 수 있습니다. [가입에 대한 자세한 내용은 README](https://github.com/reactwg/react-compiler)에서 확인하세요. -이 에러는 React 19 RC 이상을 사용하지 않을 경우 발생합니다. 이 문제를 해결하려면 먼저 [React 19 RC로 앱을 업그레이드](/blog/2024/04/25/react-19-upgrade-guide)하세요. - -React 19로 업그레이드할 수 없는 경우, [워킹 그룹](https://github.com/reactwg/react-compiler/discussions/6)에서 설명한 대로 사용자 공간 캐시 함수 구현을 시도해 볼 수 있습니다. 그러나 가능하면 React 19로 업그레이드하는 것을 권장합니다. -======= -### What does the compiler assume? {/*what-does-the-compiler-assume*/} +### 컴파일러는 무엇을 가정하나요? {/*what-does-the-compiler-assume*/} -React Compiler assumes that your code: +React 컴파일러는 다음과 같이 가정합니다. -1. Is valid, semantic JavaScript. -2. Tests that nullable/optional values and properties are defined before accessing them (for example, by enabling [`strictNullChecks`](https://www.typescriptlang.org/tsconfig/#strictNullChecks) if using TypeScript), i.e., `if (object.nullableProperty) { object.nullableProperty.foo }` or with optional-chaining `object.nullableProperty?.foo`. -3. Follows the [Rules of React](https://react.dev/reference/rules). +1. 올바르고 의미 있는 자바스크립트 코드로 작성되었습니다. +2. nullable/optional 값과 속성에 접근하기 전에 그 값이 정의되어 있는지 테스트합니다. 예를 들어, TypeScript를 사용하는 경우 [`strictNullChecks`](https://www.typescriptlang.org/ko/tsconfig/#strictNullChecks)을 활성화하여 수행합니다. 즉, `if (object.nullableProperty) { object.nullableProperty.foo }`와 같이 처리하거나, 옵셔널 체이닝<sup>Optional Chaning</sup>을 사용하여 `object.nullableProperty?.foo`와 같이 처리합니다. +3. [React의 규칙](/reference/rules)을 따릅니다. -React Compiler can verify many of the Rules of React statically, and will safely skip compilation when it detects an error. To see the errors we recommend also installing [eslint-plugin-react-compiler](https://www.npmjs.com/package/eslint-plugin-react-compiler). ->>>>>>> 84f29eb20af17e9c154b9ad71c21af4c9171e4a2 +React 컴파일러는 React의 많은 규칙을 정적으로 검증할 수 있으며, 에러가 감지되면 안전하게 컴파일을 건너뜁니다. 에러를 확인하려면 [`eslint-plugin-react-compiler`](https://www.npmjs.com/package/eslint-plugin-react-compiler)의 설치를 권장합니다. ### 컴포넌트가 최적화되었는지 어떻게 알 수 있을까요? {/*how-do-i-know-my-components-have-been-optimized*/} [React Devtools](/learn/react-developer-tools) (v5.0+)에는 React 컴파일러를 내장 지원하며, 컴파일러에 의해 최적화된 컴포넌트 옆에 "Memo ✨" 배지를 표시합니다. -<<<<<<< HEAD ### 컴파일 후 작동하지 않는 문제 {/*something-is-not-working-after-compilation*/} -`eslint-plugin-react-compiler`을 설치한 경우, 컴파일러는 에디터에서 React 규칙 위반 사항을 표시합니다. 이 경우 컴파일러가 해당 컴포넌트나 Hook의 최적화를 건너뛰었음을 의미합니다. 이것은 완전히 정상적인 동작이며, 컴파일러는 이를 복구하고 코드베이스의 다른 컴포넌트를 계속해서 최적화할 수 있습니다. **모든 eslint 위반 사항을 즉시 수정할 필요는 없습니다.** 자신의 속도에 맞춰 해결하면서 최적화되는 컴포넌트와 Hooks의 수를 점진적으로 늘릴 수 있습니다. -======= -### Something is not working after compilation {/*something-is-not-working-after-compilation*/} -If you have eslint-plugin-react-compiler installed, the compiler will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. **You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized. ->>>>>>> 84f29eb20af17e9c154b9ad71c21af4c9171e4a2 -그러나 JavaScript의 유연하고 동적인 특성 때문에 모든 경우를 철저하게 감지하는 것은 불가능합니다. 이러면 버그나 무한 루프와 같은 정의되지 않은 동작이 발생할 수 있습니다. +`eslint-plugin-react-compiler`을 설치한 경우, 컴파일러는 에디터에서 React 규칙 위반 사항을 표시합니다. 이 경우 컴파일러가 해당 컴포넌트나 Hook의 최적화를 건너뛰었음을 의미합니다. 이것은 완전히 정상적인 동작이며, 컴파일러는 이를 복구하고 코드베이스의 다른 컴포넌트를 계속해서 최적화할 수 있습니다. **모든 ESLint 위반 사항을 즉시 수정할 필요는 없습니다.** 자신의 속도에 맞춰 해결하면서 최적화되는 컴포넌트와 Hooks의 수를 점진적으로 늘릴 수 있습니다. + +그러나 자바스크립트의 유연하고 동적인 특성 때문에 모든 경우를 철저하게 감지하는 것은 불가능합니다. 이러면 버그나 무한 루프와 같은 정의되지 않은 동작이 발생할 수 있습니다. -<<<<<<< HEAD -컴파일 후 앱이 제대로 작동하지 않고 eslint 에러도 보이지 않는다면, 컴파일러가 코드를 잘못 컴파일한 것일 수 있습니다. 이를 확인하려면 관련된 컴포넌트나 Hook을 [`"use no memo"` 지시어](#opt-out-of-the-compiler-for-a-component)를 통해 강력하게 제외해 문제를 해결하려고 시도해 보세요. -======= -If your app doesn't work properly after compilation and you aren't seeing any ESLint errors, the compiler may be incorrectly compiling your code. To confirm this, try to make the issue go away by aggressively opting out any component or hook you think might be related via the [`"use no memo"` directive](#opt-out-of-the-compiler-for-a-component). ->>>>>>> 84f29eb20af17e9c154b9ad71c21af4c9171e4a2 +컴파일 후 앱이 제대로 작동하지 않고 ESLint 에러도 보이지 않는다면, 컴파일러가 코드를 잘못 컴파일한 것일 수 있습니다. 이를 확인하려면 관련된 컴포넌트나 Hook을 [`"use no memo"` 지시어](#opt-out-of-the-compiler-for-a-component)를 통해 강력하게 제외해 문제를 해결하려고 시도해 보세요. ```js {2} function SuspiciousComponent() { @@ -565,6 +376,6 @@ function SuspiciousComponent() { 문제를 해결했을 때 지시어를 제거하면 문제가 다시 발생하는지 확인하세요. 그런 다음 [React 컴파일러 플레이그라운드](https://playground.react.dev)를 활용하여 문제를 최소한의 재현 가능한 예시로 단순화해 보거나, 오픈 소스 코드라면 전체 소스 코드를 붙여 넣어 버그 보고서를 공유해주세요. 이를 통해 문제를 파악하고 해결하는 데 도움을 드릴 수 있습니다. -### 기타 문제 {/*other-issues*/} +### 이외의 문제 {/*other-issues*/} -자세한 내용은 https://github.com/reactwg/react-compiler/discussions/7 를 참조해 주세요. +자세한 내용은 https://github.com/reactwg/react-compiler/discussions/7 을 참조해 주세요. From c4514bd2a55e56306f078c628af4695aaeddb572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Mon, 30 Dec 2024 01:31:42 +0900 Subject: [PATCH 0447/1164] chore: add missing newline --- public/.well-known/atproto-did | 2 +- src/content/blog/2024/10/21/react-compiler-beta-release.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/.well-known/atproto-did b/public/.well-known/atproto-did index ad8b0a36b..a73fe2232 100644 --- a/public/.well-known/atproto-did +++ b/public/.well-known/atproto-did @@ -1 +1 @@ -did:plc:uorpbnp2q32vuvyeruwauyhe \ No newline at end of file +did:plc:uorpbnp2q32vuvyeruwauyhe diff --git a/src/content/blog/2024/10/21/react-compiler-beta-release.md b/src/content/blog/2024/10/21/react-compiler-beta-release.md index f5a870b22..ff45fa54d 100644 --- a/src/content/blog/2024/10/21/react-compiler-beta-release.md +++ b/src/content/blog/2024/10/21/react-compiler-beta-release.md @@ -123,4 +123,4 @@ Thanks to [Sathya Gunasekaran](https://twitter.com/_gsathya), [Joe Savona](https [^2]: Thanks [Vaishali Garg](https://www.linkedin.com/in/vaishaligarg09) for leading this study on React Compiler at Meta, and for reviewing this post. -[^3]: After controlling on author tenure, diff length/complexity, and other potential confounding factors. \ No newline at end of file +[^3]: After controlling on author tenure, diff length/complexity, and other potential confounding factors. From ea4fc354decc44f79edabf47c196ea20dd31b945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Mon, 30 Dec 2024 15:38:46 +0900 Subject: [PATCH 0448/1164] docs: resolve conflict in `README.md` --- README.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/README.md b/README.md index 9512dde59..606d4d9d8 100644 --- a/README.md +++ b/README.md @@ -22,17 +22,10 @@ ### 사전 준비 1. Git -<<<<<<< HEAD 1. Node: v16.8.0 이상의 모든 버전 1. Yarn v1(`yarn@1.22.22`): [Yarn 설치 안내](https://yarnpkg.com/lang/en/docs/install/) 참고 1. 포크<sup>Fork</sup>한 개인 저장소 1. 로컬에 클론<sup>Clone</sup>한 [ko.react.dev 저장소](https://github.com/reactjs/ko.react.dev) -======= -1. Node: any version starting with v16.8.0 or greater -1. Yarn: See [Yarn website for installation instructions](https://yarnpkg.com/lang/en/docs/install/) -1. A fork of the repo (for any contributions) -1. A clone of the [react.dev repo](https://github.com/reactjs/react.dev) on your local machine ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc ### 설치 From ff21c195c9912a4dcde67ff7d00842afef305465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Mon, 30 Dec 2024 15:42:34 +0900 Subject: [PATCH 0449/1164] chore: resolve conflict in `sidebarReference.json` --- src/sidebarReference.json | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/sidebarReference.json b/src/sidebarReference.json index ebe359a75..2e9dfe1eb 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -304,7 +304,6 @@ "title": "prerenderToNodeStream", "path": "/reference/react-dom/static/prerenderToNodeStream" } - ] }, { @@ -334,23 +333,12 @@ "sectionHeader": "React 서버 컴포넌트" }, { -<<<<<<< HEAD "title": "서버 컴포넌트", - "path": "/reference/rsc/server-components", - "canary": true - }, - { - "title": "서버 액션", - "path": "/reference/rsc/server-actions", - "canary": true -======= - "title": "Server Components", "path": "/reference/rsc/server-components" }, { - "title": "Server Functions", - "path": "/reference/rsc/server-functions" ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc + "title": "서버 액션", + "path": "/reference/rsc/server-actions" }, { "title": "지시어", From 446273e994d312fbf517a09cf84d58f16a08c382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Mon, 30 Dec 2024 15:47:20 +0900 Subject: [PATCH 0450/1164] chore: delete stale names from `CODEOWNERS` --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index eb881b609..b7e5c36c1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @hg-pyun @taehwanno @simsim0709 @gnujoow @b9words @taggon @MaxKim-J @eomttt @lumirlumir +* @hg-pyun @gnujoow @eomttt @lumirlumir From 00d9e6f594f2ccaeeccf1718820862d07568aaf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Mon, 30 Dec 2024 16:08:16 +0900 Subject: [PATCH 0451/1164] docs: update `versions.md` --- src/content/versions.md | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/content/versions.md b/src/content/versions.md index 07f53a6f8..33d2ad180 100644 --- a/src/content/versions.md +++ b/src/content/versions.md @@ -1,27 +1,22 @@ --- -title: React Versions +title: React 버전 --- <Intro> -[react.dev](https://react.dev)의 React 문서는 최신 버전의 React에 대한 문서를 제공합니다. +[ko.react.dev](/)의 React 문서는 최신 버전의 React에 대한 문서를 제공합니다. </Intro> -주요 버전 내에서 문서를 최신 상태로 유지하기 위해 노력하며 각 소규모 또는 패치 버전에 대한 문서는 게시하지 않습니다. 새로운 주요 버전이 출시되면 이전 버전의 문서는 `x.react.dev`로 보관합니다. 자세한 내용은 [버전 관리 정책](/community/versioning-policy)을 참고하세요. +주<sup>Major, 主</sup> 버전 내에서 문서를 최신 상태로 유지하기 위해 노력하며, 부<sup>Minor, 部</sup> 또는 수<sup>Patch, 修</sup> 버전에 대한 문서는 게시하지 않습니다. 새로운 주<sup>Major, 主</sup> 버전이 출시되면 이전 버전의 문서는 `x.react.dev`로 보관합니다. 자세한 내용은 [버전 관리 정책](/community/versioning-policy)을 참고하세요. -이전 주요 버전의 기록은 아래에서 찾을 수 있습니다. +이전의 주<sup>Major, 主</sup> 버전에 대한 기록은 아래에서 찾을 수 있습니다. -<<<<<<< HEAD -## Future versions {/*future-versions*/} -======= -You can find an archive of previous major versions below. -## Latest version: 19.0 {/*latest-version*/} ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +## 최신 버전: 19.0 {/*latest-version*/} - [react.dev](https://react.dev) {/*docs-19*/} -## Previous versions {/*previous-versions*/} +## 이전 버전 {/*previous-versions*/} - [18.react.dev](https://18.react.dev) {/*docs-18*/} - [17.react.dev](https://17.react.dev) {/*docs-17*/} @@ -32,7 +27,7 @@ You can find an archive of previous major versions below. #### 이전 문서들 {/*legacy-docs*/} -2023년, React 18에 대한 [새로운 문서](/blog/2023/03/16/introducing-react-dev)를 [react.dev](https://react.dev)로 출시했습니다. 기존 React 18 문서는 [legacy.reactjs.org](https://legacy.reactjs.org)에서 볼 수 있습니다. 버전 17 이하의 문서는 기존 사이트에 호스팅됩니다. +2023년, React 18에 대한 [새로운 문서](/blog/2023/03/16/introducing-react-dev)를 [react.dev](https://react.dev)로 출시했습니다. 이전의 React 18 문서는 [legacy.reactjs.org](https://legacy.reactjs.org)에서 볼 수 있습니다. 버전 17 이하의 문서는 이전 사이트에 호스팅됩니다. React 15 이전 버전의 경우, [15.react.dev](https://15.react.dev)를 참고하세요. @@ -296,12 +291,12 @@ React 15 이전 버전의 경우, [15.react.dev](https://15.react.dev)를 참고 - [v0.3.1 (May 2013)](https://github.com/facebook/react/blob/main/CHANGELOG.md#031-may-30-2013) - [v0.3.0 (May 2013)](https://github.com/facebook/react/blob/main/CHANGELOG.md#031-may-30-2013) -### 초기 커밋 {/*initial-commit*/} +### 최초의 커밋 {/*initial-commit*/} -React는 2013년 5월 29일에 오픈소스로 공개되었습니다. 초기 커밋은 다음과 같습니다. [`75897c`: 최초 공개 릴리즈](https://github.com/facebook/react/commit/75897c2dcd1dd3a6ca46284dd37e13d22b4b16b4) +React는 2013년 5월 29일에 오픈소스로 공개되었습니다. 최초의 커밋은 [`75897c`: 최초 공개 릴리즈](https://github.com/facebook/react/commit/75897c2dcd1dd3a6ca46284dd37e13d22b4b16b4)입니다. 첫 블로그 게시글을 참고하세요. [왜 우리는 React를 만들었는가?](https://legacy.reactjs.org/blog/2013/06/05/why-react.html) -React는 2013년에 Facebook 시애틀에서 오픈소스로 공개되었습니다. +React는 2013년에 페이스북<sup>Facebook</sup> 시애틀에서 오픈소스로 공개되었습니다. <iframe width="560" height="315" src="https://www.youtube.com/embed/XxVg_s8xAms?si=466vSJrnXTn05j9A" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> From 5040d2964481235cd4338a8d80160adebe6243cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Mon, 30 Dec 2024 16:53:44 +0900 Subject: [PATCH 0452/1164] docs: update `blog/index.md` --- src/content/blog/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/blog/index.md b/src/content/blog/index.md index da3907b3e..b5bec0f05 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -4,7 +4,7 @@ title: React 블로그 <Intro> -이 블로그는 React 팀에서 업데이트한 내용들의 공식 소스입니다. 릴리스 노트 및 더 이상 사용되지 않는 표현에 대한 알림을 비롯하여 중요한 내용은 이곳에 먼저 공유됩니다. 또, 트위터에서 [@reactjs](https://twitter.com/reactjs) 계정을 팔로우하셔도 좋지만, 이 블로그만으로도 모든 정보를 얻을 수 있습니다. +이 블로그는 React 팀의 업데이트에 대한 공식 출처입니다. 릴리스 노트 및 더 이상 사용되지 않는 기능들에 대한 공지<sup>Deprecation Notice</sup>를 비롯한 중요 내용들이 이곳에 먼저 공유됩니다. 트위터에서 [@reactjs](https://twitter.com/reactjs) 계정을 팔로우해도 좋지만, 이 블로그만으로도 모든 정보를 얻을 수 있습니다. </Intro> @@ -90,7 +90,7 @@ React 팀은 몇 가지 업데이트를 공유하게 되어 기쁩니다. ### 모든 릴리스 노트 {/*all-release-notes*/} -React의 모든 릴리스 내용이 별도의 블로그 게시글로 작성되지는 않지만, 모든 릴리스에 대한 세부 변경 명세는 React 저장소의 [`CHANGELOG.md`](https://github.com/facebook/react/blob/main/CHANGELOG.md) 파일 또는 [Releases](https://github.com/facebook/react/releases) 페이지에서 확인할 수 있습니다. +React의 모든 릴리스 내용이 별도의 블로그 게시글로 작성되지는 않지만, 모든 릴리스에 대한 세부 변경 내역은 React 저장소의 [`CHANGELOG.md`](https://github.com/facebook/react/blob/main/CHANGELOG.md) 파일 또는 [Releases](https://github.com/facebook/react/releases) 페이지에서 확인할 수 있습니다. --- From 5feba882c6be5285c3c0d0e40866c635df9a0b75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Mon, 30 Dec 2024 18:16:02 +0900 Subject: [PATCH 0453/1164] docs: update `data-fetching-with-react-server-components` --- ...data-fetching-with-react-server-components.md | 16 ++++++++-------- src/content/blog/index.md | 4 ++-- src/sidebarBlog.json | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/content/blog/2020/12/21/data-fetching-with-react-server-components.md b/src/content/blog/2020/12/21/data-fetching-with-react-server-components.md index 78709dc61..190461156 100644 --- a/src/content/blog/2020/12/21/data-fetching-with-react-server-components.md +++ b/src/content/blog/2020/12/21/data-fetching-with-react-server-components.md @@ -1,8 +1,8 @@ --- -title: "제로 번들 사이즈 React 서버 컴포넌트 소개" +title: "제로 번들 사이즈 React 서버 컴포넌트를 소개합니다" author: Dan Abramov, Lauren Tan, Joseph Savona, and Sebastian Markbage date: 2020/12/21 -description: 2020년은 긴 한 해였습니다. 연말이 다가옴에 따라 제로 번들 사이즈의 React 서버 컴포넌트 연구에 대한 특별한 홀리데이 업데이트를 공유하고자 합니다. +description: 2020년은 긴 한 해였습니다. 연말이 다가옴에 따라 제로 번들 사이즈의 React 서버 컴포넌트 연구에 대한 특별 연휴 업데이트를 공유하고자 합니다. --- 2020년 12월 21일, [Dan Abramov](https://twitter.com/dan_abramov), [Lauren Tan](https://twitter.com/potetotes), [Joseph Savona](https://twitter.com/en_JS), [Sebastian Markbåge](https://twitter.com/sebmarkbage) @@ -11,24 +11,24 @@ description: 2020년은 긴 한 해였습니다. 연말이 다가옴에 따라 <Intro> -2020년은 긴 한 해였습니다. 연말이 다가옴에 따라 제로 번들 사이즈의 **React 서버 컴포넌트** 연구에 대한 특별한 홀리데이 업데이트를 공유하고자 합니다. +2020년은 긴 한 해였습니다. 연말이 다가옴에 따라 제로 번들 사이즈 **React 서버 컴포넌트** 연구에 대한 특별 연휴 업데이트를 공유하고자 합니다. </Intro> --- -React 서버 컴포넌트를 소개하기 위해 강연과 데모를 준비했습니다. 이는 연휴 기간 또는 새해에 업무가 재개되는 시점에서 확인할 수 있습니다. +React 서버 컴포넌트를 소개하기 위해 강연과 데모를 준비했습니다. 이는 연휴 기간 또는 새해에 업무가 재개되는 시점에 확인할 수 있습니다. <YouTubeIframe src="https://www.youtube.com/embed/TQQPAU21ZUw" /> -**React 서버 컴포넌트는 아직 연구 개발 단계입니다.** 우리는 투명성의 정신으로 React 커뮤니티로부터 초기 피드백을 받기 위해 이 작업을 공유하고 있습니다. 시간이 오래 걸릴 것이므로 **지금 당장 따라잡아야 한다고 느끼지 마세요!** +**React 서버 컴포넌트는 아직 연구 개발 단계입니다.** 투명성을 유지하고 React 커뮤니티로부터 초기 피드백을 받기 위해 작업을 공유하고 있습니다. 시간이 오래 걸릴 것이므로 **지금 당장 따라잡아야 한다고 느끼지 마세요!** -이를 확인하려면 다음과 같은 순서로 진행하시면 됩니다. +이를 확인하기 위해 아래와 같은 순서를 따르는 것을 추천합니다. 1. **강연**을 시청하여 React 서버 컴포넌트에 대해 학습하고 데모를 확인하세요. -2. **[데모를 클론](http://github.com/reactjs/server-components-demo)** 하여 컴퓨터에서 React 서버 컴포넌트를 사용해 보세요. +2. <strong>[데모를 클론](http://github.com/reactjs/server-components-demo)</strong>하여 컴퓨터에서 React 서버 컴포넌트를 사용해 보세요. -3. 자세한 기술 분석과 피드백을 제공하려면 **[RFC 확인하기(FAQ가 마지막에 포함되어 있습니다)](https://github.com/reactjs/rfcs/pull/188)** 를 참조하세요. +3. 자세한 기술 분석과 피드백 제공을 위해 <strong>[RFC(FAQ가 마지막에 포함되어 있습니다)](https://github.com/reactjs/rfcs/pull/188)</strong>를 읽어보세요. RFC 또는 [@reactjs](https://twitter.com/reactjs) 트위터 계정에서 여러분의 의견을 기다리겠습니다. 즐거운 연말연시 안전하게 보내시고 내년에 뵙겠습니다! diff --git a/src/content/blog/index.md b/src/content/blog/index.md index b5bec0f05..f412442b6 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -80,8 +80,8 @@ React 팀은 몇 가지 업데이트를 공유하게 되어 기쁩니다. - 라이브러리 작성자가 사용해 보고 피드백을 제공할 수 있도록 React 18 알파를 게시했습니다. </BlogCard> -<BlogCard title="제로 번들 사이즈 React 서버 컴포넌트 소개" date="2020년 12월 21일" url="/blog/2020/12/21/data-fetching-with-react-server-components"> -2020년은 긴 한 해였습니다. 연말이 다가옴에 따라 제로 번들 사이즈의 React 서버 컴포넌트 연구에 대한 특별한 홀리데이 업데이트를 공유하고자 합니다. React 서버 컴포넌트를 소개하기 위해 강연과 데모를 준비했습니다. 이는 연휴 기간 또는 새해에 업무가 재개되는 시점에서 확인할 수 있습니다. +<BlogCard title="제로 번들 사이즈 React 서버 컴포넌트를 소개합니다" date="2020년 12월 21일" url="/blog/2020/12/21/data-fetching-with-react-server-components"> +2020년은 긴 한 해였습니다. 연말이 다가옴에 따라 제로 번들 사이즈의 React 서버 컴포넌트 연구에 대한 특별 연휴 업데이트를 공유하고자 합니다. React 서버 컴포넌트를 소개하기 위해 강연과 데모를 준비했습니다. 이는 연휴 기간 또는 새해에 업무가 재개되는 시점에 확인할 수 있습니다. </BlogCard> </div> diff --git a/src/sidebarBlog.json b/src/sidebarBlog.json index 01923387c..8ff8995c1 100644 --- a/src/sidebarBlog.json +++ b/src/sidebarBlog.json @@ -110,7 +110,7 @@ "path": "/blog/2021/06/08/the-plan-for-react-18" }, { - "title": "제로 번들 사이즈 React 서버 컴포넌트 소개", + "title": "제로 번들 사이즈 React 서버 컴포넌트를 소개합니다", "titleForHomepage": "서버 컴포넌트 소개", "icon": "labs", "date": "2020.12.21", From 1a8f84bafe91318c468d9579ee40c0488bdf7419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Mon, 30 Dec 2024 18:57:46 +0900 Subject: [PATCH 0454/1164] docs: update `the-plan-for-react-18.md` --- .../blog/2021/06/08/the-plan-for-react-18.md | 44 +++++++++---------- src/content/blog/index.md | 4 +- src/content/community/versioning-policy.md | 2 +- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/content/blog/2021/06/08/the-plan-for-react-18.md b/src/content/blog/2021/06/08/the-plan-for-react-18.md index e87d9740e..36f1d8e9b 100644 --- a/src/content/blog/2021/06/08/the-plan-for-react-18.md +++ b/src/content/blog/2021/06/08/the-plan-for-react-18.md @@ -1,8 +1,8 @@ --- -title: "React 18 계획" +title: "React 18에 대한 계획" author: Andrew Clark, Brian Vaughn, Christine Abernathy, Dan Abramov, Rachel Nabors, Rick Hanlon, Sebastian Markbage, and Seth Webster date: 2021/06/08 -description: React 팀은 몇 가지 업데이트를 공유하게 되어 기쁩니다. 다음 주요 버전이 될 React 18 릴리즈에 대한 작업을 시작했습니다. 커뮤니티가 React 18의 새로운 기능을 점진적으로 채택할 수 있도록 준비하기 위해 워킹 그룹을 만들었습니다. 라이브러리 작성자가 사용해 보고 피드백을 제공할 수 있도록 React 18 알파를 게시했습니다... +description: React 팀은 몇 가지 업데이트를 공유하게 되어 기쁩니다. 다음 주요 버전이 될 React 18 릴리즈에 대한 작업을 시작했습니다. 커뮤니티가 React 18의 새로운 기능을 점진적으로 채택할 수 있도록 준비하기 위해 워킹 그룹을 만들었습니다. 라이브러리 작성자가 사용해 보고 피드백을 제공할 수 있도록 React 18 Alpha를 게시했습니다... --- 2021년 6월 8일, [Andrew Clark](https://twitter.com/acdlite), [Brian Vaughn](https://github.com/bvaughn), [Christine Abernathy](https://twitter.com/abernathyca), [Dan Abramov](https://twitter.com/dan_abramov), [Rachel Nabors](https://twitter.com/rachelnabors), [Rick Hanlon](https://twitter.com/rickhanlonii), [Sebastian Markbåge](https://twitter.com/sebmarkbage), [Seth Webster](https://twitter.com/sethwebster) @@ -13,11 +13,11 @@ description: React 팀은 몇 가지 업데이트를 공유하게 되어 기쁩 React 팀은 몇 가지 업데이트를 공유하게 되어 기쁩니다. -1. 다음 주요 버전이 될 React 18 릴리즈에 대한 작업을 시작했습니다. -2. 커뮤니티가 React 18의 새로운 기능을 점진적으로 채택할 수 있도록 준비하기 위해 워킹 그룹을 만들었습니다. -3. 라이브러리 작성자가 사용해 보고 피드백을 제공할 수 있도록 React 18 알파를 게시했습니다. +1. 다음번 주<sup>Major, 主</sup> 버전이 될 React 18 릴리즈에 대한 작업을 시작했습니다. +2. 커뮤니티가 React 18의 새로운 기능을 점진적으로 채택할 수 있도록 준비하기 위해 워킹 그룹<sup>Working Group</sup>을 만들었습니다. +3. 라이브러리 작성자가 사용해 보고 피드백을 제공할 수 있도록 React 18 Alpha를 게시했습니다. -이 업데이트는 주로 서드파티 라이브러리 관리자를 대상으로 합니다. React를 배우거나 가르치거나 사용자 애플리케이션을 빌드하는 데 사용하는 경우 이 게시물을 무시해도 됩니다. 하지만 궁금한 점이 있으시다면 React 18 워킹 그룹에서 토론을 따라가셔도 좋습니다! +이번 업데이트는 주로 서드파티<sup>Third Party</sup> 라이브러리 관리자를 대상으로 합니다. React를 배우거나 가르치거나, 혹은 사용자 애플리케이션을 빌드하는 데 사용하는 경우 이 게시물을 무시해도 됩니다. 하지만 궁금한 점이 있으시다면 React 18 워킹 그룹의 토론에 참여하셔도 좋습니다! --- @@ -25,47 +25,47 @@ React 팀은 몇 가지 업데이트를 공유하게 되어 기쁩니다. ## React 18의 새로운 기능 {/*whats-coming-in-react-18*/} -React 18이 출시되면 [자동 일괄 처리](https://github.com/reactwg/react-18/discussions/21)와 같은 즉시 사용한 개선 사항 및 [`startTransition`](https://github.com/reactwg/react-18/discussions/41)과 같은 새로운 API, `React.lazy`를 기본으로 지원하는 [새로운 스트리밍 서버 렌더러](https://github.com/reactwg/react-18/discussions/37)가 포함될 예정입니다. +React 18이 출시되면 [자동 일괄 처리<sup>Automatic Batching</sup>](https://github.com/reactwg/react-18/discussions/21)와 같은 기본 개선 사항 및 [`startTransition`](https://github.com/reactwg/react-18/discussions/41)과 같은 새로운 API, `React.lazy`를 기본적으로 지원하는 [새로운 스트리밍 서버 렌더러<sup>Streaming Server Renderer</sup>](https://github.com/reactwg/react-18/discussions/37)가 포함될 예정입니다. -이러한 기능은 React 18에 추가되는 새로운 옵트인 메커니즘 덕분에 가능합니다. 이를 "동시 렌더링"이라고 하며, 이 기능을 통해 React는 동시에 여러 버전의 UI를 준비할 수 있습니다. 이 변경 사항은 대부분 보이지 않지만, 앱의 실제 성능과 체감 성능을 모두 개선할 수 있는 새로운 가능성을 열어줍니다. +이러한 기능들은 React 18에 추가될 새로운 선택적<sup>Opt-In</sup> 메커니즘 덕분에 가능해졌습니다. 이를 "동시 렌더링<sup>Concurrent Rendering</sup>"이라고 하며, 이 기능을 통해 React는 동시에 여러 버전의 UI를 준비할 수 있습니다. 이러한 변경 사항들은 대부분 직접 볼 수는 없지만, 앱의 실제 성능과 체감 성능을 모두 개선할 수 있는 새로운 가능성을 열어줍니다. -React의 미래에 대한 저희의 연구를 계속 지켜보셨다면(그럴 필요는 없습니다!) "동시 모드"라는 기능에 대해 들어보셨거나 앱이 손상될 수 있다는 이야기를 들어보셨을 것입니다. 이러한 커뮤니티의 피드백을 반영하여 점진적인 도입을 위해 업그레이드 전략을 재설계했습니다. "모드"를 모두 사용하거나 사용하지 않는 대신, 동시 렌더링은 새로운 기능 중 하나에 의해 트리거되는 업데이트에 대해서만 활성화됩니다. 즉, **실제로는 재작성 없이 React 18을 도입하고 자신의 속도에 맞춰 새로운 기능을 사용해 볼 수 있습니다**. +React의 미래에 대한 저희들의 연구를 계속 지켜보셨다면(물론, 그럴 필요는 없습니다!), "동시 모드<sup>Concurrent Mode</sup>"라는 기능에 대해 들어보셨거나, 그것이 여러분들의 앱을 망칠 수 있다는 이야기를 들으셨을 수도 있습니다. 이러한 커뮤니티의 피드백을 반영하여 점진적인 도입을 위한 업그레이드 전략을 재설계했습니다. "모드"를 모두 사용하거나 사용하지 않는 대신, 동시 렌더링<sup>Concurrent Rendering</sup>은 새로운 기능 중 하나에 의해 트리거되는 업데이트에 대해서만 활성화됩니다. 즉, **재작성 없이 React 18을 도입하고 자신의 속도에 맞춰 새로운 기능들을 사용해 볼 수 있습니다**. ## 점진적인 도입 전략 {/*a-gradual-adoption-strategy*/} -React 18의 동시성은 옵트인 방식이므로 컴포넌트 동작에 대한 중요한 변경 사항은 없습니다. **애플리케이션 코드를 거의 또는 전혀 변경하지 않고도 일반적인 주요 React 릴리즈와 비슷한 수준의 노력으로 React 18로 업그레이드할 수 있습니다**. 여러 앱을 React 18로 전환한 경험에 비추어 볼 때, 많은 사용자가 하루 오후 안에 업그레이드할 수 있을 것으로 예상합니다. +React 18의 동시성은 선택적<sup>Opt-In</sup>이므로 컴포넌트 동작에 대한 중요 변경 사항<sup>Breaking Changes</sup>은 없습니다. **애플리케이션 코드를 거의 또는 전혀 변경하지 않고도, 일반적인 주요 React 릴리즈와 비슷한 수준의 노력으로 React 18로 업그레이드할 수 있습니다**. 여러 앱을 React 18로 전환한 경험에 비추어 볼 때, 많은 사용자가 반나절 안에 업그레이드할 수 있을 것으로 예상합니다. -우리는 Facebook에서 수만 개의 컴포넌트에 동시 기능을 성공적으로 제공했으며, 경험상 대부분의 React 컴포넌트가 추가 변경 없이 "바로 작동"하는 것으로 나타났습니다. 전체 커뮤니티를 위한 원활한 업그레이드가 될 수 있도록 최선을 다하고 있으며, 오늘 React 18 워킹 그룹을 발표합니다. +우리는 페이스북<sup>Facebook</sup>에서 수만 개의 컴포넌트에 동시성 기능들을 성공적으로 배포했으며, 경험상 대부분의 React 컴포넌트가 추가 변경 없이 "바로 작동"하였습니다. 커뮤니티 전체를 위한 원활한 업그레이드가 될 수 있도록 최선을 다하고 있으며, 오늘 React 18 워킹 그룹을 발표합니다. ## 커뮤니티와의 협력 {/*working-with-the-community*/} -이번 릴리즈에서는 새로운 시도를 하고 있습니다. React 커뮤니티의 전문가, 개발자, 라이브러리 작성자, 교육자들로 구성된 패널을 [React 18 워킹 그룹](https://github.com/reactwg/react-18)에 초대하여 피드백을 제공하고, 질문하고, 릴리즈에 대해 협업할 수 있도록 했습니다. 이번 소규모 그룹에는 원하는 모든 분을 초대할 수는 없었지만, 이 실험이 성공한다면 앞으로 더 많은 분을 초대할 수 있기를 바랍니다! +이번 릴리즈에서는 새로운 시도를 하고 있습니다. React 커뮤니티의 전문가, 개발자, 라이브러리 작성자, 교육자들로 구성된 패널을 [React 18 워킹 그룹](https://github.com/reactwg/react-18)에 초대하여 피드백을 제공하고, 질문하고, 릴리즈에 대해 협업할 수 있도록 했습니다. 이번 소규모 그룹에 원하는 모든 분들을 초대할 수는 없었지만, 이번 실험이 성공하여 앞으로 더 많은 분을 초대할 수 있기를 바랍니다! -**React 18 워킹 그룹의 목표는 기본 애플리케이션과 라이브러리가 React 18을 원활하고 점진적으로 채택할 수 있도록 생태계를 준비하는 것입니다.** 워킹 그룹은 [GitHub 토론](https://github.com/reactwg/react-18/discussions)에서 호스팅되며, 일반인도 열람할 수 있습니다. 워킹 그룹의 구성원은 피드백을 남기고, 질문하고, 아이디어를 공유할 수 있습니다. 핵심 팀도 토론 리포지토리를 사용하여 연구 결과를 공유할 것입니다. 안정 버전 출시가 가까워지면 중요한 정보도 이 블로그에 게시될 예정입니다. +**React 18 워킹 그룹의 목표는 기본 애플리케이션과 라이브러리가 React 18을 원활하고 점진적으로 채택할 수 있는 생태계를 준비하는 것입니다.** 워킹 그룹은 [깃허브 토론<sup>GitHub Discussions</sup>](https://github.com/reactwg/react-18/discussions)에서 호스팅되며, 일반인도 열람할 수 있습니다. 워킹 그룹의 구성원은 피드백을 남기고, 질문하고, 아이디어를 공유할 수 있습니다. 핵심 팀도 토론 저장소<sup>Repository</sup>를 사용하여 연구 결과를 공유할 것입니다. 안정적인 버전의 출시가 가까워지면, 중요 정보들을 블로그에 게시할 것입니다. -React 18로 업그레이드하는 방법이나 릴리즈에 대한 추가 리소스에 대한 자세한 내용은 [React 18 발표 게시물](https://github.com/reactwg/react-18/discussions/4)을 참고하세요. +React 18로 업그레이드하는 방법이나, 릴리즈에 대한 추가적인 정보들은 [React 18 발표 게시물](https://github.com/reactwg/react-18/discussions/4)을 참고하세요. ## React 18 워킹 그룹에 접근하기 {/*accessing-the-react-18-working-group*/} -누구나 [React 18 워킹 그룹 리포지토리](https://github.com/reactwg/react-18)에서 토론 내용을 읽을 수 있습니다. +누구나 [React 18 워킹 그룹 저장소](https://github.com/reactwg/react-18)에서 토론 내용을 읽을 수 있습니다. -워킹 그룹에 대한 초기 관심이 급증할 것으로 예상되므로 초대받은 회원만 스레드를 만들거나 댓글을 달 수 있습니다. 그러나 토론글은 모든 사람에게 완전히 공개되므로 모든 사람이 동일한 정보에 접근할 수 있습니다. 이는 워킹 그룹 구성원을 위한 생산적인 환경을 조성하는 동시에 더 많은 커뮤니티와의 투명성을 유지하는 좋은 절충안이라고 생각합니다. +워킹 그룹에 대한 초기 관심이 급증할 것으로 예상되므로, 초대받은 회원만 스레드를 만들거나 댓글을 달 수 있습니다. 그러나, 토론글은 모든 사람에게 완전히 공개되므로 모든 사람이 동일한 정보에 접근할 수 있습니다. 이는 워킹 그룹 구성원을 위한 생산적인 환경을 조성하는 동시에 더 많은 커뮤니티와의 투명성을 유지하는 좋은 절충안이라 생각합니다. 언제나 그렇듯이 [이슈 트래커](https://github.com/facebook/react/issues)에 버그 보고서, 질문 및 일반적인 피드백을 제출할 수 있습니다. -## 지금 React 18 알파를 사용해 보는 방법 {/*how-to-try-react-18-alpha-today*/} +## 지금 React 18 Alpha를 사용하는 방법 {/*how-to-try-react-18-alpha-today*/} -새로운 알파는 [정기적으로 `@alpha` 태그를 사용하여 npm에 게시됩니다](https://github.com/reactwg/react-18/discussions/9). 이러한 릴리즈는 메인 리포지토리에 대한 가장 최근 커밋을 사용하여 빌드됩니다. 기능이나 버그 수정이 병합되면 다음 주일에 알파에 표시됩니다. +새로운 Alpha는 [정기적으로 `@alpha` 태그를 통해 npm에 배포됩니다](https://github.com/reactwg/react-18/discussions/9). 이러한 릴리즈는 메인 저장소<sup>Main Repo</sup>에 대한 가장 최근 커밋을 사용하여 빌드됩니다. 기능 혹은 버그 수정이 병합되면 그 다음주에 Alpha로 배포됩니다. -알파 릴리즈 사이에는 중요한 동작 또는 API 변경이 있을 수 있습니다. **알파 릴리즈는 사용자를 대상으로 하는 프로덕션 애플리케이션에는 권장되지 않는다는 점**을 기억하세요. +Alpha 릴리즈 사이에는 중요한 동작 또는 API 변경이 있을 수 있습니다. **Alpha 릴리즈는 사용자를 대상으로 하는 프로덕션 애플리케이션에 권장하지 않는다는 점**을 기억하세요. ## 예상 React 18 릴리즈 일정 {/*projected-react-18-release-timeline*/} -구체적인 릴리즈 날짜는 예정되어 있지 않지만, 대부분의 프로덕션 애플리케이션에서 React 18을 사용할 수 있게 되려면 몇 달 동안 피드백과 반복 작업을 거쳐야 할 것으로 예상됩니다. +구체적인 릴리즈 날짜는 예정되어 있지 않지만, 대부분의 프로덕션 애플리케이션에서 React 18을 사용할 수 있게 되려면 몇 달 동안 피드백과 반복 작업을 거쳐야 할 것으로 예상합니다. -* 라이브러리 알파: 오늘 사용 가능 +* 라이브러리 Alpha: 오늘 사용 가능 * 공개 베타: 최소 몇 개월 -* 릴리즈 후보 (RC): 베타 출시 후 최소 몇 주 후 +* 릴리즈 후보 (RC): Beta 출시 후 최소 몇 주 후 * 일반 사용 가능: RC 이후 최소 몇 주 후 예상 릴리즈 일정에 대한 자세한 내용은 [워킹 그룹에서 확인](https://github.com/reactwg/react-18/discussions/9)할 수 있습니다. 공개 릴리즈에 가까워지면 이 블로그에 업데이트를 게시하겠습니다. diff --git a/src/content/blog/index.md b/src/content/blog/index.md index f412442b6..9c61f1d8e 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -72,12 +72,12 @@ React 18은 릴리스 노트에서 언급한 대로, 새로운 동시성 렌더 지난주, 우리는 6번째 React Conf를 개최했습니다. 지난 몇 년 동안 우리는 React Conf 무대를 통해 React Native, React Hooks와 같은 업계 변화를 알리는 발표를 해왔습니다. 올해는 React 18의 출시와 동시 기능의 점진적인 도입을 시작으로 React의 멀티 플랫폼 비전을 공유했습니다. </BlogCard> -<BlogCard title="React 18 계획" date="2021년 6월 8일" url="/blog/2021/06/08/the-plan-for-react-18"> +<BlogCard title="React 18에 대한 계획" date="2021년 6월 8일" url="/blog/2021/06/08/the-plan-for-react-18"> React 팀은 몇 가지 업데이트를 공유하게 되어 기쁩니다. - 다음 주요 버전이 될 React 18 릴리즈에 대한 작업을 시작했습니다. - 커뮤니티가 React 18의 새로운 기능을 점진적으로 채택할 수 있도록 준비하기 위해 워킹 그룹을 만들었습니다. -- 라이브러리 작성자가 사용해 보고 피드백을 제공할 수 있도록 React 18 알파를 게시했습니다. +- 라이브러리 작성자가 사용해 보고 피드백을 제공할 수 있도록 React 18 Alpha를 게시했습니다. </BlogCard> <BlogCard title="제로 번들 사이즈 React 서버 컴포넌트를 소개합니다" date="2020년 12월 21일" url="/blog/2020/12/21/data-fetching-with-react-server-components"> diff --git a/src/content/community/versioning-policy.md b/src/content/community/versioning-policy.md index 5f376ff4c..241619139 100644 --- a/src/content/community/versioning-policy.md +++ b/src/content/community/versioning-policy.md @@ -44,7 +44,7 @@ React의 개발 빌드에는 유용한 경고가 많이 포함되어 있습니 일반적으로, 다음 변경 사항들은 메이저 버전 번호를 변경하지 *않습니다*. * **개발 빌드 경고.** 프로덕션 동작에 영향을 미치지 않으므로, 우리는 메이저 버전 사이에 새로운 경고를 추가하거나 기존 경고를 수정할 수 있습니다. 이를 통해 앞으로 다가올 breaking changes에 대해 안정적으로 경고할 수 있습니다. * **`unstable_`로 시작하는 API.** 이 API들은 아직 확정되지 않은 실험적 기능들로서 제공됩니다. `unstable_` 접두사를 사용하여 이들을 릴리즈함으로써, 더 빠르게 릴리즈를 반복하고 안정적인 API에 더 빠르게 도달할 수 있습니다. -* **알파 버전과 카나리 버전의 React.** 이른 시일 내에 새로운 기능을 테스트하기 위해 알파 버전의 React를 제공하지만, 알파 기간 동안 배운 것을 바탕으로 변경할 수 있는 유연성이 필요합니다. 이러한 버전을 사용하는 경우, 안정적인 릴리즈 이전에 API가 변경될 수 있음을 유의해야 합니다. +* **Alpha 버전과 카나리 버전의 React.** 이른 시일 내에 새로운 기능을 테스트하기 위해 Alpha 버전의 React를 제공하지만, Alpha 기간 동안 배운 것을 바탕으로 변경할 수 있는 유연성이 필요합니다. 이러한 버전을 사용하는 경우, 안정적인 릴리즈 이전에 API가 변경될 수 있음을 유의해야 합니다. * **문서화되지 않은 API와 내부 데이터 구조.** `__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED`나 `__reactInternalInstance$uk43rzhitjg`와 같은 내부 속성 이름에 접근하는 경우, 이에 대한 보장이 없습니다. 당신 스스로 해결해야 합니다. 당신이 골머리를 앓는 것을 바라지 않기에, 이 정책은 실용적으로 설계되었습니다. 만약 이러한 변화를 모두 메이저 버전으로 릴리즈한다면, 더 많은 메이저 버전을 릴리즈하게 되고, 궁극적으로 버전 관리에 대해 커뮤니티에 더 많은 고통을 야기할 것입니다. 이는 우리가 원하는 만큼 React를 빠르게 개선할 수 없다는 것을 의미합니다. From 9682773149fab4201a85102d7e9e4f46888eb260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Mon, 30 Dec 2024 19:23:28 +0900 Subject: [PATCH 0455/1164] docs: update `react-conf-2021-recap.md` --- .../blog/2021/12/17/react-conf-2021-recap.md | 56 +++++++++---------- src/content/blog/index.md | 2 +- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/content/blog/2021/12/17/react-conf-2021-recap.md b/src/content/blog/2021/12/17/react-conf-2021-recap.md index d512b6dbf..7caddb827 100644 --- a/src/content/blog/2021/12/17/react-conf-2021-recap.md +++ b/src/content/blog/2021/12/17/react-conf-2021-recap.md @@ -2,7 +2,7 @@ title: "React Conf 2021 요약" author: Jesslyn Tannady and Rick Hanlon date: 2021/12/17 -description: 지난주, 우리는 6번째 React Conf를 개최했습니다. 지난 몇 년 동안 우리는 React Conf 무대를 통해 React Native, React Hooks 와 같은 업계 변화를 알리는 발표를 해왔습니다. 올해는 React 18의 출시와 동시 기능의 점진적인 도입을 시작으로 React의 멀티 플랫폼 비전을 공유했습니다. +description: 지난주, 6번째 React Conf를 개최했습니다. 지난 몇 년 동안 React Conf 무대를 통해 React Native, React Hook과 같은 업계 변화를 알리는 발표를 했습니다. 올해는 React 18의 출시 및 동시성 기능의 점진적 도입을 시작으로 React의 멀티 플랫폼 비전을 공유했습니다. --- 2021년 12월 17일, [Jesslyn Tannady](https://twitter.com/jtannady), [Rick Hanlon](https://twitter.com/rickhanlonii) @@ -11,29 +11,29 @@ description: 지난주, 우리는 6번째 React Conf를 개최했습니다. 지 <Intro> -지난주, 우리는 6번째 React Conf를 개최했습니다. 지난 몇 년 동안 우리는 React Conf 무대를 통해 [_React Native_](https://engineering.fb.com/2015/03/26/android/react-native-bringing-modern-web-techniques-to-mobile/), [_React Hooks_](https://reactjs.org/docs/hooks-intro.html)와 같은 업계 변화를 알리는 발표를 해왔습니다. 올해는 React 18의 출시와 동시 기능의 점진적인 도입을 시작으로 React의 멀티 플랫폼 비전을 공유했습니다. +지난주, 6번째 React Conf를 개최했습니다. 지난 몇 년 동안 React Conf 무대를 통해 [_React Native_](https://engineering.fb.com/2015/03/26/android/react-native-bringing-modern-web-techniques-to-mobile/), [_React Hook_](https://reactjs.org/docs/hooks-intro.html)과 같은 업계 변화를 알리는 발표를 했습니다. 올해는 React 18의 출시 및 동시성 기능의 점진적 도입을 시작으로 React의 멀티 플랫폼 비전을 공유했습니다. </Intro> --- -React Conf가 온라인으로 개최된 것은 이번이 처음이며, 8개 언어로 번역되어 무료로 스트리밍되었습니다. 전 세계의 참가자들은 모든 시간대에서 접근성을 위해 컨퍼런스 Discord와 리플레이 이벤트에 참여했습니다. 50,000명 이상이 등록했으며, 19개 강연의 조회수는 60,000회를 넘었고, 두 이벤트에 걸쳐 5,000명이 Discord에 참여했습니다. +React Conf가 온라인으로 개최된 것은 이번이 처음이며, 8개 언어로 번역되어 무료로 스트리밍되었습니다. 전 세계의 참가자들은 다양한 시간대에서의 참여를 위해 컨퍼런스 Discord와 리플레이 이벤트를 이용했습니다. 50,000명 이상이 등록했으며, 19개 강연의 조회수는 60,000회를 넘었고, 두 이벤트에 걸쳐 5,000명이 Discord에 참여했습니다. -모든 강연은 [온라인으로 스트리밍 가능](https://www.youtube.com/watch?v=FZ0cG47msEk&list=PLNG_1j3cPCaZZ7etkzWA7JfdmKWT0pMsa)합니다. +모든 강연은 [온라인 스트리밍이 가능](https://www.youtube.com/watch?v=FZ0cG47msEk&list=PLNG_1j3cPCaZZ7etkzWA7JfdmKWT0pMsa)합니다. -무대에서 공유된 내용을 요약해 보았습니다: +무대에서 공유된 내용을 요약하였습니다. -## React 18 및 동시 기능 {/*react-18-and-concurrent-features*/} +## React 18 및 동시성 기능 {/*react-18-and-concurrent-features*/} -기조연설에서 저희는 React 18을 시작으로 React의 미래에 대한 비전을 공유했습니다. +기조연설에서 React 18을 시작으로 React의 미래에 대한 비전을 공유했습니다. -React 18은 오랫동안 기다려온 동시 renderer를 추가하고 Suspense를 큰 변경 없이 업데이트했습니다. 앱은 React 18로 업그레이드하여 다른 주요 출시와 동등한 수준의 노력으로 동시 기능을 점진적으로 도입할 수 있습니다. +React 18은 오랫동안 기다려온 동시 렌더러<sup>Concurrent Renderer</sup>를 추가하고 Suspense를 주<sup>Major, 主</sup><sub>(역자. Breaking Change를 일으키는)</sub> 변경 없이 업데이트했습니다. 앱은 React 18로 업그레이드하여 다른 주<sup>Major, 主</sup> 릴리즈와 동등한 수준의 노력으로 동시성 기능을 점진적으로 도입할 수 있습니다. -**이는 동시 모드가 없고 동시 기능만 있음을 의미합니다.** +**이는 동시 모드가 없고 동시성 기능만 있음을 의미합니다.** 기조연설에서는 Suspense, 서버 컴포넌트, 새로운 React 워킹 그룹에 대한 비전과 React Native에 대한 장기적인 멀티플랫폼 비전도 공유했습니다. -[Andrew Clark](https://twitter.com/acdlite), [Juan Tejada](https://twitter.com/_jstejada), [Lauren Tan](https://twitter.com/potetotes), [Rick Hanlon](https://twitter.com/rickhanlonii)의 기조연설 전문을 여기에서 시청하세요: +[Andrew Clark](https://twitter.com/acdlite), [Juan Tejada](https://twitter.com/_jstejada), [Lauren Tan](https://twitter.com/potetotes), [Rick Hanlon](https://twitter.com/rickhanlonii)의 기조연설 전문을 아래에서 시청하세요. <YouTubeIframe src="https://www.youtube.com/embed/FZ0cG47msEk" /> @@ -41,13 +41,13 @@ React 18은 오랫동안 기다려온 동시 renderer를 추가하고 Suspense 기조연설에서는 React 18 RC를 지금 바로 사용해볼 수 있다는 사실도 발표했습니다. 추가 피드백을 기다리는 중이며, 내년 초에 정식 버전으로 출시할 예정입니다. -React 18 RC를 사용해 보려면 의존성을 업그레이드하세요: +React 18 RC를 사용해 보려면 의존성<sup>Dependencies</sup>을 업그레이드하세요. ```bash npm install react@rc react-dom@rc ``` -를 클릭하고 새로운 `createRoot` API로 전환하세요: +그리고 새로운 `createRoot` API로 전환하세요. ```js // before @@ -60,15 +60,15 @@ const root = ReactDOM.createRoot(container); root.render(<App/>); ``` -React 18로 업그레이드하는 데모는 여기에서 [Shruti Kapoor](https://twitter.com/shrutikapoor08)의 강연을 참조하세요: +React 18 업그레이드 데모는 아래의 [Shruti Kapoor](https://twitter.com/shrutikapoor08)의 강연을 참조하세요. <YouTubeIframe src="https://www.youtube.com/embed/ytudH8je5ko" /> ## Suspense가 있는 스트리밍 서버 렌더링 {/*streaming-server-rendering-with-suspense*/} -React 18에는 Suspense를 사용한 서버 측 렌더링 성능 개선 사항도 포함되어 있습니다. +React 18에는 Suspense를 사용한 서버 측 렌더링<sup>SSR, Server Side Rendering</sup> 성능 개선 사항도 포함되어 있습니다. -스트리밍 서버 렌더링을 사용하면 서버의 React 컴포넌트에서 HTML을 생성하고 해당 HTML을 사용자에게 스트리밍할 수 있습니다. React 18에서는 'Suspense'를 사용하여 앱을 더 작은 독립 단위로 분해하여 나머지 앱을 차단하지 않고 서로 독립적으로 스트리밍할 수 있습니다. 이는 사용자가 콘텐츠를 더 빨리 보고 훨씬 빠르게 상호작용을 시작할 수 있다는 것을 의미합니다. +스트리밍 서버 렌더링을 사용하면, 서버의 React 컴포넌트에서 HTML을 생성하고 해당 HTML을 사용자에게 스트리밍할 수 있습니다. React 18에서는 `Suspense`를 사용하여 앱을 더 작은 독립 단위로 분해하여, 나머지 앱을 차단하지 않고 서로 독립적으로 스트리밍할 수 있습니다. 이는 사용자가 콘텐츠를 더 빨리 보고 훨씬 빠르게 상호작용할 수 있다는 것을 의미합니다. 더 자세히 알아보려면 [Shaundai Person](https://twitter.com/shaundai)의 강연을 참조하세요: @@ -76,48 +76,48 @@ React 18에는 Suspense를 사용한 서버 측 렌더링 성능 개선 사항 ## 첫 번째 React 워킹 그룹 {/*the-first-react-working-group*/} -React 18에서는 전문가, 개발자, 라이브러리 관리자, 교육자들로 구성된 패널과 협력하기 위해 첫 번째 워킹 그룹을 만들었습니다. 우리는 함께 점진적인 채택 전략을 세우고 `useId`, `useSyncExternalStore`, `useInsertionEffect`와 같은 새로운 API를 개선하기 위해 노력했습니다. +React 18에서는 전문가, 개발자, 라이브러리 관리자, 교육자들로 구성된 패널과 협력하기 위한 첫 번째 워킹 그룹을 만들었습니다. 저희는 함께 점진적인 채택 전략을 세우고 `useId`, `useSyncExternalStore`, `useInsertionEffect`와 같은 새로운 API를 개선하기 위해 노력했습니다. -이 작업에 대한 개요는 [Aakansha' Doshi](https://twitter.com/aakansha1216)의 강연을 참조하세요: +해당 작업에 대한 개요는 [Aakansha' Doshi](https://twitter.com/aakansha1216)의 강연을 참조하세요. <YouTubeIframe src="https://www.youtube.com/embed/qn7gRClrC9U" /> ## React 개발자 도구 {/*react-developer-tooling*/} -이번 릴리즈의 새로운 기능을 지원하기 위해 새로 구성된 React 개발자 도구 팀과 개발자가 React 앱을 디버깅하는 데 도움이 되는 새로운 타임라인 프로파일러도 발표했습니다. +이번 릴리즈의 새로운 기능을 지원하기 위해 새로 구성된 React 개발자 도구 팀과 개발자가 React 앱 디버깅에 도움이 되는 새로운 타임라인 프로파일러<sup>Timeline Profiler</sup>도 발표했습니다. -새로운 개발자 도구 기능에 대한 자세한 내용과 데모는 [Brian Vaughn](https://twitter.com/brian_d_vaughn)의 강연을 참조하세요: +새로운 개발자 도구 기능에 대한 자세한 내용과 데모는 [Brian Vaughn](https://twitter.com/brian_d_vaughn)의 강연을 참조하세요. <YouTubeIframe src="https://www.youtube.com/embed/oxDfrke8rZg" /> ## memo 없는 React {/*react-without-memo*/} -미래를 내다보며, [Xuan Huang(黄玄)](https://twitter.com/Huxpro)이 자동 메모화 컴파일러에 대한 React Labs 연구의 업데이트를 공유했습니다. 이 강연에서 자세한 정보와 컴파일러 프로토타입 데모를 확인하세요: +미래를 내다보며, [Xuan Huang(黄玄)](https://twitter.com/Huxpro)이 자동 메모화 컴파일러에 대한 React Labs 연구의 업데이트를 공유했습니다. 이 강연에서 자세한 정보와 컴파일러 프로토타입 데모를 확인하세요. <YouTubeIframe src="https://www.youtube.com/embed/lGEMwh32soc" /> ## React 문서 기조연설 {/*react-docs-keynote*/} -[Rachel Nabors](https://twitter.com/rachelnabors)가 React의 새로운 문서에 대한 투자에 대한 기조연설로 React로 학습하고 디자인하는 방법에 대한 강연을 시작했습니다([현재 react.dev로 제공됨](/blog/2023/03/16/introducing-react-dev)): +[Rachel Nabors](https://twitter.com/rachelnabors)가 React의 새로운 문서에 대한 투자와 관련한 기조연설로, React로 학습하고 디자인하는 방법에 대한 강연을 했습니다. ([현재 react.dev로 배포되었습니다.](/blog/2023/03/16/introducing-react-dev)) <YouTubeIframe src="https://www.youtube.com/embed/mneDaMYOKP8" /> ## 그리고... {/*and-more*/} -**React로 학습하고 디자인하는 방법에 대한 강연:** +**React로 학습하고 디자인하는 방법에 대한 강연** * Debbie O'Brien: [새로운 React 문서에서 배운 것들](https://youtu.be/-7odLW_hG7s). * Sarah Rainsberger: [브라우저에서 학습하기](https://youtu.be/5X-WEQflCL0). -* Linton Ye: [React로 디자인함에서의 ROI](https://youtu.be/7cPWmID5XAk). -* Delba de Oliveira: [React를 이용한 인터랙티브 놀이터](https://youtu.be/zL8cz2W0z34). +* Linton Ye: [React 디자인에서의 ROI](https://youtu.be/7cPWmID5XAk). +* Delba de Oliveira: [React를 이용한 상호작용 놀이터](https://youtu.be/zL8cz2W0z34). -**Relay, React Native, PyTorch 팀의 강연:** +**Relay, React Native, PyTorch 팀의 강연** -* Robert Balicki: [Relay 다시 소개](https://youtu.be/lhVGdErZuN4). +* Robert Balicki: [Relay 재소개](https://youtu.be/lhVGdErZuN4). * Eric Rozell과 Steven Moyes: [React Native 데스크톱](https://youtu.be/9L4FFrvwJwY). -* Roman Rädle: [React Native를 위한 온디바이스 머신러닝](https://youtu.be/NLj73vrc2I8) +* Roman Rädle: [React Native를 위한 온디바이스 머신러닝](https://youtu.be/NLj73vrc2I8). -**접근성, 툴링 및 서버 컴포넌트에 대한 커뮤니티 강연:** +**접근성, 툴링 및 서버 컴포넌트에 대한 커뮤니티 강연** * Daishi Kato: [외부 스토어 라이브러리를 위한 React 18](https://youtu.be/oPfSC5bQPR8). * Diego Haz: [React 18에서 접근 가능한 컴포넌트 구축하기](https://youtu.be/dcm8fjBfro8). diff --git a/src/content/blog/index.md b/src/content/blog/index.md index 9c61f1d8e..8b9f06d6d 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -69,7 +69,7 @@ React 18은 릴리스 노트에서 언급한 대로, 새로운 동시성 렌더 </BlogCard> <BlogCard title="React Conf 2021 요약" date="2021년 12월 17일" url="/blog/2021/12/17/react-conf-2021-recap"> -지난주, 우리는 6번째 React Conf를 개최했습니다. 지난 몇 년 동안 우리는 React Conf 무대를 통해 React Native, React Hooks와 같은 업계 변화를 알리는 발표를 해왔습니다. 올해는 React 18의 출시와 동시 기능의 점진적인 도입을 시작으로 React의 멀티 플랫폼 비전을 공유했습니다. +지난주, 6번째 React Conf를 개최했습니다. 지난 몇 년 동안 React Conf 무대를 통해 React Native, React Hook과 같은 업계 변화를 알리는 발표를 했습니다. 올해는 React 18의 출시 및 동시성 기능의 점진적 도입을 시작으로 React의 멀티 플랫폼 비전을 공유했습니다. </BlogCard> <BlogCard title="React 18에 대한 계획" date="2021년 6월 8일" url="/blog/2021/06/08/the-plan-for-react-18"> From b5021f98220fe298d1da2ff44103332ac7466329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Tue, 31 Dec 2024 00:12:36 +0900 Subject: [PATCH 0456/1164] docs: update `react-18-upgrade-guide` --- .../blog/2022/03/08/react-18-upgrade-guide.md | 114 +++++++++--------- src/content/blog/index.md | 2 +- 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/src/content/blog/2022/03/08/react-18-upgrade-guide.md b/src/content/blog/2022/03/08/react-18-upgrade-guide.md index a1733f0df..06c41bc50 100644 --- a/src/content/blog/2022/03/08/react-18-upgrade-guide.md +++ b/src/content/blog/2022/03/08/react-18-upgrade-guide.md @@ -2,7 +2,7 @@ title: "React 18로 업그레이드하는 방법" author: Rick Hanlon date: 2022/03/08 -description: React 18은 릴리스 노트에서 언급한 대로 새로운 동시성 렌더러를 도입하여 기존 애플리케이션에 점진적으로 적용할 계획입니다. 이 글에서는 React 18로 업그레이드하는 방법을 단계별로 소개하겠습니다. +description: React 18은 릴리스 노트에서 언급한 대로 새로운 동시 렌더러를 도입하여 기존 애플리케이션에 점진적으로 적용할 계획입니다. 이 글에서는 React 18로 업그레이드하는 방법을 단계별로 소개하겠습니다. --- 2022년 3월 8일, [Rick Hanlon](https://twitter.com/rickhanlonii) @@ -11,7 +11,7 @@ description: React 18은 릴리스 노트에서 언급한 대로 새로운 동 <Intro> -React 18은 [릴리스 노트](/blog/2022/03/29/react-v18)에서 언급한 대로 새로운 동시성 렌더러를 도입하여 기존 애플리케이션에 점진적으로 적용할 계획입니다. 이 글에서는 React 18로 업그레이드하는 방법을 단계별로 소개하겠습니다. +React 18은 [릴리스 노트](/blog/2022/03/29/react-v18)에서 언급한 대로 새로운 동시 렌더러<sup>Concurrent Renderer</sup>를 도입하여 기존 애플리케이션에 점진적으로 적용할 계획입니다. 이 글에서는 React 18로 업그레이드하는 방법을 단계별로 소개하겠습니다. React 18로 업그레이드하는 과정에서 발생하는 [문제를 알려주세요](https://github.com/facebook/react/issues/new/choose). @@ -19,7 +19,7 @@ React 18로 업그레이드하는 과정에서 발생하는 [문제를 알려주 <Note> -React Native 사용자의 경우, React 18은 React Native의 향후 버전에 탑재될 것입니다. 이는 새로운 기능을 활용하기 위해 React 18이 이 글에서 소개되는 새로운 React Native 아키텍처에 의존하기 때문입니다. 자세한 정보는 [React Conf 키노트](https://www.youtube.com/watch?v=FZ0cG47msEk&t=1530s)를 확인해주세요. +React Native 사용자의 경우, React 18은 React Native의 향후 버전에 탑재될 것입니다. 이는 새로운 기능을 활용하기 위해 React 18이 이 글에서 소개되는 새로운 React Native 아키텍처에 의존하기 때문입니다. 자세한 정보는 [React Conf 기조연설](https://www.youtube.com/watch?v=FZ0cG47msEk&t=1530s)을 확인해주세요. </Note> @@ -33,13 +33,13 @@ React Native 사용자의 경우, React 18은 React Native의 향후 버전에 npm install react react-dom ``` -혹은 yarn을 사용한다면 다음 명령어를 입력하세요. +`yarn`을 사용한다면 다음 명령어를 입력하세요. ```bash yarn add react react-dom ``` -## 클라이언트 렌더링 API 관련 업데이트 {/*updates-to-client-rendering-apis*/} +## 클라이언트 렌더링 API 업데이트 {/*updates-to-client-rendering-apis*/} React 18을 처음 설치하면 콘솔 창에 다음과 같은 경고 메시지가 표시될 것입니다. @@ -49,7 +49,7 @@ ReactDOM.render is no longer supported in React 18. Use createRoot instead. Unti </ConsoleBlock> -React 18은 사용자들이 더 편리하게 root 요소들을 관리할 수 있는 최신 root API를 도입합니다. 이에 더불어 최신 root API는 새로운 동시성 렌더러를 동작시켜 동시성 기능을 사용할 수 있게 합니다. +React 18은 사용자들이 더 편리하게 Root 요소들을 관리할 수 있는 최신 Root API를 도입했습니다. 이에 더불어 최신 Root API는 새로운 동시 렌더러를 동작시켜 동시성 기능<sup>Concurrent Features</sup>을 사용할 수 있게 합니다. ```js // 변경 전 @@ -74,7 +74,7 @@ unmountComponentAtNode(container); root.unmount(); ``` -또한 Suspense를 사용할 때 일반적으로 기대한 결과가 나오지 않기 때문에 콜백 함수를 렌더링 메서드에서 제거했습니다. +Suspense를 사용할 때 일반적으로 기대한 결과가 나오지 않기 때문에 콜백 함수를 렌더링 메서드에서 제거했습니다. ```js // 변경 전 @@ -99,11 +99,11 @@ root.render(<AppWithCallbackAfterRender />); <Note> -구형 렌더링 콜백 API에 정확히 대응하는 대안은 없으며, 사용자의 사용 방식에 따라 다를 수 있습니다. 자세한 정보는 현재 진행 중인 그룹 포스트인 [Replacing render with createRoot](https://github.com/reactwg/react-18/discussions/5)를 확인할 수 있습니다. +옛 렌더링 콜백 API에 정확히 대응하는 대안은 없으며, 사용자의 사용 방식에 따라 다를 수 있습니다. 자세한 정보는 현재 진행 중인 그룹 포스트인 [Replacing render with `createRoot`](https://github.com/reactwg/react-18/discussions/5)를 확인할 수 있습니다. </Note> -마지막으로, hydration으로 서버 측 렌더링(SSR)을 이용할 경우에는 `hydrate`를 `hydrateRoot`로 업그레이드하세요. +마지막으로, Hydration으로 서버 측 렌더링<sup>SSR, Server Side Rendering</sup>을 이용할 경우에는 `hydrate`를 `hydrateRoot`로 업그레이드하세요. ```js // 변경 전 @@ -118,17 +118,17 @@ const root = hydrateRoot(container, <App tab="home" />); // createRoot와는 달리, root.render()를 별도로 호출할 필요가 없습니다. ``` -자세한 정보는 [진행 중인 디스커션](https://github.com/reactwg/react-18/discussions/5)을 확인할 수 있습니다. +자세한 정보는 [진행 중인 토론](https://github.com/reactwg/react-18/discussions/5)에서 확인할 수 있습니다. <Note> -**업그레이드 이후에도 앱이 작동하지 않는다면 `<StrictMode>`로 감싸여 있지 않은지 확인해 보세요.** [React 18에서는 Strict 모드가 더 엄격해져서](#updates-to-strict-mode), 모든 컴포넌트가 개발 모드의 추가된 검사 항목을 만족시키지 못할 수 있습니다. Strict 모드를 제거함으로써 문제를 해결할 수 있다면, 업그레이드 중에 제거한 다음, 통합 개발 환경이나 코드 편집기가 표시하는 오류들을 해결된 후에 다시 추가할 수 있습니다 (트리의 상단 또는 일부분에). +**업그레이드 이후에도 앱이 작동하지 않는다면 `<StrictMode>`로 감싸여 있지 않은지 확인해 보세요.** [React 18에서는 Strict 모드가 더 엄격해져서](#updates-to-strict-mode), 모든 컴포넌트가 개발 모드의 추가된 검사 항목을 만족하지 못할 수 있습니다. Strict 모드를 제거함으로써 문제를 해결할 수 있다면, 업그레이드 중에 제거한 다음, 통합 개발 환경이나 코드 편집기가 표시하는 오류들을 해결한 후에 (트리의 상단 또는 일부분에) 다시 추가할 수 있습니다. </Note> ## Updates to Server Rendering APIs {/*updates-to-server-rendering-apis*/} -이번 배포에서는 서버와 스트리밍 SSR에서 Suspense를 최대한 지원하기 위해 `react-dom/server` API를 개편했습니다. 이 개편을 통해, 서버에서 점진적인 Suspense 스트리밍을 지원하지 않는 구형 Node 스트리밍 API를 더 이상 사용하지 않게 되었습니다. +이번 릴리즈에서는 서버와 스트리밍 SSR에서 Suspense를 최대한 지원하기 위해 `react-dom/server` API를 개편했습니다. 이번 개편을 통해, 서버에서 점진적인 Suspense 스트리밍을 지원하지 않는 구형 Node 스트리밍 API를 더 이상 사용하지 않게 되었습니다. 이 API를 사용하면 다음과 같은 경고가 표시됩니다. @@ -140,7 +140,7 @@ const root = hydrateRoot(container, <App tab="home" />); 더불어 Deno나 Cloudflare workers와 같은 최신 런타임 환경에서 Suspense를 활용하여 스트리밍 SSR를 지원하기 위해 새로운 API를 도입합니다. * `renderToReadableStream`: **새로 추가됨 ✨** -다음 API들은 계속 작동되긴 하지만, Suspense 지원이 제한될 것입니다. +다음 API들은 계속 동작하긴 하지만, Suspense 지원이 제한될 것입니다. * `renderToString`: **제한됨** ⚠️ * `renderToStaticMarkup`: **제한됨** ⚠️ @@ -151,7 +151,7 @@ const root = hydrateRoot(container, <App tab="home" />); ## TypeScript 사용 시 타입 작성에 대한 업데이트 {/*updates-to-typescript-definitions*/} -프로젝트에 TypeScript를 사용하고 있다면, `@types/react`와 `@types/react-dom` 의존성을 최신 버전으로 업데이트해야 합니다. 새로운 타입들을 사용하면 더 안전하게 작업할 수 있으며, 기존의 타입 체커가 감지하지 못했던 이슈들을 찾아낼 수 있습니다. 가장 눈에 띄는 변화는 `children` 프로퍼티를 명확한 리스트로 정의해야 한다는 것입니다. 아래의 예시를 확인해보세요. +프로젝트에 TypeScript를 사용하고 있다면, `@types/react`와 `@types/react-dom` 의존성을 최신 버전으로 업데이트해야 합니다. 새로운 타입들을 사용하면 더 안전하게 작업할 수 있으며, 기존의 타입 검사가 감지하지 못했던 이슈들을 찾아낼 수 있습니다. 가장 눈에 띄는 변화는 `children` 프로퍼티를 명확한 리스트로 정의해야 한다는 것입니다. 아래 예시를 확인해보세요. ```typescript{3} interface MyButtonProps { @@ -162,49 +162,49 @@ interface MyButtonProps { [React 18 typings pull request](https://github.com/DefinitelyTyped/DefinitelyTyped/pull/56210)에서 타입 변경 내용을 전체적으로 확인할 수 있습니다. 이 링크는 라이브러리 타입 수정 내용을 담고 있어 코드를 어떻게 수정해야 하는지 확인할 수 있습니다. [automated migration script](https://github.com/eps1lon/types-react-codemod)를 사용하여 애플리케이션 코드에 최신이고 더 안전한 타입을 빠르게 적용할 수 있습니다. -타이핑에 버그를 발견하면 DefinitelyTyped 저장소에 [이슈를 제기해 주세요](https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/new?category=issues-with-a-types-package). +타이핑에 버그를 발견하면 DefinitelyTyped 저장소에 [이슈를 보내주세요](https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/new?category=issues-with-a-types-package). ## 자동 Batching {/*automatic-batching*/} -React 18은 자동으로 더 많은 batching을 수행하여 놀라운 성능 향상을 이뤘습니다. Batching이란 더 나은 성능을 위해 여러 개의 상태 업데이트를 단 한 번의 리렌더링으로 처리하는 것을 말합니다. React 18 이전에는 React 이벤트 핸들러 내에서의 상태 업데이트만 batching을 수행해 왔습니다. 그러나 프로미스, setTimeout, 네이티브 이벤트 핸들러 또는 다른 이벤트들은 React에서 기본적으로 batching을 수행하지 않았죠. 다음 예시를 확인하세요. +React 18은 자동으로 더 많은 Batching을 수행하여 놀라운 성능 향상을 이뤘습니다. Batching이란 더 나은 성능을 위해 여러 개의 상태 업데이트를 단 한 번의 리렌더링으로 처리하는 것을 말합니다. React 18 이전에는 React 이벤트 핸들러 내에서의 상태 업데이트만 Batching을 수행해 왔습니다. 그러나 프로미스, `setTimeout`, 네이티브 이벤트 핸들러 또는 다른 이벤트들은 React에서 기본적으로 Batching을 수행하지 않았죠. 다음 예시를 확인하세요. ```js -// React 18 이전에는 오직 React 이벤트들만 batch되었습니다. +// React 18 이전에는 오직 React 이벤트들만 Batch되었습니다. function handleClick() { setCount(c => c + 1); setFlag(f => !f); - // React는 마지막에 단 한 번만 리렌더링합니다. (그게 batching이죠!) + // React는 마지막에 단 한 번만 리렌더링합니다. (그게 Batching이죠!) } setTimeout(() => { setCount(c => c + 1); setFlag(f => !f); - // React는 각 상태 업데이트마다 한 번씩, 총 두 번 렌더링합니다. (batching 없음) + // React는 각 상태 업데이트마다 한 번씩, 총 두 번 렌더링합니다. (Batching 없음) }, 1000); ``` +React 18를 시작으로 `createRoot`를 사용하여 모든 업데이트가 자동으로 Batch될 것입니다. 이는 `setTimeout`, 프로미스, 네이티브 이벤트 핸들러 또는 다른 이벤트 내의 업데이트도 React 이벤트 내의 업데이트와 같이 Batch 될 것임을 의미합니다. -React 18를 시작으로 `createRoot`를 사용하여 모든 업데이트가 자동으로 배치될 것입니다. 이는 timeout, 프로미스, 네이티브 이벤트 핸들러 또는 다른 이벤트 내의 업데이트도 React 이벤트 내의 업데이트와 같이 batch 될 것임을 의미합니다. ```js -// React 18 이후로 timeout, 프로미스, -// 네이티브 이벤트 핸들러 또는 다른 이벤트 내의 업데이트도 batch 됩니다. +// React 18 이후로 setTimeout, 프로미스, +// 네이티브 이벤트 핸들러 또는 다른 이벤트 내의 업데이트도 Batch 됩니다. function handleClick() { setCount(c => c + 1); setFlag(f => !f); - // React는 마지막에 단 한 번만 리렌더링합니다. (그게 batching이죠!) + // React는 마지막에 단 한 번만 리렌더링합니다. (그게 Batching이죠!) } setTimeout(() => { setCount(c => c + 1); setFlag(f => !f); - // React는 마지막에 단 한 번만 리렌더링합니다. (그게 batching이죠!) + // React는 마지막에 단 한 번만 리렌더링합니다. (그게 Batching이죠!) }, 1000); ``` -이는 엄청난 변화이지만, 이를 통해 렌더링 작업에 수고를 줄일 수 있고, 애플리케이션의 성능도 향상될 것으로 예상합니다. 자동 batching을 원하지 않는 경우, `flushSync`를 사용할 수도 있습니다. +이는 엄청난 변화이지만, 이를 통해 렌더링 작업에 수고를 줄일 수 있고, 애플리케이션의 성능도 향상될 것으로 예상합니다. 자동 Batching을 원하지 않는 경우, `flushSync`를 사용할 수도 있습니다. ```js import { flushSync } from 'react-dom'; @@ -225,41 +225,41 @@ function handleClick() { ## 라이브러리를 위한 새로운 API {/*new-apis-for-libraries*/} -React 18 워킹 그룹은 스타일이나 외부 저장 장치와 같은 특정 목적을 위한 동시성 렌더링을 지원하기 위해 라이브러리 관리자들과 협력하여 새로운 API를 개발했습니다. React 18을 지원하기 위해서는 일부 라이브러리들은 다음 API 중 하나로 변경해야 할 수도 있습니다. +React 18 워킹 그룹은 스타일이나 외부 저장 장치와 같은 특정 목적을 위한 동시성 렌더링을 지원하기 위해 라이브러리 관리자들과 협력하여 새로운 API를 개발했습니다. React 18을 지원하기 위해 일부 라이브러리들은 다음 API 중 하나로 변경해야 할 수도 있습니다. -* `useSyncExternalStore`는 외부 저장 장치의 업데이트를 실시간으로 반영하여 외부 저장 장치가 동시성 불러오기를 지원할 수 있도록 하는 새로운 Hook입니다. 이 API는 React 외부의 상태를 포함하는 라이브러리에서 사용하는 것을 추천합니다. 자세한 정보는 [useSyncExternalStore overview post](https://github.com/reactwg/react-18/discussions/70)와 [useSyncExternalStore API details](https://github.com/reactwg/react-18/discussions/86)에서 확인할 수 있습니다. +* `useSyncExternalStore`는 외부 저장 장치의 업데이트를 실시간으로 반영하여 외부 저장 장치가 동시성 불러오기<sup>Concurrent Read</sup>를 지원할 수 있도록 하는 새로운 Hook입니다. 이 API는 React 외부의 상태를 포함하는 라이브러리에서 사용하는 것을 추천합니다. 자세한 정보는 [`useSyncExternalStore` overview post](https://github.com/reactwg/react-18/discussions/70)와 [`useSyncExternalStore` API details](https://github.com/reactwg/react-18/discussions/86)에서 확인할 수 있습니다. -* `useInsertionEffect`는 CSS-in-JS 라이브러리가 렌더링 시 스타일 주입과 같은 성능 이슈를 개선하는 새로운 Hook입니다. 이미 CSS-in-JS 라이브러리를 만든 경우가 아니라면 이 hook을 사용할 필요는 없을 것입니다. 이 hook은 DOM이 변경된 후 실행되지만, 레이아웃 effect가 새로운 레이아웃을 읽어 들이기 전에 실행됩니다. 자세한 정보는 [Library Upgrade Guide for `<style>`](https://github.com/reactwg/react-18/discussions/110)에서 확인할 수 있습니다. +* `useInsertionEffect`는 CSS-in-JS 라이브러리가 렌더링 시 스타일 주입과 같은 성능 이슈를 개선하는 새로운 Hook입니다. 이미 CSS-in-JS 라이브러리를 만든 경우가 아니라면 이 Hook을 사용할 필요는 없을 것입니다. 이 Hook은 DOM이 변경된 후 실행되지만, 레이아웃 이펙트가 새로운 레이아웃을 읽어 들이기 전에 실행됩니다. 자세한 정보는 [Library Upgrade Guide for `<style>`](https://github.com/reactwg/react-18/discussions/110)에서 확인할 수 있습니다. -또, React 18은 동시성 렌더링을 위해 startTransition, useDeferredValue, 그리고 useId와 같은 새로운 API를 도입합니다. 더 자세한 내용은 [release post](/blog/2022/03/29/react-v18)에서 확인할 수 있습니다. +또, React 18은 동시성 렌더링을 위해 `startTransition`, `useDeferredValue`, 그리고 `useId`와 같은 새로운 API를 도입했습니다. 더 자세한 내용은 [릴리즈 게시물](/blog/2022/03/29/react-v18)에서 확인할 수 있습니다. ## Strict 모드 업데이트 {/*updates-to-strict-mode*/} 차후에는 React에 새로운 기능을 추가하여 UI의 섹션을 추가하거나 제거할 수 있게 할 계획입니다. 예를 들면, 사용자가 뒤로 가기를 누르면 React가 즉시 이전 화면을 보여줄 수 있도록 하는 거죠. 이를 위해 React는 이전과 동일한 컴포넌트 상태를 사용하여 트리를 마운트 해제하고 다시 마운트할 것입니다. -이 기능은 React의 성능을 대폭 향상할 것이지만, 컴포넌트들이 effect들이 여러 번 마운트되었다가 사라지는 것에 아무런 영향을 받지 않아야 합니다. 대부분의 effect들은 변함없이 계속 작동하겠지만, 어떤 것들은 단 한 번만 마운트되고 사라질 수 있도록 설계되어 있습니다. +이 기능은 React의 성능을 대폭 향상할 것이지만, 컴포넌트들이 이펙트가 여러 번 마운트되었다가 사라지는 것에 아무런 영향을 받지 않아야 합니다. 대부분의 이펙트들은 변함없이 계속 작동하겠지만, 어떤 것들은 단 한 번만 마운트되고 사라질 수 있도록 설계되어 있습니다. -React 18은 이러한 문제를 시각적으로 보여주기 위해 Strict 모드에 개발 전용 검사를 새롭게 도입합니다. 이 검사는 컴포넌트가 처음 마운트될 때 자동으로 마운트 해제한 다음, 이전 상태를 복원하면서 다시 마운트할 것입니다. +React 18은 이러한 문제를 시각적으로 보여주기 위해 Strict 모드에 개발 전용 검사를 새롭게 도입했습니다. 이 검사는 컴포넌트가 처음 마운트될 때 자동으로 마운트 해제한 다음, 이전 상태를 복원하면서 다시 마운트할 것입니다. -이 업데이트 이전에는 React가 다음과 같이 컴포넌트를 마운트하고 effect를 생성했습니다. +이번 업데이트 이전에는 React가 다음과 같이 컴포넌트를 마운트하고 이펙트를 생성했습니다. ``` * React가 컴포넌트를 마운트합니다. - * 레이아웃 effect가 생성됩니다. - * 이펙트 effect가 생성됩니다. + * 레이아웃 이펙트가 생성됩니다. + * Effect 이펙트가 생성됩니다. ``` -React 18의 Strict 모드에서는 개발 전용 모드에서 React가 컴포넌트를 마운트 해제하고 다시 마운트하는 것을 실험합니다. +React 18의 Strict 모드에서는 개발 전용 모드에서 React가 컴포넌트를 마운트 해제하고 다시 마운트하는 것을 시뮬레이션합니다. ``` * React가 컴포넌트를 마운트합니다. - * 레이아웃 effect가 생성됩니다. - * 이펙트 effect가 생성됩니다. + * 레이아웃 이펙트가 생성됩니다. + * Effect 이펙트가 생성됩니다. * React가 컴포넌트를 마운트 해제하는 것을 시뮬레이션합니다. - * 레이아웃 effect가 사라집니다. - * Effect가 사라집니다. + * 레이아웃 이펙트가 사라집니다. + * 이펙트가 사라집니다. * React는 컴포넌트를 이전 상태로 다시 마운트하는 것을 시뮬레이션합니다. - * 레이아웃 effect 셋업 코드가 실행됩니다. + * 레이아웃 이펙트 셋업 코드가 실행됩니다. * Effect 셋업 코드가 실행됩니다. ``` @@ -267,7 +267,7 @@ React 18의 Strict 모드에서는 개발 전용 모드에서 React가 컴포넌 ## 테스트 환경 구축하기 {/*configuring-your-testing-environment*/} -`createRoot`를 사용하기 위해 처음으로 테스트들을 업데이트하면 테스트 콘솔 창에서 다음과 같은 경고 메시지가 표시될 수 있습니다. +`createRoot`를 사용하기 위해 처음으로 테스트를 업데이트하면 테스트 콘솔 창에서 다음과 같은 경고 메시지가 표시될 수 있습니다. <ConsoleBlock level="error"> @@ -284,11 +284,11 @@ globalThis.IS_REACT_ACT_ENVIRONMENT = true; 이 변수는 React에 유닛 테스트와 유사한 환경에서 실행 중임을 알리기 위함입니다. 업데이트된 사항을 `act`로 감싸지 않으면 React가 유용한 경고 메시지들을 표시합니다. -React에 `act`가 필요 없다고 알리려면 해당 변수를 `false`로 설정할 수 있습니다. 이렇게 하면 전체 브라우저 환경을 시뮬레이션하는 종단 간 테스트에 유용하게 사용할 수 있습니다. +React에 `act`가 필요 없다고 알리려면 해당 변수를 `false`로 설정할 수 있습니다. 이렇게 하면 전체 브라우저 환경을 시뮬레이션하는 E2E<sup>End-to-End</sup> 테스트에 유용하게 사용할 수 있습니다. 결국에는 테스트 라이브러리가 이를 자동으로 설정해줄 것으로 예상합니다. 예를 들어, [React Testing Library의 다음 버전은 추가적인 설정 없이도 React 18을 지원하는 기능이 내장되어 있습니다](https://github.com/testing-library/react-testing-library/issues/509#issuecomment-917989936). -[`act` 테스트 API와 유관 변경 사항에 대한 추가 정보](https://github.com/reactwg/react-18/discussions/102)는 워킹 그룹에서 확인할 수 있습니다. +[`act` 테스트 API와 관련 변경 사항에 대한 추가 정보](https://github.com/reactwg/react-18/discussions/102)는 워킹 그룹에서 확인할 수 있습니다. ## Internet Explorer 지원 중단 {/*dropping-support-for-internet-explorer*/} @@ -297,7 +297,7 @@ React에 `act`가 필요 없다고 알리려면 해당 변수를 `false`로 설 Internet Explorer를 지원해야 하는 경우 React 17을 사용하는 것을 권장합니다. -## 더 이상 사용되지 않는 것들 {/*deprecations*/} +## 더 이상 사용되지 않습니다 {/*deprecations*/} * `react-dom`: `ReactDOM.render`가 더 이상 사용되지 않습니다. 사용하면 경고가 표시되고 앱이 React 17 모드로 실행됩니다. * `react-dom`: `ReactDOM.hydrate`가 더 이상 사용되지 않습니다. 사용하면 경고가 표시되고 앱이 React 17 모드로 실행됩니다. @@ -305,29 +305,29 @@ Internet Explorer를 지원해야 하는 경우 React 17을 사용하는 것을 * `react-dom`: `ReactDOM.renderSubtreeIntoContainer`가 더 이상 사용되지 않습니다. * `react-dom/server`: `ReactDOMServer.renderToNodeStream`이 더 이상 사용되지 않습니다. -## 이 밖의 획기적인 변화 {/*other-breaking-changes*/} +## 이 밖의 주요한 변화<sup>Breaking Changes</sup> {/*other-breaking-changes*/} -* **일관된 useEffect 타이밍**: click이나 keydown 이벤트와 같은 개별적인 사용자 입력 이벤트 중에 업데이트가 트리거된 경우 React는 항상 동기적으로 이펙트 함수를 플러시합니다. 이전에는 동작이 언제나 예측 가능하거나 일관적이지 않았습니다. -* **Hydration 오류 강화**: 텍스트 콘텐츠가 누락되거나 추가되어 Hydration 불일치가 발생하는 경우 이제 경고가 아닌 오류로 처리됩니다. React는 더 이상 서버 마크업과 일치시키기 위해 클라이언트에서 노드를 삽입하거나 삭제하여 개별 노드를 "패치 업" 하려고 시도하지 않으며, 트리에서 가장 가까운 `<Suspense>` 바운더리까지 클라이언트 렌더링으로 되돌립니다. 이렇게 하면 Hydration 트리의 일관성을 유지하고 Hydration 불일치로 인해 발생할 수 있는 잠재적인 개인정보 보호 및 보안 허점을 방지할 수 있습니다. +* **일관된 `useEffect` 타이밍**: 클릭이나 Keydown 이벤트와 같은 개별적인 사용자 입력 이벤트 중에 업데이트가 트리거된 경우 React는 항상 동기적으로 이펙트 함수를 플러시합니다. 이전에는 동작이 언제나 예측 가능하거나 일관적이지 않았습니다. +* **Hydration 오류 강화**: 텍스트 콘텐츠가 누락되거나 추가되어 Hydration 불일치가 발생하는 경우, 이제 경고가 아닌 오류로 처리됩니다. React는 더 이상 서버 마크업과 일치시키기 위해 클라이언트에서 노드를 삽입하거나 삭제하여 개별 노드를 "패치 업" 하려고 시도하지 않으며, 트리에서 가장 가까운 `<Suspense>` 바운더리까지 클라이언트 렌더링으로 되돌립니다. 이렇게 하면 Hydration 트리의 일관성을 유지하고 Hydration 불일치로 인해 발생할 수 있는 잠재적인 개인정보 보호 및 보안 허점을 방지할 수 있습니다. * **항상 일관성을 유지하는 Suspense 트리**: 컴포넌트가 트리에 완전히 추가되기 전에 일시 중단되면 React는 불완전한 상태로 트리에 추가하거나 그 이펙트를 실행하지 않습니다. 대신 React는 새 트리를 완전히 버리고 비동기 작업이 완료될 때까지 기다린 다음 처음부터 다시 렌더링을 시도합니다. React는 브라우저를 블로킹하지 않고 다시 시도해 동시에 렌더링합니다. -* **Suspense가 있는 레이아웃 효과**: 트리가 다시 일시 중단되고 fallback으로 되돌아갈 때, React는 레이아웃 효과를 정리(clean-up)한 후 경계 안의 콘텐츠가 다시 표시될 때 레이아웃 효과를 다시 생성합니다. 이는 Suspense와 함께 사용할 때 컴포넌트 라이브러리가 레이아웃을 올바르게 측정하지 못하던 문제를 해결합니다. +* **Suspense가 있는 레이아웃 효과**: 트리가 다시 일시 중단되고 Fallback으로 되돌아갈 때, React는 레이아웃 효과를 정리<sup>Clean Up</sup>한 후 경계 안의 콘텐츠가 다시 표시될 때 레이아웃 효과를 다시 생성합니다. 이는 Suspense와 함께 사용할 때 컴포넌트 라이브러리가 레이아웃을 올바르게 측정하지 못하던 문제를 해결합니다. * **새로운 JS 환경 요구 사항**: React는 이제 `Promise`, `Symbol`, `Object.assign`을 포함한 최신 브라우저 기능에 의존합니다. 최신 브라우저 기능을 기본적으로 제공하지 않거나 호환되지 않는 구현이 있는 Internet Explorer와 같은 구형 브라우저 및 기기를 지원하는 경우 번들된 애플리케이션에 전역 폴리필을 포함하는 것을 고려하세요. ## 이 밖의 주목할 만한 변화 {/*other-notable-changes*/} ### React {/*react*/} -* **이제 컴포넌트들이 `undefined`를 렌더링할 수 있습니다.** React는 더 이상 컴포넌트에서 `undefined`를 반환할 때 경고하지 않습니다. 이렇게 함으로써 컴포넌트는 컴포넌트 트리의 중간에 허용된 값과 일관된 값을 반환하게 됩니다. JSX 앞에 `return` 문을 빼먹는 실수와 같은 문제를 방지하기 위해 린터를 사용하는 것을 권장합니다. -* **테스트에서 `act` 경고는 이제 선택 사항입니다.** 종단 간 테스트를 실행하는 경우 `act` 경고 메시지는 불필요합니다. 이 경고 메시지가 쓸모 있는 [유닛 테스트에서만 활성화할 수 있도록](https://github.com/reactwg/react-18/discussions/102) 만들었습니다. -* **이제 마운트가 해제된 컴포넌트에서 `setState` 관련 경고가 나타나지 않습니다.** 이전에는 `setState`를 마운트가 해제된 컴포넌트에서 호출할 때 메모리 누수에 대한 경고가 표시되었습니다. 이 경고는 구독을 위해 추가되었지만, 대부분의 경우 상태 설정에 문제가 없을 때 이 경고를 마주치게 되어 코드를 더 나빠지게 만드는 대안을 찾아야 했습니다. React 18에서는 이 경고를 [제거했습니다](https://github.com/facebook/react/pull/22114). -* **더 이상 콘솔 로그를 억제하지 않습니다.** Strict 모드를 사용할 때 React는 예기치 않은 부작용을 감지하기 위해 각 컴포넌트를 두 번 렌더링합니다. React 17에서는 두 번째 렌더링의 콘솔 로그를 억제하여 로그를 더 쉽게 읽을 수 있게 했습니다. 그러나 [커뮤니티의 피드백](https://github.com/facebook/react/issues/21783)에 따라 이 억제를 제거했습니다. 이제 React DevTools가 설치되어 있다면 두 번째 로그의 렌더링이 회색으로 표시되며 완전히 억제하는 옵션도 사용할 수 있습니다. (기본적으로 꺼져 있음) -* **메모리 사용을 개선했습니다.** React는 이제 마운트가 해제될 때 더 많은 내부 필드를 정리하여 코드에 존재할 수 있는 수정되지 않은 메모리 누수의 영향을 덜 심하게 만듭니다. +* **이제 컴포넌트들이 `undefined`를 렌더링할 수 있습니다.** React는 더 이상 컴포넌트에서 `undefined`를 반환할 때 경고하지 않습니다. 이렇게 함으로써 컴포넌트는 컴포넌트 트리의 중간에 허용된 값과 일관된 값을 반환하게 됩니다. JSX 앞에 `return` 문을 빼먹는 실수와 같은 문제를 방지하기 위해 린터<sup>Linter</sup>를 사용하는 것을 권장합니다. +* **테스트에서 `act` 경고는 이제 선택 사항입니다.** E2E<sup>End-to-End</sup> 테스트를 실행하는 경우 `act` 경고 메시지는 불필요합니다. 이 경고 메시지가 쓸모 있는 [유닛 테스트에서만 활성화할 수 있도록](https://github.com/reactwg/react-18/discussions/102) 만들었습니다. +* **이제 마운트가 해제된 컴포넌트에서 `setState` 관련 경고가 나타나지 않습니다.** 이전에는 `setState`를 마운트가 해제된 컴포넌트에서 호출할 때 메모리 누수에 대한 경고가 표시되었습니다. 이 경고는 구독을 위해 추가되었지만, 대부분의 경우 상태 설정에 문제가 없을 때 이 경고를 마주하게 되어 코드를 더 나쁘게 만드는 대안을 찾아야 했습니다. React 18에서는 이 경고를 [제거했습니다](https://github.com/facebook/react/pull/22114). +* **더 이상 콘솔 로그를 억제하지 않습니다.** Strict 모드를 사용할 때 React는 예기치 않은 부작용을 감지하기 위해 각 컴포넌트를 두 번 렌더링합니다. React 17에서는 두 번째 렌더링의 콘솔 로그를 억제하여 로그를 더 쉽게 읽을 수 있게 했습니다. 그러나 [커뮤니티의 피드백](https://github.com/facebook/react/issues/21783)에 따라 이 억제를 제거했습니다. 이제 React DevTools가 설치되어 있다면 두 번째 로그의 렌더링이 회색으로 표시되며 완전히 억제하는 옵션도 사용할 수 있습니다. (기본적으로 꺼져 있음.) +* **메모리 사용을 개선했습니다.** React는 이제 마운트가 해제될 때 더 많은 내부 필드를 정리하여 코드에 존재할 수 있는 수정되지 않은 메모리 누수의 영향을 줄입니다. ### React DOM 서버 {/*react-dom-server*/} -* **`renderToString`** 은 이제 서버에서 서스펜딩할 때 더 이상 오류가 발생하지 않습니다. 대신 가장 가까운 `<Suspense>` 경계에 fallback HTML을 출력하고, 그런 다음 클라이언트에서 동일한 콘텐츠를 다시 렌더링하도록 시도합니다. 여전히 `renderToPipeableStream` 또는 `renderToReadableStream`과 같은 스트리밍 API로 전환하는 것이 좋습니다. -* **`renderToStaticMarkup`** 은 이제 서버에서 서스펜딩할 때 더 이상 오류가 발생하지 않습니다. 대신 가장 가까운 `<Suspense>` 경계에 fallback HTML을 출력합니다. +* <strong>`renderToString`</strong>은 이제 서버에서 Suspend할 때 더 이상 오류가 발생하지 않습니다. 대신 가장 가까운 `<Suspense>` 경계에 Fallback HTML을 출력하고, 그런 다음 클라이언트에서 동일한 콘텐츠를 다시 렌더링하도록 시도합니다. 여전히 `renderToPipeableStream` 또는 `renderToReadableStream`과 같은 스트리밍 API로 전환하는 것이 좋습니다. +* <strong>`renderToStaticMarkup`</strong>은 이제 서버에서 Suspend할 때 더 이상 오류가 발생하지 않습니다. 대신 가장 가까운 `<Suspense>` 경계에 Fallback HTML을 출력합니다. -## 변경 명세 {/*changelog*/} +## 변경 내역 {/*changelog*/} -[여기에서 전체 변경 명세](https://github.com/facebook/react/blob/main/CHANGELOG.md)를 확인할 수 있습니다. +[여기서 전체 변경 내역](https://github.com/facebook/react/blob/main/CHANGELOG.md)을 확인할 수 있습니다. diff --git a/src/content/blog/index.md b/src/content/blog/index.md index 8b9f06d6d..8e0787649 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -65,7 +65,7 @@ React 18은 수년간의 준비 끝에 탄생한 버전으로 React 팀에게 </BlogCard> <BlogCard title="React 18로 업그레이드하는 방법" date="2022년 3월 8일" url="/blog/2022/03/08/react-18-upgrade-guide"> -React 18은 릴리스 노트에서 언급한 대로, 새로운 동시성 렌더러를 도입하여 기존 애플리케이션에 점진적으로 적용할 계획입니다. 이 글에서는 React 18로 업그레이드하는 방법을 단계별로 소개하겠습니다. +React 18은 릴리스 노트에서 언급한 대로, 새로운 동시 렌더러를 도입하여 기존 애플리케이션에 점진적으로 적용할 계획입니다. 이 글에서는 React 18로 업그레이드하는 방법을 단계별로 소개하겠습니다. </BlogCard> <BlogCard title="React Conf 2021 요약" date="2021년 12월 17일" url="/blog/2021/12/17/react-conf-2021-recap"> From 1a371141382a44f14f3885d0acf09029ef8a5a10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Tue, 31 Dec 2024 01:52:28 +0900 Subject: [PATCH 0457/1164] docs: update `learn/index.md` --- src/content/learn/index.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/content/learn/index.md b/src/content/learn/index.md index 509268fc5..dfe86ba5e 100644 --- a/src/content/learn/index.md +++ b/src/content/learn/index.md @@ -4,11 +4,7 @@ title: 빠르게 시작하기 <Intro> -<<<<<<< HEAD React 문서에 오신 것을 환영합니다! 이 페이지에서는 여러분이 매일 사용하게 될 React 개념의 80%를 소개합니다. -======= -Welcome to the React documentation! This page will give you an introduction to 80% of the React concepts that you will use on a daily basis. ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc </Intro> From 3ca7d66fff7a9e846ec7870a5a2e88346a781d45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Tue, 31 Dec 2024 14:28:37 +0900 Subject: [PATCH 0458/1164] docs: update `useDeferredValue.md` --- .../reference/react/useDeferredValue.md | 174 +++--------------- 1 file changed, 29 insertions(+), 145 deletions(-) diff --git a/src/content/reference/react/useDeferredValue.md b/src/content/reference/react/useDeferredValue.md index f810701c3..2de21b873 100644 --- a/src/content/reference/react/useDeferredValue.md +++ b/src/content/reference/react/useDeferredValue.md @@ -4,7 +4,7 @@ title: useDeferredValue <Intro> -`useDeferredValue`는 UI 일부 업데이트를 지연시킬 수 있는 React Hook입니다. +`useDeferredValue`는 일부 UI 업데이트를 지연시킬 수 있는 React Hook입니다. ```js const deferredValue = useDeferredValue(value) @@ -32,47 +32,32 @@ function SearchPage() { } ``` -[아래에서 더 많은 예를 확인하세요.](#usage) +[아래에서 더 많은 예시를 확인하세요](#usage). #### 매개변수 {/*parameters*/} -<<<<<<< HEAD * `value`: 지연시키려는 값입니다. 모든 타입을 가질 수 있습니다. -* <CanaryBadge title="This feature is only available in the Canary channel" /> **optional** `initialValue`: A value to use during the initial render of a component. If this option is omitted, `useDeferredValue` will not defer during the initial render, because there's no previous version of `value` that it can render instead. -======= -* `value`: The value you want to defer. It can have any type. * **optional** `initialValue`: A value to use during the initial render of a component. If this option is omitted, `useDeferredValue` will not defer during the initial render, because there's no previous version of `value` that it can render instead. ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc - #### 반환값 {/*returns*/} -<<<<<<< HEAD - -- `currentValue`: 초기 렌더링 중에는 반환된 '지연된 값'은 사용자가 제공한 값과 같습니다. 업데이트가 발생하면 React는 먼저 이전 값으로 리렌더링을 시도(반환값이 이전 값과 일치하도록)하고, 그다음 백그라운드에서 다시 새 값으로 리렌더링을 시도(반환값이 업데이트된 새 값과 일치하도록)합니다. - -<Canary> - -In the latest React Canary versions, `useDeferredValue` returns the `initialValue` on initial render, and schedules a re-render in the background with the `value` returned. - -</Canary> -======= -- `currentValue`: During the initial render, the returned deferred value will be the `initialValue`, or the same as the value you provided. During updates, React will first attempt a re-render with the old value (so it will return the old value), and then try another re-render in the background with the new value (so it will return the updated value). ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +- `currentValue`: 초기 렌더링 중 반환된 '지연된 값'은 사용자가 제공한 값과 같습니다. 업데이트가 발생하면 React는 먼저 이전 값으로 리렌더링을 시도(반환값이 이전 값과 일치하도록)하고, 그 다음 백그라운드에서 다시 새 값으로 리렌더링을 시도(반환값이 업데이트된 새 값과 일치하도록)합니다. #### 주의 사항 {/*caveats*/} +- When an update is inside a Transition, `useDeferredValue` always returns the new `value` and does not spawn a deferred render, since the update is already deferred. + - `useDeferredValue`에 전달하는 값은 문자열 및 숫자와 같은 원시값이거나, 컴포넌트의 외부에서 생성된 객체여야 합니다. 렌더링 중에 새 객체를 생성하고 즉시 `useDeferredValue`에 전달하면 렌더링할 때마다 값이 달라져 불필요한 백그라운드 리렌더링이 발생할 수 있습니다. -- `useDeferredValue`가 현재 렌더링(여전히 이전 값을 사용하는 경우) 외에 다른 값([`Object.is`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/is)로 비교)을 받으면 백그라운드에서 새 값으로 리렌더링하도록 예약합니다. `값`에 대한 또 다른 업데이트가 있으면 백그라운드 리렌더링은 중단될 수 있습니다. React는 백그라운드 리렌더링을 처음부터 다시 시작할 것입니다. 예를 들어 차트가 리렌더링 가능한 지연된 값을 받는 속도보다 사용자가 input에 값을 입력하는 속도가 더 빠른 경우, 차트는 사용자가 입력을 멈춘 후에만 리렌더링됩니다. +- `useDeferredValue`가 현재 렌더링(여전히 이전 값을 사용하는 경우) 외에 다른 값([`Object.is`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/is)로 비교)을 받으면 백그라운드에서 새 값으로 리렌더링하도록 예약합니다. `value`에 대한 또 다른 업데이트가 있으면 백그라운드 리렌더링은 중단될 수 있습니다. React는 백그라운드 리렌더링을 처음부터 다시 시작할 것입니다. 예를 들어 차트가 리렌더링 가능한 지연된 값을 받는 속도보다 사용자가 Input에 값을 입력하는 속도가 더 빠른 경우, 차트는 사용자가 입력을 멈춘 후에만 리렌더링됩니다. -- `useDeferredValue`는 [`<Suspense>`](/reference/react/Suspense)와 통합됩니다. 새로운 값으로 인한 백그라운드 업데이트로 인해 UI가 일시 중단되면 사용자는 폴백을 볼 수 없습니다. 데이터가 로딩될 때까지 이전 지연된 값이 표시됩니다. +- `useDeferredValue`는 [`<Suspense>`](/reference/react/Suspense)와 통합됩니다. 새로운 값으로 인한 백그라운드 업데이트로 인해 UI가 일시 중단되면 사용자는 Fallback을 볼 수 없습니다. 데이터가 로딩될 때까지 이전 지연된 값이 표시됩니다. - `useDeferredValue`는 그 자체로 추가 네트워크 요청을 방지하지 않습니다. - `useDeferredValue` 자체로 인한 고정된 지연은 없습니다. React는 원래의 리렌더링을 완료하자마자 즉시 새로운 지연된 값으로 백그라운드 리렌더링 작업을 시작합니다. 그러나 이벤트로 인한 업데이트(예: 타이핑)는 백그라운드 리렌더링을 중단하고 우선순위를 갖습니다. -- `useDeferredValue`로 인한 백그라운드 리렌더링은 화면에 커밋될 때까지 Effects를 실행하지 않습니다. 백그라운드 리렌더링이 일시 중단되면 데이터가 로딩되고 UI가 업데이트된 후에 해당 Effects가 실행됩니다. +- `useDeferredValue`로 인한 백그라운드 리렌더링은 화면에 커밋될 때까지 Effect를 실행하지 않습니다. 백그라운드 리렌더링이 일시 중단되면 데이터가 로딩되고 UI가 업데이트된 후에 해당 Effect가 실행됩니다. --- @@ -101,18 +86,18 @@ function SearchPage() { <Note> -이 예시에서는 Suspense 지원 데이터 소스 중 하나를 사용한다고 가정합니다 +이 예시에서는 Suspense 지원 데이터 소스 중 하나를 사용한다고 가정합니다. -- [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/)와 [Next.js](https://nextjs.org/docs/getting-started/react-essentials) 같이 Suspense가 가능한 프레임워크를 사용한 데이터 가져오기 -- [`lazy`](/reference/react/lazy)를 활용한 지연 로딩 컴포넌트 -- [`use`](/reference/react/use)를 사용해서 Promise 값 읽기 +- [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/)와 [Next.js](https://nextjs.org/docs/getting-started/react-essentials) 같이 Suspense가 가능한 프레임워크를 사용한 데이터 가져오기. +- [`lazy`](/reference/react/lazy)를 활용한 지연 로딩 컴포넌트. +- [`use`](/reference/react/use)를 사용해서 Promise 값 읽기. -[Suspense와 그 한계 자세히 알아보기](/reference/react/Suspense) +[Suspense와 그 한계에 대해 자세히 알아보기](/reference/react/Suspense). </Note> -이 예시에서는 검색 결과를 불러오는 동안 `SearchResults` 컴포넌트가 [일시 중지](/reference/react/Suspense#displaying-a-fallback-while-content-is-loading)됩니다. `"a"`를 입력하고 결과를 기다린 다음 `"ab"`로 수정해 보세요. `"a"`에 대한 결과가 로딩 폴백으로 대체될 것입니다. +아래 예시에서는 검색 결과를 불러오는 동안 `SearchResults` 컴포넌트가 [일시 중지<sup>Suspend</sup>](/reference/react/Suspense#displaying-a-fallback-while-content-is-loading)됩니다. `"a"`를 입력하고 결과를 기다린 다음 `"ab"`로 수정해 보세요. `"a"`에 대한 결과가 로딩 폴백으로 대체될 것입니다. <Sandpack> @@ -158,34 +143,6 @@ export default function SearchResults({ query }) { </ul> ); } -<<<<<<< HEAD - -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. -function use(promise) { - if (promise.status === 'fulfilled') { - return promise.value; - } else if (promise.status === 'rejected') { - throw promise.reason; - } else if (promise.status === 'pending') { - throw promise; - } else { - promise.status = 'pending'; - promise.then( - result => { - promise.status = 'fulfilled'; - promise.value = result; - }, - reason => { - promise.status = 'rejected'; - promise.reason = reason; - }, - ); - throw promise; - } -} -======= ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc ``` ```js src/data.js hidden @@ -307,28 +264,11 @@ export default function App() { } ``` -`query`는 즉시 업데이트되므로 input에 새 값이 표시됩니다. 그러나 `deferredQuery`는 데이터가 로딩될 때까지 이전 값을 유지하므로 `SearchResults`는 잠시 동안 오래된 결과를 표시합니다. +`query`는 즉시 업데이트되므로 Input에 새 값이 표시됩니다. 그러나 `deferredQuery`는 데이터가 로딩될 때까지 이전 값을 유지하므로 `SearchResults`는 잠시 동안 오래된 결과를 표시합니다. -아래 예시에서 `"a"`를 입력하고 결과가 로딩될 때까지 기다린 다음, 입력값을 `"ab"`로 수정해보세요. 이제 새 결과가 로딩될 때까지 Suspense 폴백 대신 오래된 결과 목록이 표시되는 것을 확인할 수 있습니다: +아래 예시에서 `"a"`를 입력하고 결과가 로딩될 때까지 기다린 다음, 입력값을 `"ab"`로 수정해보세요. 이제 새 결과가 로딩될 때까지 Suspense 폴백 대신 오래된 결과 목록이 표시되는 것을 확인할 수 있습니다. <Sandpack> -<<<<<<< HEAD -```json package.json hidden -{ - "dependencies": { - "react": "experimental", - "react-dom": "experimental" - }, - "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test --env=jsdom", - "eject": "react-scripts eject" - } -} -``` -======= ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc ```js src/App.js import { Suspense, useState, useDeferredValue } from 'react'; @@ -373,34 +313,6 @@ export default function SearchResults({ query }) { </ul> ); } -<<<<<<< HEAD - -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. -function use(promise) { - if (promise.status === 'fulfilled') { - return promise.value; - } else if (promise.status === 'rejected') { - throw promise.reason; - } else if (promise.status === 'pending') { - throw promise; - } else { - promise.status = 'pending'; - promise.then( - result => { - promise.status = 'fulfilled'; - promise.value = result; - }, - reason => { - promise.status = 'rejected'; - promise.reason = reason; - }, - ); - throw promise; - } -} -======= ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc ``` ```js src/data.js hidden @@ -505,13 +417,14 @@ input { margin: 10px; } <DeepDive> #### 값을 지연시키는 것은 내부적으로 어떻게 작동하나요? {/*how-does-deferring-a-value-work-under-the-hood*/} -두 단계로 진행된다고 생각하면 됩니다 + +두 단계로 진행된다고 생각하면 됩니다. 1. **먼저, React는 새로운 `query`(`"ab"`)로 리렌더링하지만 이전 `deferredQuery`(여전히 `"a"`)를 사용합니다.** 결과 목록에 전달하는 `deferredQuery` 값은 "지연"된 `query` 값입니다. 2. **백그라운드에서 React는 `query`와 `deferredQuery`를 모두 `"ab"`로 업데이트한 상태로 리렌더링을 시도합니다.** 이 리렌더링이 완료되면 React는 이를 화면에 표시합니다. 그러나 일시 중단되는 경우(`"ab"`에 대한 결과가 아직 로딩되지 않은 경우) React는 이 렌더링 시도를 포기하며, 데이터가 로딩된 후 이 리렌더링을 다시 시도합니다. 사용자는 데이터가 준비될 때까지 오래된 지연된 값을 계속 보게 됩니다. -지연된 "background" 렌더링은 중단할 수 있습니다. 예를 들어 input을 다시 입력하면 React는 지연된 값을 버리고 새 값으로 다시 시작합니다. React는 항상 가장 최근에 제공받은 값을 사용합니다. +지연된 "background" 렌더링은 중단할 수 있습니다. 예를 들어 Input을 다시 입력하면 React는 지연된 값을 버리고 새 값으로 다시 시작합니다. React는 항상 가장 최근에 제공받은 값을 사용합니다. 여전히 각 키 입력마다 네트워크 요청이 있다는 점에 주의하세요. 여기서 지연되는 것은 네트워크 요청 자체가 아니라 결과가 준비될 때까지 결과를 표시하는 것입니다. 사용자가 계속 입력하더라도 각 키 입력에 대한 응답은 캐시 되므로 백스페이스를 누르면 즉시 다시 가져오지 않습니다. @@ -521,8 +434,7 @@ input { margin: 10px; } ### 콘텐츠가 오래되었음을 표시하기 {/*indicating-that-the-content-is-stale*/} -위의 예에서는 최신 쿼리에 대한 결과 목록이 아직 로딩 중이라는 표시가 없습니다. 새 결과를 로딩하는 데 시간이 오래 걸리는 경우 사용자에게 혼란을 줄 수 있습니다. 결과 목록이 최신 쿼리와 일치하지 않는다는 것을 사용자에게 더 명확하게 알리기 위해, 오래된 결과 목록이 표시될 때 시각적 표시를 추가할 수 있습니다. - +위 예시에서는 최신 쿼리에 대한 결과 목록이 아직 로딩 중이라는 표시가 없습니다. 새 결과를 로딩하는 데 시간이 오래 걸리는 경우 사용자에게 혼란을 줄 수 있습니다. 결과 목록이 최신 쿼리와 일치하지 않는다는 것을 사용자에게 더 명확하게 알리기 위해, 오래된 결과 목록이 표시될 때 시각적 표시를 추가할 수 있습니다. ```js {2} <div style={{ @@ -532,7 +444,7 @@ input { margin: 10px; } </div> ``` -이렇게 변경하면 입력을 시작하자마자 새 결과 목록이 로딩될 때까지 오래된 결과 목록이 약간 어두워집니다. 아래 예시에서와 같이 점진적으로 어두워진다고 느껴지도록 CSS transition을 추가하여 흐리게 표시되는 것을 지연시킬 수도 있습니다. +이렇게 변경하면 입력을 시작하자마자 새 결과 목록이 로딩될 때까지 오래된 결과 목록이 약간 어두워집니다. 아래 예시에서와 같이 점진적으로 어두워진다고 느껴지도록 CSS Transition을 추가하여 흐리게 표시되는 것을 지연시킬 수도 있습니다. <Sandpack> @@ -585,34 +497,6 @@ export default function SearchResults({ query }) { </ul> ); } -<<<<<<< HEAD - -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. -function use(promise) { - if (promise.status === 'fulfilled') { - return promise.value; - } else if (promise.status === 'rejected') { - throw promise.reason; - } else if (promise.status === 'pending') { - throw promise; - } else { - promise.status = 'pending'; - promise.then( - result => { - promise.status = 'fulfilled'; - promise.value = result; - }, - reason => { - promise.status = 'rejected'; - promise.reason = reason; - }, - ); - throw promise; - } -} -======= ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc ``` ```js src/data.js hidden @@ -718,9 +602,9 @@ input { margin: 10px; } ### UI 일부에 대해 리렌더링 지연하기 {/*deferring-re-rendering-for-a-part-of-the-ui*/} -`useDeferredValue`를 성능 최적화로 적용할 수도 있습니다. UI 일부가 리렌더링 속도가 느리고, 이를 최적화할 쉬운 방법이 없으며, 나머지 UI를 차단하지 않도록 하려는 경우에 유용합니다. +`useDeferredValue`를 성능 최적화 용도로 적용할 수도 있습니다. UI 일부의 리렌더링 속도가 느리고, 이를 최적화할 쉬운 방법이 없으며, 나머지 UI를 차단하지 않도록 하려는 경우에 유용합니다. -키 입력 시마다 리렌더링되는 텍스트 필드와 컴포넌트(예: 차트 또는 긴 목록)가 있다고 상상해 보세요 +키 입력 시마다 리렌더링되는 텍스트 필드와 컴포넌트(예: 차트 또는 긴 목록)가 있다고 상상해 보세요. ```js function App() { @@ -734,7 +618,7 @@ function App() { } ``` -먼저, props가 같은 경우 리렌더링을 건너뛰도록 `SlowList`를 최적화합니다. 이렇게 하려면, [`memo`](/reference/react/memo#skipping-re-rendering-when-props-are-unchanged)로 감싸주세요. +먼저, Props가 같은 경우 리렌더링을 건너뛰도록 `SlowList`를 최적화합니다. 이렇게 하려면, [`memo`](/reference/react/memo#skipping-re-rendering-when-props-are-unchanged)로 감싸주세요. ```js {1,3} const SlowList = memo(function SlowList({ text }) { @@ -742,9 +626,9 @@ const SlowList = memo(function SlowList({ text }) { }); ``` -그러나 이는 `SlowList` props가 이전 렌더링 때와 *동일한* 경우에만 도움이 됩니다. 지금 직면하고 있는 문제는 props가 *다르고* 실제로 다른 시각적 출력을 보여줘야 할 때 속도가 느리다는 것입니다. +그러나 이는 `SlowList` Props가 이전 렌더링 때와 *동일한* 경우에만 도움이 됩니다. 지금 직면하고 있는 문제는 Props가 *다르고* 실제로 다른 시각적 출력을 보여줘야 할 때 속도가 느리다는 것입니다. -구체적으로, 주요 성능 문제는 input에 타이핑할 때마다 `SlowList`가 새로운 props를 수신하고 전체 트리를 리렌더링하면 타이핑이 끊기는 느낌이 든다는 것입니다. 이 경우 `useDeferredValue`를 사용하면 입력 업데이트(빨라야 하는)를 결과 목록 업데이트(느려도 되는)보다 높은 우선순위에 둘 수 있습니다. +구체적으로, 주요 성능 문제는 Input에 타이핑할 때마다 `SlowList`가 새로운 Props를 수신하고 전체 트리를 리렌더링하면 타이핑이 끊기는 느낌이 든다는 것입니다. 이 경우 `useDeferredValue`를 사용하면 입력 업데이트(빨라야 하는)를 결과 목록 업데이트(느려도 되는)보다 높은 우선순위에 둘 수 있습니다. ```js {3,7} function App() { @@ -918,7 +802,7 @@ export default SlowList; <Pitfall> -이 최적화를 위해서는 `SlowList`를 [`memo`](/reference/react/memo)로 감싸야 합니다. `text`가 변경될 때마다 React는 부모 컴포넌트를 빠르게 리렌더링할 수 있어야 하기 때문입니다. 리렌더링하는 동안 `deferredText`는 여전히 이전 값을 가지므로 `SlowList`는 리렌더링을 건너뛸 수 있습니다(props는 변경되지 않았습니다). [`memo`](/reference/react/memo)가 없으면 어쨌든 리렌더링해야 하므로 최적화의 취지가 무색해집니다. +이 최적화를 위해서는 `SlowList`를 [`memo`](/reference/react/memo)로 감싸야 합니다. `text`가 변경될 때마다 React는 부모 컴포넌트를 빠르게 리렌더링할 수 있어야 하기 때문입니다. 리렌더링하는 동안 `deferredText`는 여전히 이전 값을 가지므로 `SlowList`는 리렌더링을 건너뛸 수 있습니다. (Props는 변경되지 않았습니다.) [`memo`](/reference/react/memo)가 없으면 어쨌든 리렌더링해야 하므로 최적화의 취지가 무색해집니다. </Pitfall> @@ -926,14 +810,14 @@ export default SlowList; #### 값을 지연하는 것은 디바운싱 및 스로틀링과 어떤 점이 다른가요? {/*how-is-deferring-a-value-different-from-debouncing-and-throttling*/} -이 시나리오에서 이전에 사용했을 수 있는 두 가지 일반적인 최적화 기술이 있습니다 +이 시나리오에서 이전에 사용했을 수 있는 두 가지 일반적인 최적화 기술이 있습니다. - *디바운싱*은 타이핑을 멈출 때까지(예: 1초 동안) 기다렸다가 목록을 업데이트하는 것을 의미합니다. - *스로틀링*은 가끔씩(예: 최대 1초에 한 번) 목록을 업데이트하는 것을 의미합니다. 이러한 기법들은 경우에 따라 유용하지만, `useDeferredValue`는 React 자체와 깊게 통합되어 있고 사용자의 기기에 맞게 조정되기 때문에 렌더링을 최적화하는 데 더 적합합니다. -디바운싱이나 스로틀링과 달리 고정된 지연을 선택할 필요가 없습니다. 사용자의 디바이스가 빠른 경우(예: 고성능 노트북) 지연된 리렌더링은 거의 즉시 발생하며 눈에 띄지 않습니다. 사용자의 디바이스가 느린 경우, 기기 속도에 비례하여 목록이 input에 '지연'됩니다. +디바운싱이나 스로틀링과 달리 고정된 지연을 선택할 필요가 없습니다. 사용자의 디바이스가 빠른 경우(예: 고성능 노트북) 지연된 리렌더링은 거의 즉시 발생하며 눈에 띄지 않습니다. 사용자의 디바이스가 느린 경우, 기기 속도에 비례하여 목록이 Input에 '지연'됩니다. 또한 디바운싱이나 스로틀링과 달리, `useDeferredValue`에 의해 수행되는 지연된 리렌더링은 기본적으로 중단할 수 있습니다. 즉, React가 큰 목록을 리렌더링하는 도중에 사용자가 다른 키 입력을 하면 React는 해당 리렌더링을 중단하고 키 입력을 처리한 다음 백그라운드에서 리렌더링을 시작합니다. 반면 디바운싱과 스로틀링은 렌더링이 키 입력을 차단하는 순간을 지연할 뿐이므로 여전히 불안정한 경험을 만들어 냅니다. From f826c9d8a86748777f0d00e8d7d62bfd1eab5673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Tue, 31 Dec 2024 14:32:48 +0900 Subject: [PATCH 0459/1164] docs: update `react-v18.md` --- .../blog/2021/06/08/the-plan-for-react-18.md | 4 +- .../blog/2021/12/17/react-conf-2021-recap.md | 4 +- .../blog/2022/03/08/react-18-upgrade-guide.md | 6 +- src/content/blog/2022/03/29/react-v18.md | 176 +++++++++--------- ...-what-we-have-been-working-on-june-2022.md | 4 +- src/content/blog/index.md | 2 +- 6 files changed, 98 insertions(+), 98 deletions(-) diff --git a/src/content/blog/2021/06/08/the-plan-for-react-18.md b/src/content/blog/2021/06/08/the-plan-for-react-18.md index 36f1d8e9b..c9719277e 100644 --- a/src/content/blog/2021/06/08/the-plan-for-react-18.md +++ b/src/content/blog/2021/06/08/the-plan-for-react-18.md @@ -27,9 +27,9 @@ React 팀은 몇 가지 업데이트를 공유하게 되어 기쁩니다. React 18이 출시되면 [자동 일괄 처리<sup>Automatic Batching</sup>](https://github.com/reactwg/react-18/discussions/21)와 같은 기본 개선 사항 및 [`startTransition`](https://github.com/reactwg/react-18/discussions/41)과 같은 새로운 API, `React.lazy`를 기본적으로 지원하는 [새로운 스트리밍 서버 렌더러<sup>Streaming Server Renderer</sup>](https://github.com/reactwg/react-18/discussions/37)가 포함될 예정입니다. -이러한 기능들은 React 18에 추가될 새로운 선택적<sup>Opt-In</sup> 메커니즘 덕분에 가능해졌습니다. 이를 "동시 렌더링<sup>Concurrent Rendering</sup>"이라고 하며, 이 기능을 통해 React는 동시에 여러 버전의 UI를 준비할 수 있습니다. 이러한 변경 사항들은 대부분 직접 볼 수는 없지만, 앱의 실제 성능과 체감 성능을 모두 개선할 수 있는 새로운 가능성을 열어줍니다. +이러한 기능들은 React 18에 추가될 새로운 선택적<sup>Opt-In</sup> 메커니즘 덕분에 가능해졌습니다. 이를 "동시성 렌더링<sup>Concurrent Rendering</sup>"이라고 하며, 이 기능을 통해 React는 동시에 여러 버전의 UI를 준비할 수 있습니다. 이러한 변경 사항들은 대부분 직접 볼 수는 없지만, 앱의 실제 성능과 체감 성능을 모두 개선할 수 있는 새로운 가능성을 열어줍니다. -React의 미래에 대한 저희들의 연구를 계속 지켜보셨다면(물론, 그럴 필요는 없습니다!), "동시 모드<sup>Concurrent Mode</sup>"라는 기능에 대해 들어보셨거나, 그것이 여러분들의 앱을 망칠 수 있다는 이야기를 들으셨을 수도 있습니다. 이러한 커뮤니티의 피드백을 반영하여 점진적인 도입을 위한 업그레이드 전략을 재설계했습니다. "모드"를 모두 사용하거나 사용하지 않는 대신, 동시 렌더링<sup>Concurrent Rendering</sup>은 새로운 기능 중 하나에 의해 트리거되는 업데이트에 대해서만 활성화됩니다. 즉, **재작성 없이 React 18을 도입하고 자신의 속도에 맞춰 새로운 기능들을 사용해 볼 수 있습니다**. +React의 미래에 대한 저희들의 연구를 계속 지켜보셨다면(물론, 그럴 필요는 없습니다!), "동시성 모드<sup>Concurrent Mode</sup>"라는 기능에 대해 들어보셨거나, 그것이 여러분들의 앱을 망칠 수 있다는 이야기를 들으셨을 수도 있습니다. 이러한 커뮤니티의 피드백을 반영하여 점진적인 도입을 위한 업그레이드 전략을 재설계했습니다. "모드"를 모두 사용하거나 사용하지 않는 대신, 동시성 렌더링<sup>Concurrent Rendering</sup>은 새로운 기능 중 하나에 의해 트리거되는 업데이트에 대해서만 활성화됩니다. 즉, **재작성 없이 React 18을 도입하고 자신의 속도에 맞춰 새로운 기능들을 사용해 볼 수 있습니다**. ## 점진적인 도입 전략 {/*a-gradual-adoption-strategy*/} diff --git a/src/content/blog/2021/12/17/react-conf-2021-recap.md b/src/content/blog/2021/12/17/react-conf-2021-recap.md index 7caddb827..70ae528ea 100644 --- a/src/content/blog/2021/12/17/react-conf-2021-recap.md +++ b/src/content/blog/2021/12/17/react-conf-2021-recap.md @@ -27,9 +27,9 @@ React Conf가 온라인으로 개최된 것은 이번이 처음이며, 8개 언 기조연설에서 React 18을 시작으로 React의 미래에 대한 비전을 공유했습니다. -React 18은 오랫동안 기다려온 동시 렌더러<sup>Concurrent Renderer</sup>를 추가하고 Suspense를 주<sup>Major, 主</sup><sub>(역자. Breaking Change를 일으키는)</sub> 변경 없이 업데이트했습니다. 앱은 React 18로 업그레이드하여 다른 주<sup>Major, 主</sup> 릴리즈와 동등한 수준의 노력으로 동시성 기능을 점진적으로 도입할 수 있습니다. +React 18은 오랫동안 기다려온 동시성 렌더러<sup>Concurrent Renderer</sup>를 추가하고 Suspense를 주<sup>Major, 主</sup><sub>(역자. Breaking Change를 일으키는)</sub> 변경 없이 업데이트했습니다. 앱은 React 18로 업그레이드하여 다른 주<sup>Major, 主</sup> 릴리즈와 동등한 수준의 노력으로 동시성 기능을 점진적으로 도입할 수 있습니다. -**이는 동시 모드가 없고 동시성 기능만 있음을 의미합니다.** +**이는 동시성 모드가 없고 동시성 기능만 있음을 의미합니다.** 기조연설에서는 Suspense, 서버 컴포넌트, 새로운 React 워킹 그룹에 대한 비전과 React Native에 대한 장기적인 멀티플랫폼 비전도 공유했습니다. diff --git a/src/content/blog/2022/03/08/react-18-upgrade-guide.md b/src/content/blog/2022/03/08/react-18-upgrade-guide.md index 06c41bc50..a08353f1d 100644 --- a/src/content/blog/2022/03/08/react-18-upgrade-guide.md +++ b/src/content/blog/2022/03/08/react-18-upgrade-guide.md @@ -2,7 +2,7 @@ title: "React 18로 업그레이드하는 방법" author: Rick Hanlon date: 2022/03/08 -description: React 18은 릴리스 노트에서 언급한 대로 새로운 동시 렌더러를 도입하여 기존 애플리케이션에 점진적으로 적용할 계획입니다. 이 글에서는 React 18로 업그레이드하는 방법을 단계별로 소개하겠습니다. +description: React 18은 릴리스 노트에서 언급한 대로 새로운 동시성 렌더러를 도입하여 기존 애플리케이션에 점진적으로 적용할 계획입니다. 이 글에서는 React 18로 업그레이드하는 방법을 단계별로 소개하겠습니다. --- 2022년 3월 8일, [Rick Hanlon](https://twitter.com/rickhanlonii) @@ -11,7 +11,7 @@ description: React 18은 릴리스 노트에서 언급한 대로 새로운 동 <Intro> -React 18은 [릴리스 노트](/blog/2022/03/29/react-v18)에서 언급한 대로 새로운 동시 렌더러<sup>Concurrent Renderer</sup>를 도입하여 기존 애플리케이션에 점진적으로 적용할 계획입니다. 이 글에서는 React 18로 업그레이드하는 방법을 단계별로 소개하겠습니다. +React 18은 [릴리스 노트](/blog/2022/03/29/react-v18)에서 언급한 대로 새로운 동시성 렌더러<sup>Concurrent Renderer</sup>를 도입하여 기존 애플리케이션에 점진적으로 적용할 계획입니다. 이 글에서는 React 18로 업그레이드하는 방법을 단계별로 소개하겠습니다. React 18로 업그레이드하는 과정에서 발생하는 [문제를 알려주세요](https://github.com/facebook/react/issues/new/choose). @@ -49,7 +49,7 @@ ReactDOM.render is no longer supported in React 18. Use createRoot instead. Unti </ConsoleBlock> -React 18은 사용자들이 더 편리하게 Root 요소들을 관리할 수 있는 최신 Root API를 도입했습니다. 이에 더불어 최신 Root API는 새로운 동시 렌더러를 동작시켜 동시성 기능<sup>Concurrent Features</sup>을 사용할 수 있게 합니다. +React 18은 사용자들이 더 편리하게 Root 요소들을 관리할 수 있는 최신 Root API를 도입했습니다. 이에 더불어 최신 Root API는 새로운 동시성 렌더러를 동작시켜 동시성 기능<sup>Concurrent Features</sup>을 사용할 수 있게 합니다. ```js // 변경 전 diff --git a/src/content/blog/2022/03/29/react-v18.md b/src/content/blog/2022/03/29/react-v18.md index 1c1de1a8e..f7c9225b1 100644 --- a/src/content/blog/2022/03/29/react-v18.md +++ b/src/content/blog/2022/03/29/react-v18.md @@ -11,101 +11,101 @@ description: React 18 is now available on npm! In our last post, we shared step- <Intro> -이제 npm에서 React 18을 사용할 수 있습니다! 지난 포스팅에서는 앱을 [React 18로 업그레이드하는 방법](/blog/2022/03/08/react-18-upgrade-guide)을 단계별로 공유했습니다. 이번 포스팅에서는 React 18의 새로운 기능과 미래에 어떤 의미를 갖는지에 대해 설명하겠습니다. +이제 npm에서 React 18을 사용할 수 있습니다! 지난 포스팅에서는 앱을 [React 18로 업그레이드하는 방법](/blog/2022/03/08/react-18-upgrade-guide)을 단계별로 공유했습니다. 이번 포스팅에서는 React 18의 새로운 기능과 이것이 미래에 어떤 의미를 갖는지에 대해 설명하겠습니다. </Intro> --- -최신 메이저 버전에는 자동 batching, startTransition과 같은 새로운 API, Suspense를 지원하는 스트리밍 서버 사이드 렌더링과 같은 즉각적인 개선 사항이 포함되어 있습니다. +최신 주<sup>Major, 主</sup> 버전에는 자동 Batching, `startTransition`과 같은 새로운 API, Suspense를 지원하는 스트리밍 서버 측 렌더링<sup>SSR, Server Side Rendering</sup>과 같은 즉각적인 개선 사항이 포함되어 있습니다. -React 18의 많은 기능은 강력한 새 기능들을 제공하는 배후의 변경 사항인 concurrent 렌더러를 기반으로 구축되었습니다. concurrent 렌더러는 선택 사항으로, concurrent 기능을 사용할 때만 활성화할 수 있지만 사람들이 애플리케이션을 빌드하는 방식에 큰 영향을 미칠 것으로 예상됩니다. +React 18의 많은 기능은 새로운 동시성 렌더러<sup>Concurrent Renderer</sup>를 기반으로 구축되었습니다. 동시성 렌더러는 선택 사항으로, 동시성 기능을 사용할 때만 활성화할 수 있지만 사람들이 애플리케이션을 빌드하는 방식에 큰 영향을 미칠 것으로 예상합니다. -우리는 수년간 React의 동시성(concurrency) 지원을 연구하고 개발해 왔으며, 기존 사용자가 점진적으로 채택할 수 있도록 각별히 신경을 썼습니다. 지난 여름에는 커뮤니티의 전문가들로부터 피드백을 수집하고 전체 React 생태계를 위한 원활한 업그레이드 환경을 보장하기 위해 [React 18 Working Group](/blog/2021/06/08/the-plan-for-react-18)을 구성했습니다. +저희는 수년간 React의 동시성<sup>concurrency</sup> 지원을 연구하고 개발해 왔으며, 기존 사용자가 점진적으로 채택할 수 있도록 각별히 신경을 썼습니다. 지난 여름에는 커뮤니티의 전문가들로부터 피드백을 수집하고 전체 React 생태계를 위한 원활한 업그레이드 환경을 보장하기 위해 [React 18 워킹 그룹](/blog/2021/06/08/the-plan-for-react-18)을 구성했습니다. -놓치신 분들을 위해 React Conf 2021에서 많은 부분을 공유했습니다. +혹시 놓치셨다면, React Conf 2021에서 이 비전에 대해 자세히 공유했으니 참고해 보세요. * [이 연설](https://www.youtube.com/watch?v=FZ0cG47msEk&list=PLNG_1j3cPCaZZ7etkzWA7JfdmKWT0pMsa)에서는 개발자들이 훌륭한 사용자 경험을 쉽게 구축할 수 있도록 돕는 우리의 임무에 React 18이 어떻게 부합하는지 설명했습니다. * [Shruti Kapoor](https://twitter.com/shrutikapoor08)가 [React 18의 새로운 기능을 사용하는 방법을 시연](https://www.youtube.com/watch?v=ytudH8je5ko&list=PLNG_1j3cPCaZZ7etkzWA7JfdmKWT0pMsa&index=2)했습니다. * [Shaundai Person](https://twitter.com/shaundai)이 [Suspense를 사용한 스트리밍 서버 렌더링](https://www.youtube.com/watch?v=pj5N-Khihgc&list=PLNG_1j3cPCaZZ7etkzWA7JfdmKWT0pMsa&index=3)에 대한 개요를 설명했습니다. -다음은 Concurrent 렌더링부터 시작하여 이번 릴리스에서 기대할 수 있는 기능에 대한 전체 개요입니다. +다음은 동시성 렌더링<sup>Concurrent Rendering</sup>부터 시작하여 이번 릴리스에서 기대할 수 있는 기능에 대한 전체 개요입니다. <Note> -React Native 사용자를 위해 React 18은 새로운 React Native 아키텍처와 함께 React Native로 제공될 예정입니다. 자세한 내용은 [React Conf 키노트](https://www.youtube.com/watch?v=FZ0cG47msEk&t=1530s)를 확인하세요. +React Native 사용자를 위해 React 18은 새로운 React Native 아키텍처와 함께 React Native로 제공될 예정입니다. 자세한 내용은 [React Conf 기조연설](https://www.youtube.com/watch?v=FZ0cG47msEk&t=1530s)를 확인하세요. </Note> -## React의 Concurrent이란? {/*what-is-concurrent-react*/} +## React의 동시성<sup>Concurrency</sup>이란? {/*what-is-concurrent-react*/} -React 18에서 가장 중요한 추가 사항은 여러분이 결코 생각할 필요가 없기를 바라는 것, 바로 동시성(concurrency)입니다. 라이브러리 관리자에게는 조금 더 복잡할 수 있지만 애플리케이션 개발자에게는 대체로 해당하는 이야기라고 생각합니다. +React 18에서 가장 중요한 추가 사항은 여러분이 결코 생각할 필요가 없기를 바라는 것, 바로 동시성<sup>concurrency</sup>입니다. 라이브러리 관리자에게는 조금 더 복잡할 수 있지만 애플리케이션 개발자에게는 대부분 해당하는 이야기라 생각합니다. -Concurrency 자체는 기능이 아닙니다. React가 동시에 여러 버전의 UI를 준비할 수 있게 해주는 새로운 비하인드 메커니즘입니다. Concurrency는 구현의 세부 사항으로 생각할 수 있으며, concurrency가 제공하는 기능 때문에 가치가 있습니다. React는 내부 구현에서 우선순위 큐와 다중 버퍼링과 같은 정교한 기술을 사용합니다. 하지만 우리의 공개 API에서는 이러한 개념을 찾아볼 수 없습니다. +동시성 자체는 기능이 아닙니다. React가 동시에 여러 버전의 UI를 준비할 수 있게 해주는 새로운 내부 동작 방식입니다. 동시성은 구현의 세부 사항으로 생각할 수 있으며, 동시성이 제공하는 기능들 때문에 가치가 있습니다. React는 내부 구현에서 우선순위 큐 및 다중 버퍼링과 같은 정교한 기술들을 사용합니다. 하지만 우리의 공개 API에서는 이러한 개념을 찾아볼 수 없습니다. -API를 설계할 때 우리는 개발자에게 구현 세부 사항을 숨기려고 노력합니다. React 개발자는 사용자 경험을 *어떤 모습(what)* 으로 만들 것인지에 집중하고, React는 그 경험을 *어떻게(how)* 전달할 것인지를 처리합니다. 따라서 React 개발자가 내부에서 concurrency가 어떻게 작동하는지 알기를 기대하지 않습니다. +API를 설계할 때 우리는 개발자에게 구현 세부 사항을 숨기려고 노력합니다. React 개발자는 사용자 경험을 *어떤 모습*<sup>*What*</sup> 으로 만들 것인지에 집중하고, React는 그 경험을 *어떻게*<sup>*How*</sup> 전달할 것인지를 처리합니다. 따라서 React 개발자가 내부에서 동시성이 어떻게 작동하는지 알기를 기대하지 않습니다. -그러나 Concurrent React는 일반적인 구현 세부 사항보다 더 중요합니다. 이것이 React의 핵심 렌더링 모델에 대한 근본적인 업데이트이기 때문입니다. 따라서 concurrency가 어떻게 작동하는지 아는 것이 엄청나게 중요하지는 않지만, 높은 수준에서 concurrency가 무엇인지 아는 것은 가치가 있을 수 있습니다. +그러나 React의 동시성은 일반적인 구현 세부 사항보다 더 중요합니다. 이것은 React의 핵심 렌더링 모델에 대한 근본적인 업데이트이기 때문입니다. 따라서 동시성이 어떻게 동작하는지 아는 것이 엄청 중요하지는 않지만, 고수준<sup>High Level</sup>에서 동시성이 무엇인지 아는 것은 가치가 있을 수 있습니다. -Concurrent React의 핵심은 렌더링을 중단 가능하다는 것입니다. React 18로 처음 업그레이드할 때 concurrent 기능을 추가하기 전 업데이트는 이전 버전의 React와 동일하게 중단되지 않는 단일 동기식 트랜잭션으로 렌더링 됩니다. 동기식 렌더링의 경우 업데이트가 렌더링을 시작하면 사용자가 화면에서 결과를 볼 수 있을 때까지 그 어떤 것도 렌더링을 방해할 수 없습니다. +React의 동시성에서 핵심은 렌더링이 중단 가능하다는 것입니다. React 18로 처음 업그레이드할 때 동시성 기능을 추가하기 전 업데이트는 이전 버전의 React와 동일하게 중단되지 않는 단일 동기식 트랜잭션으로 렌더링 됩니다. 동기식 렌더링의 경우 업데이트가 렌더링을 시작하면 사용자가 화면에서 결과를 볼 수 있을 때까지 그 어떤 것도 렌더링을 방해할 수 없습니다. -Concurrent 렌더링에서는 항상 그렇지는 않습니다. React는 업데이트된 렌더링을 시작하고 중간에 일시 중지했다가 나중에 계속할 수 있습니다. 심지어 진행 중인 렌더링을 완전히 중단할 수도 있습니다. React는 렌더링이 중단되더라도 UI가 일관되게 표시되도록 보장합니다. 이를 위해 트리 전체가 평가된 후 DOM 변형을 수행하기 위해 기다립니다. 이 기능을 통해 React는 메인 스레드를 차단하지 않고 백그라운드에서 새 화면을 준비할 수 있습니다. 즉, UI가 대규모 렌더링 작업 중에도 사용자 입력에 즉시 반응하여 유동적인 사용자 경험을 제공할 수 있습니다. +동시성 렌더링에서는 항상 그렇지는 않습니다. React는 업데이트된 렌더링을 시작하고 중간에 일시 중지했다가 나중에 계속할 수 있습니다. 심지어 진행 중인 렌더링을 완전히 중단할 수도 있습니다. React는 렌더링이 중단되더라도 UI가 일관되게 표시되도록 보장합니다. 이를 위해 트리 전체가 평가된 후 DOM 변형을 수행하기 위해 기다립니다. 이 기능을 통해 React는 메인 스레드를 차단하지 않고 백그라운드에서 새 화면을 준비할 수 있습니다. 즉, UI가 대규모 렌더링 작업 중에도 사용자 입력에 즉시 반응하여 유동적인 사용자 경험을 제공할 수 있습니다. -또 다른 예는 재사용 가능한 상태입니다. Concurrent React는 화면에서 UI의 섹션을 제거했다가 나중에 다시 추가하면서 이전 상태를 재사용할 수 있습니다. 예를 들어 사용자가 화면에서 벗어나 뒤로 탭 할 때, React는 화면을 이전과 동일한 상태로 복원할 수 있어야 합니다. 곧 출시될 마이너 버전에서는 이 패턴을 구현하는 `<Offscreen>`이라는 새로운 컴포넌트를 추가할 계획입니다. 마찬가지로 Offscreen을 사용하여 사용자가 보기 전에 백그라운드에서 새 UI를 준비할 수 있게 될 것입니다. +또 다른 예시는 재사용 가능한 State입니다. React의 동시성은 화면에서 UI의 섹션을 제거했다가 나중에 다시 추가하면서 이전 State를 재사용할 수 있습니다. 예를 들어 사용자가 화면에서 벗어나 뒤로가기를 탭 할 때, React는 화면을 이전과 동일한 상태로 복원할 수 있어야 합니다. 곧 출시될 마이너 버전에서는 이 패턴을 구현하는 `<Offscreen>`이라는 새로운 컴포넌트를 추가할 계획입니다. 마찬가지로 `<Offscreen>`을 사용하여 사용자가 보기 전에 백그라운드에서 새 UI를 준비할 수 있게 될 것입니다. -Concurrent 렌더링은 React의 강력한 새 도구이며 Suspense, Transitions, 스트리밍 서버 렌더링 등 대부분의 새로운 기능이 이를 활용하기 위해 만들어졌습니다. 하지만 React 18은 우리가 이 새로운 기반 위에 구축하고자 하는 목표의 시작일 뿐입니다. +동시성 렌더링은 React의 강력한 새 도구이며 Suspense, Transitions, 스트리밍 서버 렌더링 등 대부분의 새로운 기능들이 이를 활용하기 위해 만들어졌습니다. 하지만 React 18은 이 새로운 기반 위에 구축하고자 하는 목표의 시작일 뿐입니다. -## 점진적으로 Concurrent 기능 적용하기 {/*gradually-adopting-concurrent-features*/} +## 점진적으로 동시성 기능 적용하기 {/*gradually-adopting-concurrent-features*/} -기술적으로 concurrent 렌더링은 획기적인 변화입니다. Concurrent 렌더링은 중단이 가능하기 때문에 이 기능을 활성화하면 컴포넌트가 약간 다르게 동작합니다. +기술적으로 동시성 렌더링은 획기적인 변화입니다. 동시성 렌더링은 중단이 가능하기 때문에 이 기능을 활성화하면 컴포넌트가 약간 다르게 동작합니다. -저희는 테스트에서 수천 개의 컴포넌트를 React 18로 업그레이드했습니다. 그 결과 거의 모든 기존 컴포넌트가 concurrent 렌더링과 함께 변경 없이 "그냥 작동"한다는 사실을 발견했습니다. 하지만 일부 컴포넌트는 추가적인 마이그레이션 작업이 필요할 수 있습니다. 일반적으로 변경 사항은 크지 않지만, 사용자가 원하는 속도에 맞춰 변경할 수 있습니다. React 18의 새로운 렌더링 동작은 **여러분의 앱에서 새로운 기능을 사용하는 부분에서만 활성화됩니다**. +저희는 테스트에서 수천 개의 컴포넌트를 React 18로 업그레이드했습니다. 그 결과 대부분의 기존 컴포넌트가 동시성 렌더링과 함께 변경 없이 "그냥 작동"한다는 사실을 발견했습니다. 하지만 일부 컴포넌트는 추가적인 마이그레이션 작업이 필요할 수 있습니다. 일반적으로 변경 사항은 크지 않지만, 사용자가 원하는 속도에 맞춰 변경할 수 있습니다. React 18의 새로운 렌더링 동작은 **여러분의 앱에서 새로운 기능을 사용하는 부분에서만 활성화됩니다**. -전반적인 업그레이드 전략은 기존 코드를 훼손하지 않고 애플리케이션을 React 18에서 실행하는 것입니다. 그런 다음 자신의 속도에 맞춰 점진적으로 concurrent 기능을 추가하기 시작할 수 있습니다. 개발 중에 concurrency 관련 버그를 발견하는 데 도움이 되는 [`<StrictMode>`](/reference/react/StrictMode)를 사용할 수 있습니다. Strict 모드는 프로덕션 동작에는 영향을 미치지 않지만, 개발 중에 추가 경고를 기록하고 비활성화될 것으로 예상되는 함수를 이중 호출합니다. 모든 것을 잡아내지는 못하지만 가장 일반적인 유형의 실수를 방지하는 데 효과적입니다. +전반적인 업그레이드 전략은 기존 코드를 훼손하지 않고 애플리케이션을 React 18에서 실행하는 것입니다. 그런 다음 자신의 속도에 맞춰 점진적으로 동시성 기능을 추가하기 시작할 수 있습니다. 개발 중에 동시성 관련 버그를 발견하는 데 도움이 되는 [`<StrictMode>`](/reference/react/StrictMode)를 사용할 수 있습니다. Strict 모드는 프로덕션 동작에는 영향을 미치지 않지만, 개발 중에 추가 경고를 기록하고 비활성화될 것으로 예상되는 함수를 이중 호출합니다. 모든 것을 잡아내지는 못하지만 가장 일반적인 유형의 실수를 방지하는 데 효과적입니다. -React 18로 업그레이드하면 즉시 concurrent 기능을 사용할 수 있습니다. 예를 들어 startTransition을 사용하여 사용자 입력을 차단하지 않고 화면 사이를 탐색할 수 있습니다. 또는 비용이 많이 드는 리렌더링을 스로틀링하기 위해 useDeferredValue를 사용할 수 있습니다. +React 18로 업그레이드하면 즉시 동시성 기능을 사용할 수 있습니다. 예를 들어 `startTransition`을 사용하여 사용자 입력을 차단하지 않고 화면 사이를 탐색할 수 있습니다. 또는 비용이 많이 드는 리렌더링을 스로틀링하기 위해 `useDeferredValue`를 사용할 수 있습니다. -하지만 장기적으로는 앱에 concurrency를 추가하는 주된 방법은 concurrency 지원 라이브러리 또는 프레임워크를 사용하는 것입니다. 대부분의 경우 concurrent API와 직접 상호 작용하지는 않을 것입니다. 예를 들어 개발자가 새 화면으로 이동할 때마다 startTransition을 호출하는 대신, 라우터 라이브러리가 자동으로 startTransition에 내비게이션을 래핑합니다. +하지만 장기적으로, 앱에 동시성을 추가하는 주된 방법은 동시성 지원 라이브러리 또는 프레임워크를 사용하는 것입니다. 대부분의 경우 동시성 API와 직접 상호 작용하지는 않을 것입니다. 예를 들어 개발자가 새 화면으로 이동할 때마다 `startTransition`을 호출하는 대신, 라우터 라이브러리가 자동으로 `startTransition`에 내비게이션을 래핑합니다. -라이브러리가 concurrent와 호환이 가능하도록 업그레이드하는 데 다소 시간이 걸릴 수 있습니다. 우리는 라이브러리에서 concurrent 기능을 더 쉽게 활용할 수 있도록 새로운 API를 제공했습니다. 메인테이너들이 React 에코시스템을 점진적으로 마이그레이션하기 위해 노력하는 동안 인내심을 가져주세요. +라이브러리가 동시성과 호환이 가능하도록 업그레이드하는 데 다소 시간이 걸릴 수 있습니다. 우리는 라이브러리에서 동시성 기능을 더 쉽게 활용할 수 있도록 새로운 API를 제공했습니다. 메인테이너들이 React 에코시스템을 점진적으로 마이그레이션하기 위해 노력하는 동안 인내심을 가져주세요. 더 자세한 내용은 이전 게시물을 참조하세요. [React 18로 업그레이드하는 방법](/blog/2022/03/08/react-18-upgrade-guide). ## 데이터 프레임워크의 Suspense {/*suspense-in-data-frameworks*/} -React 18에서는 Relay, Next.js, Hydrogen 또는 Remix와 같은 고유한 프레임워크에서 데이터를 불러오기 위해 [Suspense](/reference/react/Suspense)를 사용할 수 있습니다. Suspense를 사용한 Ad hoc 데이터 불러오기는 기술적으로 가능하지만, 일반적인 전략으로 권장되지는 않습니다. +React 18에서는 Relay, Next.js, Hydrogen 또는 Remix와 같은 고유한 프레임워크에서 데이터를 가져오기<sup>Fetching</sup> 위해 [Suspense](/reference/react/Suspense)를 사용할 수 있습니다. Suspense를 사용한 Ad hoc 데이터 가져오기<sup>Fetching</sup>는 기술적으로 가능하지만, 일반적인 전략으로 권장되지는 않습니다. 향후에는 이런 프레임워크를 사용하지 않고도 Suspense로 데이터에 더 쉽게 액세스할 수 있는 추가 기본 요소를 노출할 수 있습니다. 하지만 Suspense는 라우터, 데이터 레이어, 서버 렌더링 환경 등 애플리케이션의 아키텍처에 깊이 통합되어 있을 때 가장 잘 작동합니다. 따라서 장기적으로도 라이브러리와 프레임워크가 React 생태계에서 중요한 역할을 할 것으로 예상됩니다. -이전 버전의 React에서와 마찬가지로, 클라이언트에서 코드 분할을 위해 Suspense를 React.lazy와 함께 사용할 수도 있습니다. 하지만 Suspense에 대한 우리의 비전은 항상 코드 로딩 그 이상이었습니다. 결국에는 Suspense에 대한 지원을 확장하여, 동일한 선언적 Suspense fallback이 모든 비동기 작업(코드, 데이터, 이미지 등의 로딩)을 처리할 수 있도록 하는 것이 목표입니다. +이전 버전의 React에서와 마찬가지로, 클라이언트에서 코드 분할<sup>Code Splitting</sup>을 위해 Suspense를 `React.lazy`와 함께 사용할 수도 있습니다. 하지만 Suspense에 대한 비전은 항상 코드 로딩 그 이상이었습니다. 결국에는 Suspense에 대한 지원을 확장하여, 동일한 선언적 Suspense Fallback이 모든 비동기 작업(코드, 데이터, 이미지 등의 로딩)을 처리할 수 있도록 하는 것이 목표입니다. ## 서버 컴포넌트는 아직 개발 중입니다. {/*server-components-is-still-in-development*/} -[**서버 컴포넌트**](/blog/2020/12/21/data-fetching-with-react-server-components)는 개발자가 클라이언트 측 앱의 풍부한 상호작용과 기존 서버 렌더링의 향상된 성능을 결합하여 서버와 클라이언트를 아우르는 앱을 구축할 수 있게 해주는 곧 출시될 기능입니다. 서버 컴포넌트는 본질적으로 Concurrent React와 결합하여 있지는 않지만, Suspense 및 스트리밍 서버 렌더링과 같은 concurrent 기능에 가장 잘 작동하도록 설계되었습니다. +[**서버 컴포넌트**](/blog/2020/12/21/data-fetching-with-react-server-components)는 개발자가 클라이언트 측 앱의 풍부한 상호작용과 기존 서버 렌더링의 향상된 성능을 결합하여 서버와 클라이언트를 아우르는 앱을 구축할 수 있게 해주는 곧 출시될 기능입니다. 서버 컴포넌트는 본질적으로 React의 동시성과 결합하여 있지는 않지만, Suspense 및 스트리밍 서버 렌더링과 같은 동시성 기능에 가장 잘 동작하도록 설계되었습니다. -서버 컴포넌트는 아직 실험 단계이지만 18.x 마이너 릴리스에서 초기 버전을 출시할 예정입니다. 그동안에는 이 제안을 발전시키고 광범위한 채택을 준비하기 위해 Next.js, Hydrogen, Remix와 같은 프레임워크와 협력하고 있습니다. +서버 컴포넌트는 아직 실험 단계이지만 18.x 마이너 릴리스에서 초기 버전을 출시할 예정입니다. 그 동안에는 이 제안을 발전시키고 광범위한 채택을 준비하기 위해 Next.js, Hydrogen, Remix와 같은 프레임워크와 협력하고 있습니다. ## React 18의 새로운 기능 {/*whats-new-in-react-18*/} ### 새로운 기능: 자동 Batching {/*new-feature-automatic-batching*/} -Batching은 React가 성능 향상을 위해 여러 state 업데이트를 하나의 리렌더링으로 그룹화하는 것입니다. 자동 batching이 없으면 우리는 React 이벤트 핸들러 내부의 업데이트만 batch 했습니다. Promises, setTimeout, 네이티브 이벤트 핸들러 또는 기타 이벤트 내부의 업데이트는 기본적으로 React에서 batch 되지 않았습니다. 자동 Batching을 사용하면 이러한 업데이트가 자동으로 batch 됩니다. +Batching은 React가 성능 향상을 위해 여러 State 업데이트를 하나의 리렌더링으로 그룹화하는 것입니다. 자동 Batching이 없을 때, 우리는 React 이벤트 핸들러 내부의 업데이트만 Batch 했습니다. Promises, `setTimeout`, 네이티브 이벤트 핸들러 또는 기타 이벤트 내부의 업데이트는 기본적으로 React에서 Batch 되지 않았습니다. 자동 Batching을 사용하면 이러한 업데이트가 자동으로 Batch 됩니다. ```js -// 변경 전: 오직 React 이벤트만 batch 됩니다. +// 변경 전: 오직 React 이벤트만 Batch 됩니다. setTimeout(() => { setCount(c => c + 1); setFlag(f => !f); - // React는 각 state 업데이트마다 한 번씩, 총 두 번 렌더링 됩니다. (batching 아님) + // React는 각 State 업데이트마다 한 번씩, 총 두 번 렌더링 됩니다. (Batching 없음) }, 1000); -// 변경 후: timeouts, promises 내에서도 업데이트할 수 있습니다. -// 네이티브 이벤트 핸들러 또는 다른 이벤트들이 batch 됩니다. +// 변경 후: setTimeout, Promises 내에서도 업데이트할 수 있습니다. +// 네이티브 이벤트 핸들러 또는 다른 이벤트들이 Batch 됩니다. setTimeout(() => { setCount(c => c + 1); setFlag(f => !f); - // React는 마지막에 한 번만 다시 렌더링 됩니다. (batching!) + // React는 마지막에 한 번만 다시 렌더링 됩니다. (그게 Batching 이죠!) }, 1000); ``` @@ -113,43 +113,43 @@ setTimeout(() => { ### 새로운 기능: Transitions {/*new-feature-transitions*/} -Transition은 긴급 업데이트와 비긴급 업데이트를 구분하기 위한 React의 새로운 개념입니다. +Transition은 긴급한<sup>Urgent</sup> 업데이트와 긴급하지 않은<sup>Non-Urgent</sup> 업데이트를 구분하기 위한 React의 새로운 개념입니다. -* **긴급 업데이트**는 입력, 클릭, 누르기 등과 같은 직접적인 상호작용을 반영합니다. +* **긴급한 업데이트**는 입력, 클릭, 누르기 등과 같은 직접적인 상호작용을 반영합니다. * **Transition 업데이트**는 UI를 한 화면에서 다른 화면으로 전환합니다. -입력, 클릭, 누르기 등의 긴급한 업데이트는 실제 사물의 동작 방식에 대한 우리의 직관과 일치하도록 즉각적인 반응이 필요합니다. 그렇지 않으면 "잘못됐다"고 느끼기 때문입니다. 그러나 transition은 사용자가 화면에 모든 중간값을 볼 것으로 기대하지 않기 때문에 다릅니다. +입력, 클릭, 누르기 등의 긴급한 업데이트는 실제 사물의 동작 방식에 대한 우리의 직관과 일치하도록 즉각적인 반응이 필요합니다. 그렇지 않으면 "잘못됐다"고 느끼기 때문입니다. 그러나 Transition은 사용자가 화면에 모든 중간값을 볼 것으로 기대하지 않기 때문에 다릅니다. 예를 들어, 드롭다운에서 필터를 선택하면 클릭 즉시 필터 버튼 자체가 반응할 것으로 기대합니다. 그러나 실제 결과는 별도로 전환될 수 있습니다. 약간의 지연은 눈에 띄지 않고 종종 예상되는 일입니다. 또한 결과가 렌더링 되기 전에 필터를 다시 변경하면 오직 최신 결과만 볼 수 있습니다. -일반적으로 최상의 사용자 경험을 위해서는 한 번의 사용자 입력으로 긴급한 업데이트와 긴급하지 않은 업데이트가 모두 이루어져야 합니다. 입력 이벤트 내에서 startTransition API를 사용하여 어떤 업데이트가 긴급한지, 어떤 업데이트가 "transition"인지 React에 알릴 수 있습니다. +일반적으로 최상의 사용자 경험을 위해서는 한 번의 사용자 입력으로 긴급한 업데이트와 긴급하지 않은 업데이트가 모두 이루어져야 합니다. 입력 이벤트 내에서 `startTransition` API를 사용하여 어떤 업데이트가 긴급한지, 어떤 업데이트가 "Transition"인지 React에 알릴 수 있습니다. ```js import { startTransition } from 'react'; -// 긴급: Urgent: 입력한 내용 표시 +// 긴급(Urgent): 입력한 내용 표시 setInputValue(input); -// 내부의 모든 state 업데이트를 transition으로 표시 +// 내부의 모든 State 업데이트를 Transition으로 표시 startTransition(() => { // Transition: 결과 표시 setSearchQuery(input); }); ``` -startTransition으로 래핑된 업데이트는 긴급하지 않은 것으로 처리되며 클릭이나 키 누름과 같은 더 긴급한 업데이트가 들어올 경우 중단됩니다. 사용자가 여러 문자를 연속해서 입력하는 등의 이유로 transition이 중단되면 React는 완료되지 않은 오래된 렌더링 작업을 버리고 최신 업데이트만 렌더링합니다. +`startTransition`으로 래핑된 업데이트는 긴급하지 않은 것으로 처리되며 클릭이나 키 누름과 같은 더 긴급한 업데이트가 들어올 경우 중단됩니다. 사용자가 여러 문자를 연속해서 입력하는 등의 이유로 Transition이 중단되면, React는 완료되지 않은 오래된 렌더링 작업을 버리고 최신 업데이트만 렌더링합니다. -* `useTransition`: 보류 중인(pending) state를 추적하는 값을 포함하여 transition을 시작하는 Hook. -* `startTransition`: Hook을 사용할 수 없을 때 transition을 시작하는 메서드. +* `useTransition`: 보류 중인<sup>Pending</sup> State를 추적하는 값을 포함하여 Transition을 시작하는 Hook. +* `startTransition`: Hook을 사용할 수 없을 때 Transition을 시작하는 메서드. -transition은 concurrent 렌더링을 선택하여 업데이트를 중단할 수 있습니다. 콘텐츠가 다시 일시 중단되면, transition은 백그라운드에서 transition 콘텐츠를 렌더링하는 동안 현재 콘텐츠를 계속 표시하도록 React에 지시합니다. (자세한 내용은 [Suspense RFC](https://github.com/reactjs/rfcs/blob/main/text/0213-suspense-in-react-18.md)를 참고하세요.) +Transition은 동시성 렌더링을 선택하여 업데이트를 중단할 수 있습니다. 콘텐츠가 다시 일시 중단되면, Transition은 백그라운드에서 Transition 콘텐츠를 렌더링하는 동안 현재 콘텐츠를 계속 표시하도록 React에 지시합니다. (자세한 내용은 [Suspense RFC](https://github.com/reactjs/rfcs/blob/main/text/0213-suspense-in-react-18.md)를 참고하세요.) -[Transitions 참고 문서](/reference/react/useTransition) +[Transitions 참고 문서](/reference/react/useTransition). -### 새로운 Suspense 기능들 {/*new-suspense-features*/} +### 새로운 Suspense 기능 {/*new-suspense-features*/} -Suspense를 사용하면 컴포넌트 트리의 일부가 아직 표시될 준비가 되지 않은 경우 로딩 state를 선언적으로 지정할 수 있습니다. +Suspense를 사용하면 컴포넌트 트리의 일부가 아직 표시될 준비가 되지 않은 경우, 로딩 State를 선언적으로 지정할 수 있습니다. ```js <Suspense fallback={<Spinner />}> @@ -157,103 +157,103 @@ Suspense를 사용하면 컴포넌트 트리의 일부가 아직 표시될 준 </Suspense> ``` -Suspense는 "UI 로딩 상태"를 React 프로그래밍 모델에서 1급 선언적 개념으로 만듭니다. 이를 통해 그 위에 더 높은 수준의 기능을 구축할 수 있습니다. +Suspense는 "UI 로딩 상태"를 React 프로그래밍 모델에서 1급 선언적 개념으로 만듭니다. 이를 통해 그 위에 고수준<sup>Higher-Level</sup>의 기능을 구축할 수 있습니다. -우리는 몇 년 전에 Suspense의 제한된 버전을 도입했습니다. 하지만 지원되는 사용 사례는 React.lazy를 사용한 코드 분할뿐이었으며 서버에서 렌더링할 때는 전혀 지원되지 않았습니다. +저희는 몇 년 전에 Suspense의 제한된 버전을 도입했습니다. 하지만 지원되는 사용 사례는 `React.lazy`를 이용한 코드 분할뿐이었으며 서버에서 렌더링할 때는 전혀 지원되지 않았습니다. -React 18에서는 서버에서 Suspense에 대한 지원을 추가하고 concurrent 렌더링 기능을 사용하여 기능을 확장했습니다. +React 18에서는 서버에서 Suspense에 대한 지원을 추가하고 동시성 렌더링 기능을 사용하여 기능을 확장했습니다. -React 18의 Suspense는 transition API와 함께 사용할 때 가장 잘 작동합니다. transition 도중 일시 중단하면, React는 이미 표시된 콘텐츠가 fallback으로 대체되는 것을 방지합니다. 대신 React는 충분한 데이터가 로드될 때까지 렌더링을 지연시켜 로딩 상태가 나빠지는 것을 방지합니다. +React 18의 Suspense는 Transition API와 함께 사용할 때 가장 잘 동작합니다. Transition 도중 일시 중단하면, React는 이미 표시된 콘텐츠가 Fallback으로 대체되는 것을 방지합니다. 대신 React는 충분한 데이터가 로드될 때까지 렌더링을 지연시켜 로딩 상태가 나빠지는 것을 방지합니다. -[Suspense in React 18 참고 문서](https://github.com/reactjs/rfcs/blob/main/text/0213-suspense-in-react-18.md) +자세한 내용은 [Suspense in React 18](https://github.com/reactjs/rfcs/blob/main/text/0213-suspense-in-react-18.md)에 대한 RFC를 참고하세요. -### 새로운 클라이언트 및 서버 렌더링 API들 {/*new-client-and-server-rendering-apis*/} +### 새로운 클라이언트 및 서버 렌더링 API {/*new-client-and-server-rendering-apis*/} 이번 릴리스에서는 클라이언트와 서버에서 렌더링을 위해 노출하는 API를 재설계할 기회를 가졌습니다. 이러한 변경을 통해 사용자는 React 18의 새로운 API로 업그레이드하는 동안 React 17 모드에서 이전 API를 계속 사용할 수 있습니다. #### React DOM 클라이언트 {/*react-dom-client*/} -이 새로운 API는 이제 `react-dom/client`에서 내보내집니다. +새로운 API는 이제 `react-dom/client`에서 내보내집니다. -* `createRoot`: `렌더링` 또는 `unmount`에 루트를 생성하는 새로운 메서드. `ReactDOM.render` 대신 사용하세요. 이 함수가 없으면 React 18의 새로운 기능들이 작동하지 않습니다. -* `hydrateRoot`: 서버 렌더링된 애플리케이션을 hydrate하는 새로운 메서드. 새로운 React DOM 서버 API와 함께 `ReactDOM.hydrate` 대신 사용하세요. 이 메서드가 없으면 React 18의 새로운 기능이 작동하지 않습니다. +* `createRoot`: `render` 또는 `unmount`에 Root를 생성하는 새로운 메서드. `ReactDOM.render` 대신 사용하세요. 이 함수가 없으면 React 18의 새로운 기능들이 동작하지 않습니다. +* `hydrateRoot`: 서버 렌더링된 애플리케이션을 Hydrate하는 새로운 메서드. 새로운 React DOM 서버 API와 함께 `ReactDOM.hydrate` 대신 사용하세요. 이 메서드가 없으면 React 18의 새로운 기능들이 동작하지 않습니다. -`createRoot`와 `hydrateRoot`는 모두 렌더링 중 오류가 발생하거나 로깅을 위한 hydration 중 오류가 발생했을 때 알림을 받고자 하는 경우 `onRecoverableError`라는 새로운 옵션을 허용합니다. 기본적으로 React는 [`reportError`](https://developer.mozilla.org/en-US/docs/Web/API/reportError) 또는 오래된 브라우저에서는 `console.error`를 사용합니다. +`createRoot`와 `hydrateRoot`는 모두 렌더링 중 오류가 발생하거나 로깅을 위한 Hydration 중 오류가 발생했을 때 알림을 받고자 하는 경우 `onRecoverableError`라는 새로운 옵션을 허용합니다. 기본적으로 React는 [`reportError`](https://developer.mozilla.org/en-US/docs/Web/API/reportError) 또는 오래된 브라우저에서는 `console.error`를 사용합니다. -[React DOM 클라이언트 참고 문서](/reference/react-dom/client) +[React DOM 클라이언트 참고 문서](/reference/react-dom/client). #### React DOM 서버 {/*react-dom-server*/} -이 새로운 API는 이제 `react-dom/server`에서 내보내지며 서버에서 Suspense를 스트리밍하는 데 완벽하게 지원됩니다. +이 새로운 API는 이제 `react-dom/server`에서 내보내지며 서버에서의 Suspense 스트리밍을 완벽하게 지원합니다. * `renderToPipeableStream`: Node 환경에서의 스트리밍용. * `renderToReadableStream`: 최신 엣지 런타임 환경(예: Deno 및 Cloudflare 워커)에서의 스트리밍용. -기존의 `renderToString` 메서드는 계속 작동하지만 권장하지 않습니다. +기존의 `renderToString` 메서드는 계속 동작하지만 권장하지 않습니다. -[React DOM 서버 참고 문서](/reference/react-dom/server) +[React DOM 서버 참고 문서](/reference/react-dom/server). -### 새로운 Strict 모드 동작들 {/*new-strict-mode-behaviors*/} +### 새로운 Strict 모드 동작 {/*new-strict-mode-behaviors*/} -앞으로는 React가 state를 유지하면서 UI의 섹션을 추가하고 제거할 수 있는 기능을 추가하고 싶습니다. 예를 들어 사용자가 화면에서 벗어나 뒤로 탭 할 때 React는 이전 화면을 즉시 표시할 수 있어야 합니다. 이를 위해 React는 이전과 동일한 컴포넌트 state를 사용하여 트리를 마운트 해제하고 다시 마운트합니다. +앞으로는 React가 State를 유지하면서 UI의 섹션을 추가하고 제거할 수 있는 기능을 추가하고 싶습니다. 예를 들어 사용자가 화면에서 벗어나 뒤로 탭 할 때 React는 이전 화면을 즉시 표시할 수 있어야 합니다. 이를 위해 React는 이전과 동일한 컴포넌트 State를 사용하여 트리를 마운트 해제하고 다시 마운트합니다. -이 기능을 사용하면 React 앱의 성능이 즉시 향상되지만, 컴포넌트가 effect가 여러 번 마운트 및 소멸하는 것에 대해 탄력적이어야 합니다. 대부분의 effect는 변경 없이 작동하지만 일부 effect는 한 번만 마운트되거나 소멸한다고 가정합니다. +이 기능을 사용하면 React 앱의 성능이 즉시 향상되지만, 컴포넌트의 Effect가 여러 번 마운트 및 소멸하는 것에 대해 탄력적이어야 합니다. 대부분의 Effect는 변경 없이 동작하지만 일부 Effect는 한 번만 마운트되거나 소멸한다고 가정합니다. -이러한 문제를 해결하기 위해 React 18은 Strict 모드에 새로운 개발 전용 검사를 도입했습니다. 이 새로운 검사는 컴포넌트가 처음 마운트될 때마다 모든 컴포넌트를 자동으로 마운트 해제하고 다시 마운트하여 두 번째 마운트 시 이전 state로 복원합니다. +이러한 문제를 해결하기 위해 React 18은 Strict 모드에 새로운 개발 전용 검사를 도입했습니다. 이 새로운 검사는 컴포넌트가 처음 마운트될 때마다 모든 컴포넌트를 자동으로 마운트 해제하고 다시 마운트하여 두 번째 마운트 시 이전 State로 복원합니다. -이 변경 전에는 React가 컴포넌트를 마운트하고 effect를 생성했습니다. +변경 전에는 React가 컴포넌트를 마운트하고 Effect를 생성했습니다. ``` * React가 컴포넌트를 마운트합니다. - * 레이아웃 effect가 생성됩니다. - * Effect가 생성됩니다. + * 레이아웃 이펙트가 생성됩니다. + * Effect 이펙트가 생성됩니다. ``` React 18의 Strict 모드에서는 개발 모드에서 컴포넌트를 마운트 해제하고 다시 마운트하는 것을 시뮬레이션합니다. ``` * React가 컴포넌트를 마운트합니다. - * 레이아웃 effect가 생성됩니다. - * Effect가 생성됩니다. -* React가 컴포넌트 마운트 해제를 시뮬레이션합니다. - * 레이아웃 effect가 소멸합니다. - * Effect가 소멸합니다. -* React가 컴포넌트를 이전 상태로 마운트하는 것을 시뮬레이션합니다. - * 레이아웃 effect가 생성됩니다. - * Effect가 생성됩니다. + * 레이아웃 이펙트가 생성됩니다. + * Effect 이펙트가 생성됩니다. +* React가 컴포넌트를 마운트 해제하는 것을 시뮬레이션합니다. + * 레이아웃 이펙트가 사라집니다. + * 이펙트가 사라집니다. +* React는 컴포넌트를 이전 상태로 다시 마운트하는 것을 시뮬레이션합니다. + * 레이아웃 이펙트 셋업 코드가 실행됩니다. + * Effect 셋업 코드가 실행됩니다. ``` -[여기에서 재사용할 수 있는 state 보장에 대한 문서를 참조하세요](/reference/react/StrictMode#fixing-bugs-found-by-re-running-effects-in-development). +[재사용 가능한 State를 보장하는 방법은 문서를 참고하세요](/reference/react/StrictMode#fixing-bugs-found-by-re-running-effects-in-development). -### 새로운 Hooks {/*new-hooks*/} +### 새로운 Hook {/*new-hooks*/} -#### useId {/*useid*/} +#### `useId` {/*useid*/} -`useId`는 hydration 불일치를 방지하면서 클라이언트와 서버 모두에서 고유 ID를 생성하기 위한 새로운 Hook입니다. 주로 고유 ID가 필요한 접근성 API와 통합되는 컴포넌트 라이브러리에 유용합니다. 이는 React 17 이하에서 이미 존재하던 문제를 해결하지만, 새로운 스트리밍 서버 렌더러가 HTML을 순서대로 전달하지 않기 때문에 React 18에서는 더욱 중요합니다. [참고 문서](/reference/react/useId) +`useId`는 Hydration 불일치를 방지하면서 클라이언트와 서버 모두에서 고유 ID를 생성하기 위한 새로운 Hook입니다. 주로 고유 ID가 필요한 접근성 API와 통합되는 컴포넌트 라이브러리에 유용합니다. 이는 React 17 이하에서 이미 존재하던 문제를 해결하지만, 새로운 스트리밍 서버 렌더러가 HTML을 순서대로 전달하지 않기 때문에 React 18에서는 더욱 중요합니다. [참고 문서](/reference/react/useId). > 주의 > -> `useId`는 [목록에서 key](/learn/rendering-lists#where-to-get-your-key)를 생성하기 위한 것이 *아닙니다*. Key는 여러분의 데이터에서 생성해야 합니다. +> `useId`는 [목록에서 Key](/learn/rendering-lists#where-to-get-your-key)를 생성하기 위한 것이 *아닙니다*. Key는 여러분의 데이터에서 생성해야 합니다. -#### useTransition {/*usetransition*/} +#### `useTransition` {/*usetransition*/} -`useTransition`와 `startTransition`을 사용하면 일부 상태 업데이트를 긴급하지 않은 것으로 표시할 수 있습니다. 기본적으로 다른 상태 업데이트는 긴급한 것으로 간주됩니다. React는 긴급하지 않은 상태 업데이트(예: 검색 결과 목록 렌더링)를 긴급한 상태 업데이트(예: 텍스트 입력 업데이트)로 중단할 수 있도록 허용합니다. [참고 문서](/reference/react/useTransition). +`useTransition`와 `startTransition`을 사용하면 일부 상태 업데이트를 긴급하지 않은 것으로 표시할 수 있습니다. 기본적으로 다른 상태 업데이트는 긴급한 것으로 간주합니다. React는 긴급하지 않은 상태 업데이트(예: 검색 결과 목록 렌더링)를 긴급한 상태 업데이트(예: 텍스트 입력 업데이트)로 중단할 수 있도록 허용합니다. [참고 문서](/reference/react/useTransition). -#### useDeferredValue {/*usedeferredvalue*/} +#### `useDeferredValue` {/*usedeferredvalue*/} -`useDeferredValue`를 사용하면 트리에서 긴급하지 않은 부분의 리렌더링을 지연(deferred)시킬 수 있습니다. 디바운싱과 비슷하지만 디바운싱에 비해 몇 가지 장점이 있습니다. 고정된 시간 지연이 없기 때문에 React는 첫 번째 렌더링이 화면에 반영된 직후에 deferred 렌더링을 시도합니다. deferred 렌더링은 중단할 수 있으며 사용자 입력을 차단하지 않습니다. [참고 문서](/reference/react/useDeferredValue) +`useDeferredValue`를 사용하면 트리에서 긴급하지 않은 부분의 리렌더링을 지연<sup>Deferred</sup>시킬 수 있습니다. 디바운싱과 비슷하지만 디바운싱에 비해 몇 가지 장점이 있습니다. 고정된 시간 지연이 없기 때문에 React는 첫 번째 렌더링이 화면에 반영된 직후에 지연된<sup>Deferred</sup> 렌더링을 시도합니다. 지연된<sup>Deferred</sup> 렌더링은 중단할 수 있으며 사용자 입력을 차단하지 않습니다. [참고 문서](/reference/react/useDeferredValue). -#### useSyncExternalStore {/*usesyncexternalstore*/} +#### `useSyncExternalStore` {/*usesyncexternalstore*/} -`useSyncExternalStore`는 스토어에 대한 업데이트를 강제로 동기화하여 외부 스토어가 동시 읽기를 지원할 수 있도록 하는 새로운 Hook입니다. 이 Hook은 외부 데이터에 대한 구독을 구현할 때 useEffect가 필요하지 않으며, React 외부 state와 통합하는 모든 라이브러리에 권장됩니다. [참고 문서](/reference/react/useSyncExternalStore) +`useSyncExternalStore`는 Store에 대한 업데이트를 강제로 동기화하여 외부 Store가 동시 읽기를 지원할 수 있도록 하는 새로운 Hook입니다. 이 Hook은 외부 데이터에 대한 구독을 구현할 때 `useEffect`가 필요하지 않으며, React 외부 State와 통합하는 모든 라이브러리에 권장됩니다. [참고 문서](/reference/react/useSyncExternalStore). > 주의 > > `useSyncExternalStore`는 애플리케이션 코드가 아닌 라이브러리에서 사용하기 위한 것입니다. -#### useInsertionEffect {/*useinsertioneffect*/} +#### `useInsertionEffect` {/*useinsertioneffect*/} -`useInsertionEffect`는 CSS-in-JS 라이브러리가 렌더링에서 스타일을 삽입할 때 발생하는 성능 문제를 해결할 수 있는 새로운 Hook입니다. 이미 CSS-in-JS 라이브러리를 빌드한 경우가 아니라면 이 Hook을 사용할 일은 없을 것으로 예상됩니다. 이 Hook은 DOM이 변경된 후에 실행되지만, 레이아웃 effects가 새 레이아웃을 읽기 전에 실행됩니다. 이는 React 17 이하에서 이미 존재하던 문제를 해결하지만, React 18에서는 concurrent 렌더링 중에 브라우저가 레이아웃을 다시 계산할 기회를 제공하기 때문에 더욱 중요합니다. [참고 문서](/reference/react/useInsertionEffect) +`useInsertionEffect`는 CSS-in-JS 라이브러리가 렌더링에서 스타일을 삽입할 때 발생하는 성능 문제를 해결할 수 있는 새로운 Hook입니다. 이미 CSS-in-JS 라이브러리를 빌드한 경우가 아니라면 이 Hook을 사용할 일은 없을 것으로 예상됩니다. 이 Hook은 DOM이 변경된 후에 실행되지만, 레이아웃 Effect가 새 레이아웃을 읽기 전에 실행됩니다. 이는 React 17 이하에서 이미 존재하던 문제를 해결하지만, React 18에서는 동시성 렌더링 중에 브라우저가 레이아웃을 다시 계산할 기회를 제공하기 때문에 더욱 중요합니다. [참고 문서](/reference/react/useInsertionEffect). > 주의 > diff --git a/src/content/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.md b/src/content/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.md index 923cf9376..f8fcaa7e5 100644 --- a/src/content/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.md +++ b/src/content/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.md @@ -34,7 +34,7 @@ Vercel 및 Shopify와 협력하여 Webpack 및 Vite 모두에서 공유 시맨 현재, 스크립트, 외부 스타일, 글꼴 및 이미지와 같은 리소스는 일반적으로 외부 시스템을 사용하여 사전 로드되고 로드됩니다. 이로 인해 스트리밍, 서버 컴포넌트 등과 같은 새로운 환경에서 조정하기 까다로울 수 있습니다. 우리는 모든 React 환경에서 작동하는 React API를 통해 중복 제거된 외부 자산을 미리 로드하고 로드하기 위해 API를 추가하는 것을 고려하고 있습니다. -우리는 또한 Suspense를 지원하여 로드될 때까지 표시를 차단하지만 스트리밍 및 동시 렌더링을 차단하지 않는 이미지, CSS 및 글꼴을 가질 수 있도록 하는 것을 고려하고 있습니다. 이것은 시각적 요소가 튀어나오고 레이아웃이 바뀔 때 ["popcorning"](https://twitter.com/sebmarkbage/status/1516852731251724293)을 방지하는 데 도움이 될 수 있습니다. +우리는 또한 Suspense를 지원하여 로드될 때까지 표시를 차단하지만 스트리밍 및 동시성 렌더링을 차단하지 않는 이미지, CSS 및 글꼴을 가질 수 있도록 하는 것을 고려하고 있습니다. 이것은 시각적 요소가 튀어나오고 레이아웃이 바뀔 때 ["popcorning"](https://twitter.com/sebmarkbage/status/1516852731251724293)을 방지하는 데 도움이 될 수 있습니다. ## 정적 서버 렌더링 최적화 {/*static-server-rendering-optimizations*/} @@ -56,7 +56,7 @@ Vercel 및 Shopify와 협력하여 Webpack 및 Vite 모두에서 공유 시맨 오프스크린은 UI를 시각적으로 숨기되 콘텐츠의 우선순위를 낮추는 세 번째 옵션을 도입합니다. 이 아이디어는 `content-visibility` CSS 프로퍼티와 비슷한 개념으로, 콘텐츠가 숨겨져 있을 때 나머지 UI와 동기화 상태를 유지할 필요가 없습니다. React는 앱의 나머지 부분이 유휴 상태가 될 때까지 또는 콘텐츠가 다시 표시될 때까지 렌더링 작업을 연기할 수 있습니다. -오프스크린은 높은 수준의 기능을 잠금 해제하는 낮은 수준의 기능입니다. `startTransition` 과 같은 React의 다른 동시 기능과 유사하게, 대부분의 경우 오프스크린 API와 직접 상호작용하지 않고 독단적인 프레임워크를 통해 다음과 같은 패턴을 구현합니다. +오프스크린은 높은 수준의 기능을 잠금 해제하는 낮은 수준의 기능입니다. `startTransition` 과 같은 React의 다른 동시성 기능과 유사하게, 대부분의 경우 오프스크린 API와 직접 상호작용하지 않고 독단적인 프레임워크를 통해 다음과 같은 패턴을 구현합니다. * **즉각적인 전환.** 일부 라우팅 프레임워크는 링크 위로 마우스를 가져갈 때와 같이 후속 탐색 속도를 높이기 위해 이미 데이터를 미리 가져옵니다. 오프스크린을 사용하면 백그라운드에서 다음 화면을 미리 렌더링할 수도 있습니다. * **재사용 가능한 state.** 마찬가지로 경로나 탭 사이를 탐색할 때 오프스크린을 사용하여 이전 화면의 state를 보존하여 중단한 지점에서 다시 전환하고 선택할 수 있습니다. diff --git a/src/content/blog/index.md b/src/content/blog/index.md index 8e0787649..8b9f06d6d 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -65,7 +65,7 @@ React 18은 수년간의 준비 끝에 탄생한 버전으로 React 팀에게 </BlogCard> <BlogCard title="React 18로 업그레이드하는 방법" date="2022년 3월 8일" url="/blog/2022/03/08/react-18-upgrade-guide"> -React 18은 릴리스 노트에서 언급한 대로, 새로운 동시 렌더러를 도입하여 기존 애플리케이션에 점진적으로 적용할 계획입니다. 이 글에서는 React 18로 업그레이드하는 방법을 단계별로 소개하겠습니다. +React 18은 릴리스 노트에서 언급한 대로, 새로운 동시성 렌더러를 도입하여 기존 애플리케이션에 점진적으로 적용할 계획입니다. 이 글에서는 React 18로 업그레이드하는 방법을 단계별로 소개하겠습니다. </BlogCard> <BlogCard title="React Conf 2021 요약" date="2021년 12월 17일" url="/blog/2021/12/17/react-conf-2021-recap"> From 29d7b8f1d023c69c5b6c8d952f9cfe999cdc7749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Tue, 31 Dec 2024 14:44:43 +0900 Subject: [PATCH 0460/1164] docs: update `react-labs-what-we-have-benn-working-on-june-2022.md` --- ...-what-we-have-been-working-on-june-2022.md | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/content/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.md b/src/content/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.md index f8fcaa7e5..15586cd79 100644 --- a/src/content/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.md +++ b/src/content/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.md @@ -11,7 +11,7 @@ description: React 18 은 수년간의 준비 끝에 탄생한 버전으로 Reac <Intro> -[React 18](/blog/2022/03/29/react-v18)은 수년간의 준비 끝에 탄생한 버전으로 React 팀에게 귀중한 교훈을 가져다주었습니다. 수년간의 연구와 다양한 경로를 모색한 끝에 출시된 제품입니다. 그 경로 중 일부는 성공적이었지만 더 많은 경로가 막다른 골목에서 새로운 인사이트로 이어졌습니다. 우리가 얻은 한 가지 교훈은 우리가 탐색하고 있는 경로에 대한 인사이트를 공유받지 못한 채 새로운 기능을 기다리는 것은 커뮤니티에 실망감을 준다는 것입니다. +[React 18](/blog/2022/03/29/react-v18)은 수년간의 준비 끝에 탄생한 버전으로 React 팀에게 귀중한 교훈을 가져다주었습니다. 수년간의 연구와 다양한 방법을 모색한 끝에 출시된 제품입니다. 그 방법 중 일부는 성공적이었지만 더 많은 방법들이 막다른 골목에서 새로운 통찰로 이어졌습니다. 우리가 얻은 한 가지 교훈은 우리가 탐색하고 있는 방법에 대한 통찰을 공유받지 못한 채 새로운 기능을 기다리는 것은 커뮤니티에 실망감을 준다는 것입니다. </Intro> @@ -29,7 +29,7 @@ description: React 18 은 수년간의 준비 끝에 탄생한 버전으로 Reac Vercel 및 Shopify와 협력하여 Webpack 및 Vite 모두에서 공유 시맨틱에 대한 번들러 지원을 통합하고 있습니다. 출시 전에 전체 React 생태계에서 RSC의 의미가 동일한지 확인하고자 합니다. 이것은 안정에 도달하는 데 주요 장애물입니다. -## 자산 로딩 {/*asset-loading*/} +## 자산<sup>Asset</sup> 로딩 {/*asset-loading*/} 현재, 스크립트, 외부 스타일, 글꼴 및 이미지와 같은 리소스는 일반적으로 외부 시스템을 사용하여 사전 로드되고 로드됩니다. 이로 인해 스트리밍, 서버 컴포넌트 등과 같은 새로운 환경에서 조정하기 까다로울 수 있습니다. 우리는 모든 React 환경에서 작동하는 React API를 통해 중복 제거된 외부 자산을 미리 로드하고 로드하기 위해 API를 추가하는 것을 고려하고 있습니다. @@ -38,32 +38,32 @@ Vercel 및 Shopify와 협력하여 Webpack 및 Vite 모두에서 공유 시맨 ## 정적 서버 렌더링 최적화 {/*static-server-rendering-optimizations*/} -정적 사이트 생성(SSG)과 증분 정적 재생성(ISR)은 캐시 가능한 페이지의 성능을 향상하는 좋은 방법이지만, 동적 서버 측 렌더링(SSR)의 성능을 개선할 수 있는 기능을 더 추가할 수 있다고 생각합니다 - 특히, 대부분의 컨텐츠가 캐싱이 가능하지만 일부만 불가능한 경우를 위해서요. 컴파일 및 정적 패스를 활용하여 서버 렌더링을 최적화하는 방법을 모색하고 있습니다. +정적 사이트 생성<sup>SSG</sup>과 증분 정적 재생성<sup>ISR</sup>은 캐시 가능한 페이지의 성능을 향상하는 좋은 방법이지만, 동적 서버 측 렌더링<sup>SSR</sup>의 성능을 개선할 수 있는 기능을 더 추가할 수 있다고 생각합니다. 특히, 대부분의 컨텐츠가 캐싱이 가능하지만 일부만 불가능한 경우를 위해서요. 컴파일 및 정적 경로를 활용하여 서버 렌더링을 최적화하는 방법을 모색하고 있습니다. ## React 최적화 컴파일러 {/*react-compiler*/} -우리는 React Conf 2021에서 React Forget을 [미리 선보였습니다](https://www.youtube.com/watch?v=lGEMwh32soc). 이 컴파일러는 React의 프로그래밍 모델을 유지하면서 재렌더링 비용을 최소화하기 위해 `useMemo` 와 `useCallback` 에 상응하는 호출을 자동으로 생성하는 컴파일러입니다. +우리는 React Conf 2021에서 React Forget을 [미리 선보였습니다](https://www.youtube.com/watch?v=lGEMwh32soc). 이 컴파일러는 React의 프로그래밍 모델을 유지하면서 재렌더링 비용을 최소화하기 위해 `useMemo` 와 `useCallback`에 상응하는 호출을 자동으로 생성하는 컴파일러입니다. -최근 저희는 컴파일러의 안정성과 성능을 높이기 위해 컴파일러 재작업을 완료했습니다. 이 새로운 아키텍처를 통해 [로컬 변이 사용](/learn/keeping-components-pure#local-mutation-your-components-little-secret)과 같은 더 복잡한 패턴을 분석하고 메모화할 수 있게 되었으며, memoization Hooks 와 동등한 수준 이상으로 많은 새로운 컴파일 시간 최적화 기회가 열리게 되었습니다. +최근 저희는 컴파일러의 안정성과 성능을 높이기 위해 컴파일러 재작업을 완료했습니다. 이 새로운 아키텍처를 통해 [로컬 변형 사용](/learn/keeping-components-pure#local-mutation-your-components-little-secret)과 같은 더 복잡한 패턴을 분석하고 메모화할 수 있게 되었으며, Memoization Hook과 동등한 수준 이상으로 많은 새로운 컴파일 시간 최적화 기회가 열리게 되었습니다. -또한 컴파일러의 여러 측면을 탐색할 수 있는 플레이그라운드도 개발 중입니다. 플레이그라운드의 목표는 컴파일러를 더 쉽게 개발하는 것이지만, 컴파일러를 사용해보고 컴파일러가 하는 일에 대한 직관력을 키우는 데 도움이 될 것으로 생각합니다. 컴파일러가 내부에서 어떻게 작동하는지에 대한 다양한 인사이트를 제공하며, 입력하는 대로 컴파일러의 출력을 실시간으로 렌더링합니다. 이 기능은 컴파일러가 출시될 때 함께 제공됩니다. +또한 컴파일러의 여러 측면을 탐색할 수 있는 플레이그라운드도 개발 중입니다. 플레이그라운드의 목표는 컴파일러를 더 쉽게 개발하는 것이지만, 컴파일러를 사용해보고 컴파일러가 하는 일에 대한 직관력을 키우는 데 도움이 될 것으로 생각합니다. 컴파일러가 내부에서 어떻게 작동하는지에 대한 다양한 통찰을 제공하며, 입력하는 대로 컴파일러의 출력을 실시간으로 렌더링합니다. 이 기능은 컴파일러가 출시될 때 함께 제공됩니다. ## 오프스크린 {/*offscreen*/} -이제 컴포넌트를 숨기거나 표시하려면 두 가지 옵션이 있습니다. 하나는 트리에서 완전히 추가하거나 제거하는 것입니다. 이 방법의 문제점은 마운트를 해제할 때마다 스크롤 위치와 같이 DOM에 저장된 state를 포함하여 UI의 state가 손실된다는 것입니다. +이제 컴포넌트를 숨기거나 표시하려면 두 가지 옵션이 있습니다. 하나는 트리에서 완전히 추가하거나 제거하는 것입니다. 이 방법의 문제점은 마운트를 해제할 때마다 스크롤 위치와 같이 DOM에 저장된 State를 포함하여 UI의 State가 손실된다는 것입니다. -다른 옵션은 컴포넌트를 마운트한 상태로 유지하고 CSS를 사용해 시각적으로 모양을 전환하는 것입니다. 이 방법은 UI의 state를 유지하지만, React가 새로운 업데이트를 받을 때마다 숨겨진 컴포넌트와 그 모든 자식들을 계속 렌더링해야 하므로 성능에 비용이 발생합니다. +다른 옵션은 컴포넌트를 마운트한 상태로 유지하고 CSS를 사용해 시각적으로 모양을 전환하는 것입니다. 이 방법은 UI의 State를 유지하지만, React가 새로운 업데이트를 받을 때마다 숨겨진 컴포넌트와 그 모든 자식들을 계속 렌더링해야 하므로 성능에 비용이 발생합니다. 오프스크린은 UI를 시각적으로 숨기되 콘텐츠의 우선순위를 낮추는 세 번째 옵션을 도입합니다. 이 아이디어는 `content-visibility` CSS 프로퍼티와 비슷한 개념으로, 콘텐츠가 숨겨져 있을 때 나머지 UI와 동기화 상태를 유지할 필요가 없습니다. React는 앱의 나머지 부분이 유휴 상태가 될 때까지 또는 콘텐츠가 다시 표시될 때까지 렌더링 작업을 연기할 수 있습니다. -오프스크린은 높은 수준의 기능을 잠금 해제하는 낮은 수준의 기능입니다. `startTransition` 과 같은 React의 다른 동시성 기능과 유사하게, 대부분의 경우 오프스크린 API와 직접 상호작용하지 않고 독단적인 프레임워크를 통해 다음과 같은 패턴을 구현합니다. +오프스크린은 고수준<sup>High Level</sup>의 기능을 잠금 해제하는 저수준<sup>Low Level</sup>의 기능입니다. `startTransition` 과 같은 React의 다른 동시성 기능과 유사하게, 대부분의 경우 오프스크린 API와 직접 상호작용하지 않고 독단적인 프레임워크를 통해 다음과 같은 패턴을 구현합니다. * **즉각적인 전환.** 일부 라우팅 프레임워크는 링크 위로 마우스를 가져갈 때와 같이 후속 탐색 속도를 높이기 위해 이미 데이터를 미리 가져옵니다. 오프스크린을 사용하면 백그라운드에서 다음 화면을 미리 렌더링할 수도 있습니다. -* **재사용 가능한 state.** 마찬가지로 경로나 탭 사이를 탐색할 때 오프스크린을 사용하여 이전 화면의 state를 보존하여 중단한 지점에서 다시 전환하고 선택할 수 있습니다. +* **재사용 가능한 State.** 마찬가지로 경로나 탭 사이를 탐색할 때 오프스크린을 사용하여 이전 화면의 State를 보존하여 중단한 지점에서 다시 전환하고 선택할 수 있습니다. * **가상화된 목록 렌더링.** 많은 항목 목록을 표시할 때 가상화된 목록 프레임워크는 현재 표시되는 것보다 더 많은 행을 미리 렌더링합니다. 오프스크린을 사용하여 숨겨진 행을 목록에 보이는 항목보다 낮은 우선 순위로 미리 렌더링할 수 있습니다. * **배경 콘텐츠.** 또한 모달 오버레이를 표시할 때와 같이 콘텐츠를 숨기지 않고 백그라운드에서 우선 순위를 낮추는 관련 기능을 탐색하고 있습니다. -## 전환 추적 {/*transition-tracing*/} +## Transition 추적 {/*transition-tracing*/} 현재 React에는 두 가지 프로파일링 도구가 있습니다. [기존의 프로파일러](https://legacy.reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html)는 프로파일링 세션의 모든 커밋에 대한 개요를 보여줍니다. 각 커밋에 대해 렌더링된 모든 컴포넌트와 렌더링하는 데 걸린 시간도 표시됩니다. 또한 React 18에 도입된 [Timeline Profiler](https://github.com/reactwg/react-18/discussions/76)의 베타 버전이 있는데, 이 기능은 컴포넌트가 업데이트를 예약하는 시기와 React가 이러한 업데이트에서 작동하는 시기를 보여줍니다. 이 두 프로파일러는 개발자가 코드에서 성능 문제를 식별하는 데 도움이 됩니다. @@ -75,8 +75,8 @@ Vercel 및 Shopify와 협력하여 Webpack 및 Vite 모두에서 공유 시맨 ## 새로운 React 문서 {/*new-react-docs*/} -작년에 우리는 새로운 React 문서 웹사이트의 베타 버전([나중에 react.dev로 출시](/blog/2023/03/16/introducing-react-dev))을 발표했습니다. 새로운 학습 자료는 Hooks를 먼저 가르치고 새로운 다이어그램, 일러스트레이션, 많은 대화형 예시 및 과제를 포함합니다. 우리는 React 18 릴리스에 집중하기 위해 해당 작업에서 잠시 휴식을 취했지만 이제 React 18이 출시되었으므로 새 문서를 완료하고 제공하기 위해 적극적으로 노력하고 있습니다. +작년에 새로운 React 문서 웹사이트의 베타 버전([훗날 react.dev로 출시](/blog/2023/03/16/introducing-react-dev))을 발표했습니다. 새로운 학습 자료는 Hook을 먼저 가르치고 새로운 다이어그램, 일러스트레이션, 많은 대화형 예시 및 과제를 포함합니다. 우리는 React 18 릴리스에 집중하기 위해 해당 작업에서 잠시 휴식을 취했지만 이제 React 18이 출시되었으므로 새 문서를 완료하고 제공하기 위해 적극적으로 노력하고 있습니다. -신규 및 숙련된 React 사용자 모두에게 더 어려운 주제 중 하나라고 들었기 때문에 현재 effect에 대한 자세한 섹션을 작성하고 있습니다. [effect와 동기화](/learn/synchronizing-with-effects)는 시리즈의 첫 번째 게시된 페이지이며 다음 주에 더 많은 페이지가 추가될 예정입니다. effect에 대한 자세한 섹션을 처음 작성하기 시작했을 때 React에 새로운 프리미티브를 추가하여 많은 일반적인 effect 패턴을 단순화할 수 있다는 것을 깨달았습니다. [useEvent RFC](https://github.com/reactjs/rfcs/pull/220)에서 이에 대한 몇 가지 초기 생각을 공유했습니다. 현재 초기 연구 단계에 있으며 여전히 아이디어를 반복하고 있습니다. 지금까지 RFC에 대한 커뮤니티의 의견과 진행 중인 문서 재작성에 대한 [피드백](https://github.com/reactjs/react.dev/issues/3308) 및 기여에 감사드립니다. 새로운 웹 사이트 구현에 대한 많은 개선 사항을 제출하고 검토한 [Harish Kumar](https://github.com/harish-sethuraman)에게 특별히 감사드립니다. +새로운 혹은 숙련된 React 사용자 모두에게 어려운 주제 중 하나라고 들었기 때문에, 현재 Effect에 대한 자세한 섹션을 작성하고 있습니다. [Effect로 동기화하기](/learn/synchronizing-with-effects)는 시리즈의 첫 번째 페이지이며 다음 주에 더 많은 페이지가 추가될 예정입니다. Effect에 대한 자세한 섹션을 처음 작성하기 시작했을 때 React에 새로운 프리미티브를 추가하여 많은 일반적인 Effect 패턴을 단순화할 수 있다는 것을 깨달았습니다. [useEvent RFC](https://github.com/reactjs/rfcs/pull/220)에서 이에 대한 몇 가지 초기 생각을 공유했습니다. 현재 초기 연구 단계에 있으며 여전히 아이디어를 반복하고 있습니다. 지금까지 RFC에 대한 커뮤니티의 의견과 진행 중인 문서 재작성에 대한 [피드백](https://github.com/reactjs/react.dev/issues/3308) 및 기여에 감사드립니다. 새로운 웹 사이트 구현에 대한 많은 개선 사항을 제출하고 검토한 [Harish Kumar](https://github.com/harish-sethuraman)에게 특별히 감사드립니다. *이 블로그 게시물을 검토해 주신 [Sophie Alpert](https://twitter.com/sophiebits)에게 감사드립니다!* From ca02700c6c243b0863e7ba3539b137727437e191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Tue, 31 Dec 2024 15:11:47 +0900 Subject: [PATCH 0461/1164] docs: update `introducing-react-dev` --- .../blog/2023/03/16/introducing-react-dev.md | 58 +++++++++---------- .../server/renderToReadableStream.md | 2 +- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/content/blog/2023/03/16/introducing-react-dev.md b/src/content/blog/2023/03/16/introducing-react-dev.md index 8b13cb55e..4aecb0440 100644 --- a/src/content/blog/2023/03/16/introducing-react-dev.md +++ b/src/content/blog/2023/03/16/introducing-react-dev.md @@ -20,29 +20,29 @@ description: 오늘 React와 React 문서의 새로운 보금자리인 react.dev ## 요약 {/*tldr*/} -* 새로운 React 사이트 ([react.dev](https://react.dev)) 는 함수 컴포넌트와 Hooks를 사용한 현대적인 React를 가르칩니다. -* 다이어그램, 삽화, 도전 과제, 그리고 600개 이상의 새로운 상호 작용하는 예시를 포함했습니다. +* 새로운 React 사이트 ([react.dev](https://react.dev))는 함수 컴포넌트와 Hook을 사용한 현대적인 React를 가르칩니다. +* 다이어그램, 삽화, 도전 과제, 그리고 600개 이상의 새로운 상호 작용 예시를 포함했습니다. * 예전 React 문서 사이트는 이제 [legacy.reactjs.org](https://legacy.reactjs.org)로 이전되었습니다. ## 새로운 사이트, 새로운 도메인, 새로운 홈페이지 {/*new-site-new-domain-new-homepage*/} 우선, 조금의 정리를 진행하겠습니다. -새로운 문서의 출시를 축하하고, 더욱 중요한 것은 오래된 내용과 새로운 내용을 명확하게 구분하기 위해, 더 짧은 [react.dev](https://react.dev) 도메인으로 이전했습니다. 예전 [reactjs.org](https://reactjs.org) 도메인은 이제 이곳으로 리다이렉트할 것입니다. +새로운 문서의 출시를 축하하고, 더욱 중요한 것은 오래된 내용과 새로운 내용을 명확하게 구분하기 위해, 더 짧은 [react.dev](https://react.dev) 도메인으로 이전했습니다. 예전 [reactjs.org](https://reactjs.org) 도메인을 이제 이곳으로 리다이렉트할 것입니다. -예전 React 문서는 이제 [legacy.reactjs.org](https://legacy.reactjs.org)에 보관되었습니다. 예전 내용으로 가는 모든 기존 링크는 "웹을 망가트리는 것"을 방지하기 위해 자동으로 해당 위치로 리다이렉트할 것이지만, 레거시 사이트는 더 이상 업데이트 받지 않을 것입니다. +예전 React 문서는 이제 [legacy.reactjs.org](https://legacy.reactjs.org)에 보관되었습니다. 예전 내용으로 통하는 모든 기존 링크는 "웹을 망가트리는 것"을 방지하기 위해 자동으로 해당 위치로 리다이렉트할 것이지만, 레거시 사이트에는 더 이상 업데이트 받지 않을 것입니다. -믿기 힘들겠지만, React는 곧 10살이 됩니다. JavaScript 시대에, 이건 마치 한 세기와 같습니다! 오늘날 React가 사용자 인터페이스를 만들기 위한 훌륭한 방법인 이유를 반영하기 위해 [React 홈페이지를 갱신하고](https://react.dev), 현대적인 React 기반 프레임워크를 더욱 명확하게 언급하기 위해 시작 가이드를 업데이트했습니다. +믿기 힘들겠지만, React는 곧 10살이 됩니다. 자바스크립트 시대에, 이건 마치 한 세기와 같습니다! 오늘날 React가 사용자 인터페이스를 만들기 위한 훌륭한 방법인 이유를 반영하기 위해 [React 홈페이지를 갱신하고](https://react.dev), 현대적인 React 기반 프레임워크를 더욱 명확하게 언급하기 위해 시작 가이드를 업데이트했습니다. 아직 새로운 홈페이지를 보지 않았다면, 꼭 확인해 보세요! -## Hooks를 사용한 현대적인 React에 전념하기 {/*going-all-in-on-modern-react-with-hooks*/} +## Hook을 사용한 현대적인 React에 전념하기 {/*going-all-in-on-modern-react-with-hooks*/} -2018년에 React Hooks를 발표했을 때, Hooks 문서는 클래스 컴포넌트에 익숙한 독자를 가정했습니다. 이는 커뮤니티가 Hooks를 매우 빠르게 채택하는 데 도움이 되었지만, 시간이 지나면서 예전 문서는 새로운 독자에게 적합하지 않았습니다. 새로운 독자는 클래스 컴포넌트와 Hooks를 사용한 것으로 React를 두 번 배워야만 했습니다. +2018년에 React Hook을 발표했을 때, Hook 문서는 클래스 컴포넌트에 익숙한 독자를 가정했습니다. 이는 커뮤니티가 Hook을 매우 빠르게 채택하는 데 도움이 되었지만, 시간이 지나면서 예전 문서는 새로운 독자에게 적합하지 않았습니다. 새로운 독자는 클래스 컴포넌트와 Hook을 사용한 것으로 React를 두 번 배워야만 했습니다. -**새로운 문서는 Hooks를 사용한 React를 처음부터 가르칩니다.** 문서는 두 가지 주요 섹션으로 나뉘어져 있습니다. +**새로운 문서는 Hook을 사용한 React를 처음부터 가르칩니다.** 문서는 두 가지 주요 섹션으로 나뉘어져 있습니다. -* **[React 배우기](/learn)** 는 React를 기초부터 스스로 학습할 수 있는 과정입니다. +* **[React 학습하기](/learn)** 는 React를 기초부터 스스로 학습할 수 있는 과정입니다. * **[API 참고서](/reference)** 는 모든 React API에 대한 세부 내용과 사용 예시를 제공합니다. 각 섹션에서 무슨 내용을 알 수 있는지 자세히 살펴보겠습니다. @@ -55,9 +55,9 @@ description: 오늘 React와 React 문서의 새로운 보금자리인 react.dev ## 빠르게 시작하기 {/*quick-start*/} -학습 섹션은 [빠르게 시작하기](/learn) 페이지로 시작됩니다. 이는 React를 짧게 소개하는 여정입니다. 컴포넌트, props, state 같은 개념에 대한 문법을 소개하지만, 그들을 어떻게 사용하는지에 대한 세부 내용을 다루진 않습니다. +학습 섹션은 [빠르게 시작하기](/learn) 페이지로 시작합니다. 이는 React를 짧게 소개하는 여정입니다. 컴포넌트, Props, State 같은 개념에 대한 문법을 소개하지만, 그들을 어떻게 사용하는지에 대한 세부 내용을 다루진 않습니다. -직접 해보며 배우고 싶다면, 다음으로 [Tic-Tac-Toe 자습서](/learn/tutorial-tic-tac-toe)를 확인하는 것을 추천합니다. React로 작은 게임을 구현하는 것을 자세히 설명하면서, 동시에 일상적으로 사용할 기술을 가르칩니다. 여기에 구현하게 될 내용이 있습니다. +직접 해보며 배우고 싶다면, 다음으로 [자습서: 틱택토 게임](/learn/tutorial-tic-tac-toe)을 확인하는 것을 추천합니다. React로 작은 게임을 구현하는 것을 자세히 설명하면서, 동시에 일상적으로 사용할 기술을 가르칩니다. 여기에 구현하게 될 내용이 있습니다. <Sandpack> @@ -226,11 +226,11 @@ body { </Sandpack> -또한 많은 사람에게 React를 "완전히 이해시켜 준" 자습서인 [React로 사고하기](/learn/thinking-in-react)도 강조하고 싶습니다. **두 가지 클래식 자습서 모두 함수 컴포넌트와 Hooks를 사용하도록 업데이트했고,** 따라서 새 자습서만큼 좋습니다. +또한 많은 사람에게 React를 "완전히 이해시켜 준" 자습서인 [React로 사고하기](/learn/thinking-in-react)도 강조하고 싶습니다. **두 가지 클래식 자습서 모두 함수 컴포넌트와 Hook을 사용하도록 업데이트했기에**, 새 자습서만큼 훌륭합니다. <Note> -위쪽에 있는 예시는 *샌드박스*입니다. 우리는 600개 이상의 많은 샌드박스를 사이트 전체 모든 곳에 추가했습니다. 아무 샌드박스나 편집할 수 있고, 우측 상단에 있는 "Fork"를 눌러 별도의 탭에서 열 수 있습니다. 샌드박스는 React API를 빠르게 갖고 놀면서, 아이디어를 탐구하고, 이해를 확인하게 해줍니다. +위쪽에 있는 예시는 *샌드박스*입니다. 우리는 600개 이상의 많은 샌드박스를 사이트 전체에 추가했습니다. 모든 샌드박스를 편집할 수 있고, 우측 상단에 있는 "Fork"를 눌러 별도의 탭에서 열 수 있습니다. 샌드박스는 React API를 빠르게 갖고 놀면서, 아이디어를 탐구하고, 이해를 확인하게 해줍니다. </Note> @@ -240,15 +240,15 @@ body { 이것이 학습 섹션이 여러 개의 장으로 구분된 자기 주도 학습 과정으로 구성된 이유입니다. 처음 두 장은 React의 기초에 관해서 설명합니다. React가 처음이거나 기억을 되살리고 싶다면, 여기서부터 시작하세요. -- **[UI 표현하기](/learn/describing-the-ui)**에서는 컴포넌트로 어떻게 정보를 표시하는지 가르칩니다. -- **[상호작용 추가하기](/learn/adding-interactivity)**에서는 사용자 입력에 대한 응답으로 화면을 어떻게 업데이트하는지 가르칩니다. +- <strong>[UI 표현하기](/learn/describing-the-ui)</strong>에서는 컴포넌트로 어떻게 정보를 표시하는지 가르칩니다. +- <strong>[상호작용 추가하기](/learn/adding-interactivity)</strong>에서는 사용자 입력에 대한 응답으로 화면을 어떻게 업데이트하는지 가르칩니다. 다음 두 장은 더욱 고급 내용을 다루며, 더 복잡한 부분에 대해서 깊은 통찰을 줄 것입니다. -- **[State 관리하기](/learn/managing-state)**에서는 앱의 복잡성이 증가함에 따라 어떻게 로직을 조직화하는지 가르칩니다. -- **[탈출구](/learn/escape-hatches)**에서는 React "외부로 탈출"할 방법과, 이를 수행하기에 가장 적절한 시기를 가르칩니다. +- <strong>[State 관리하기](/learn/managing-state)</strong>에서는 앱의 복잡성이 증가함에 따라 어떻게 로직을 조직화하는지 가르칩니다. +- <strong>[탈출구](/learn/escape-hatches)</strong>에서는 React "외부로 탈출"할 방법과, 이를 수행하기에 가장 적절한 시기를 가르칩니다. -모든 장은 여러 개의 관련된 페이지로 구성되어 있습니다. 대부분의 페이지는 특정 기술이나 기법을 가르칩니다-예를 들어, [JSX로 마크업 작성하기](/learn/writing-markup-with-jsx), [State에 있는 객체 업데이트하기](/learn/updating-objects-in-state)나 [컴포넌트 간 State 공유하기](/learn/sharing-state-between-components) 같은 것들이 있습니다. [렌더와 커밋](/learn/render-and-commit), [스냅샷으로서의 State](/learn/state-as-a-snapshot)와 같은 몇몇 페이지들은 아이디어를 설명하는 것에 집중합니다. 그리고 지난 몇 년 동안의 경험을 기반으로 제안을 공유하는 [Effect가 필요하지 않을 수 있습니다](/learn/you-might-not-need-an-effect) 같은 페이지도 몇 개 있습니다. +모든 장은 여러 개의 관련된 페이지로 구성되어 있습니다. 대부분의 페이지는 특정 기술이나 기법을 가르칩니다. 예를 들어, [JSX로 마크업 작성하기](/learn/writing-markup-with-jsx), [State에 있는 객체 업데이트하기](/learn/updating-objects-in-state)나 [컴포넌트 간 State 공유하기](/learn/sharing-state-between-components) 같은 것들이 있습니다. [렌더링 그리고 커밋](/learn/render-and-commit), [스냅샷으로서의 State](/learn/state-as-a-snapshot)와 같은 몇몇 페이지들은 아이디어를 설명하는 것에 집중합니다. 그리고 지난 몇 년 동안의 경험을 기반으로 제안을 공유하는 [Effect가 필요하지 않을 수도 있습니다](/learn/you-might-not-need-an-effect) 같은 페이지도 몇 개 있습니다. 이러한 장들을 순서대로 읽을 필요는 없습니다. 누가 그런 시간이 있을까요?! 하지만 읽을 수도 있습니다. 학습 섹션에 있는 페이지는 오로지 이전 페이지에 소개된 개념에만 의존합니다. 책처럼 읽고 싶다면, 도전해 보세요! @@ -342,7 +342,7 @@ export default function PackingList() { #### `&&`로 항목의 중요성을 보여주세요 {/*show-the-item-importance-with-*/} -이 예시에서는, 각 `Item`이 숫자로 된 `importance` prop을 받습니다. 오직 중요도가 0이 아닌 항목만 "_(중요도: X)_"을 이탤릭체로 렌더링하기 위해 `&&` 연산자를 사용하세요. 아이템 목록은 최종적으로 이렇게 되어야 합니다: +이 예시에서는, 각 `Item`이 숫자로 된 `importance` prop을 받습니다. 오직 중요도가 `0`이 아닌 항목만 "_(중요도: X)_"을 이탤릭체로 렌더링하기 위해 `&&` 연산자를 사용하세요. 아이템 목록은 최종적으로 이렇게 되어야 합니다: * 우주복 _(중요도: 9)_ * 금색 잎사귀가 달린 헬멧 @@ -442,7 +442,7 @@ export default function PackingList() { ### 다이어그램과 삽화로 직관력을 높여보세요 {/*build-an-intuition-with-diagrams-and-illustrations*/} -코드와 단어만으로 어떤 것을 설명하기 어려운 경우, 직관적으로 도움을 주는 다이어그램을 추가했습니다. 예를 들어, 여기 [State를 보장하고 재설정하기](/learn/preserving-and-resetting-state)에 있는 다이어그램 중 하나가 있습니다. +코드와 단어만으로 어떤 것을 설명하기 어려운 경우, 직관적으로 도움을 주는 다이어그램을 추가했습니다. 예를 들어, 여기 [State를 보존하고 초기화하기](/learn/preserving-and-resetting-state)에 있는 다이어그램 중 하나가 있습니다. <Diagram name="preserving_state_diff_same_pt1" height={350} width={794} alt="다이어그램에는 세 개의 섹션이 있으며, 각 섹션 사이에 전환되는 화살표가 있습니다. 첫 번째 섹션에는 'div'로 레이블 된 React 컴포넌트가 있습니다. 이 컴포넌트의 단일 자식으로 'section'이라고 레이블 된 섹션이 있으며, 그 안에 'Counter'라고 레이블 된 컴포넌트가 있습니다. 이 컴포넌트 안에는 'count'라고 레이블 된 state 버블이 있으며 값은 3입니다. 중간 섹션에는 동일한 'div' 부모가 있지만, 이제는 하위 컴포넌트들이 삭제되었습니다. 이를 노란색 'proof' 이미지로 표시합니다. 세 번째 섹션에는 다시 동일한 'div' 부모가 있으며, 이번에는 'div'라고 레이블 된 새로운 하위 컴포넌트가 추가되었습니다. 이 컴포넌트 안에는 'Counter'라고 레이블 된 컴포넌트가 있으며, 그 안에 'count'라고 레이블 된 state 버블이 있습니다. 이번에는 값이 0으로 표시됩니다. 모든 부분이 노란색으로 강조되어 있습니다."> @@ -450,7 +450,7 @@ export default function PackingList() { </Diagram> -또한 문서 곳곳에서 몇몇 삽화를 보게 될 것입니다--여기 [화면을 그리는 브라우저](/learn/render-and-commit#epilogue-browser-paint) 중 하나가 있습니다. +또한 문서 곳곳에서 몇몇 삽화를 보게 될 것입니다. 여기 [화면을 그리는 브라우저](/learn/render-and-commit#epilogue-browser-paint) 중 하나가 있습니다. <Illustration alt="'카드 요소가 있는 정물화'를 그리는 브라우저" src="/images/docs/illustrations/i_browser-paint.png" /> @@ -460,23 +460,23 @@ export default function PackingList() { [API 참고서](/reference/react)에서, 이제 모든 React API는 전용 페이지를 가집니다. 모든 종류의 API들이 포함됩니다. -- [`useState`](/reference/react/useState) 같은 내장 Hooks +- [`useState`](/reference/react/useState) 같은 내장 Hook - [`<Suspense>`](/reference/react/Suspense) 같은 내장 컴포넌트 - [`<input>`](/reference/react-dom/components/input) 같은 브라우저 내장 컴포넌트 - [`renderToPipeableStream`](/reference/react-dom/server/renderToReadableStream) 같은 프레임워크 지향 API - [`memo`](/reference/react/memo) 같은 그 밖의 React API - +r 모든 API 페이지가 *레퍼런스* 와 *사용법*을 포함하는 최소 두 개의 세그먼트로 나뉘어 있다는 것을 알 수 있습니다. [레퍼런스](/reference/react/useState#reference)는 인자와 반환 값을 나열하여 형식적인 API 서명을 설명합니다. 이는 간결하지만, 해당 API에 익숙하지 않다면 약간 추상적으로 느껴질 수 있습니다. 이것은 API를 어떻게 사용하는지가 아닌, API가 무엇을 하는지를 설명합니다. [사용법](/reference/react/useState#usage)은 동료나 친구가 설명하는 것처럼 실제로 API를 사용하는 이유와 방법을 보여줍니다. **이는 React 팀에서 각 API가 어떻게 사용되기를 의도한 것인지에 대한 표준적인 시나리오**를 보여줍니다. 색상 있는 코드 스니펫, 서로 다른 API들을 함께 사용하는 예시, 복사 및 붙여넣기 할 수 있는 레시피를 추가했습니다. -<Recipes titleText="Basic useState examples" titleId="examples-basic"> +<Recipes titleText="기본 useState 예시" titleId="examples-basic"> #### 카운터 (숫자) {/*counter-number*/} -이 예시에서 `count` state 변수는 숫자를 저장합니다. 버튼을 누르면 숫자가 증가합니다. +이 예시에서 `count` State 변수는 숫자를 저장합니다. 버튼을 누르면 숫자가 증가합니다. <Sandpack> @@ -504,7 +504,7 @@ export default function Counter() { #### 텍스트 필드 (문자열) {/*text-field-string*/} -이 예시에서 `text` state 변수는 문자열을 저장합니다. 문자를 입력할 때, `handleChange`가 브라우저의 input DOM 요소로부터 가장 최근에 입력된 값을 읽고 state를 업데이트하기 위해 `setText`를 호출합니다. 이에 따라 현재의 `text`를 아래에 표시할 수 있습니다. +이 예시에서 `text` State 변수는 문자열을 저장합니다. 문자를 입력할 때, `handleChange`가 브라우저의 Input DOM 요소로부터 가장 최근에 입력된 값을 읽고 State를 업데이트하기 위해 `setText`를 호출합니다. 이에 따라 현재의 `text`를 아래에 표시할 수 있습니다. <Sandpack> @@ -536,7 +536,7 @@ export default function MyInput() { #### 체크박스 (불리언) {/*checkbox-boolean*/} -이 예시에서 `liked` state 변수는 불리언을 저장합니다. input 요소를 클릭할 때, `setLiked`가 브라우저 체크박스의 선택 여부에 따라 `liked` state 변수를 업데이트합니다. `liked`는 체크박스 아래에 있는 문구를 렌더링하는 데 사용됩니다. +이 예시에서 `liked` State 변수는 불리언을 저장합니다. Input 요소를 클릭할 때, `setLiked`가 브라우저 체크박스의 선택 여부에 따라 `liked` state 변수를 업데이트합니다. `liked`는 체크박스 아래에 있는 문구를 렌더링하는 데 사용됩니다. <Sandpack> @@ -572,7 +572,7 @@ export default function MyCheckbox() { #### 양식 (두 가지 변수) {/*form-two-variables*/} -하나의 컴포넌트에서 여러 개의 state 변수를 선언할 수 있습니다. 각각의 state 변수는 완전히 독립적입니다. +하나의 컴포넌트에서 여러 개의 State 변수를 선언할 수 있습니다. 각각의 State 변수는 완전히 독립적입니다. <Sandpack> @@ -626,7 +626,7 @@ button { display: block; margin-top: 10px; } - 새로운 문서가 번역되도록 전 세계 커뮤니티와 협업하기 - 새로운 웹 사이트에 놓친 기능 추가하기 (예를 들어, 이 블로그를 위한 RSS) -이제 [react.dev](https://react.dev/)가 출시되었으니, 제삼자 React 교육 자료를 "따라잡는" 데서 벗어나 새로운 정보를 추가하고 새 웹 사이트를 더욱 개선하는 데 집중할 수 있게 되었습니다. +이제 [react.dev](https://react.dev/)가 출시되었으니, 제 삼자 React 교육 자료를 "따라잡는" 데서 벗어나 새로운 정보를 추가하고 새 웹 사이트를 더욱 개선하는 데 집중할 수 있게 되었습니다. React를 배우기에 가장 좋은 시기가 왔다고 생각합니다. diff --git a/src/content/reference/react-dom/server/renderToReadableStream.md b/src/content/reference/react-dom/server/renderToReadableStream.md index fca41bb75..24563d4c1 100644 --- a/src/content/reference/react-dom/server/renderToReadableStream.md +++ b/src/content/reference/react-dom/server/renderToReadableStream.md @@ -4,7 +4,7 @@ title: renderToReadableStream <Intro> -`renderToReadableStream`는 [Readable Web Stream.](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)를 이용해 React tree를 그립니다. +`renderToReadableStream`는 [Readable Web Stream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)을 이용해 React tree를 그립니다. ```js const stream = await renderToReadableStream(reactNode, options?) From 88b50317ac2c53d66cce703e669ce712329c0258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Tue, 31 Dec 2024 20:45:30 +0900 Subject: [PATCH 0462/1164] docs: update `react-labs-what-we-have-been-wroking-...-.md` --- ...what-we-have-been-working-on-march-2023.md | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md b/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md index 4ef33b6bc..dcc29aab1 100644 --- a/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md +++ b/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md @@ -19,17 +19,17 @@ React Labs 게시글에는 활발히 연구 개발 중인 프로젝트에 대한 ## React 서버 컴포넌트 {/*react-server-components*/} -React 서버 컴포넌트(React Server Components, 또는 RSC)는 React 팀에서 설계한 새로운 애플리케이션 아키텍처입니다. +React 서버 컴포넌트<sup>React Server Components, RSC</sup>는 React 팀에서 설계한 새로운 애플리케이션 아키텍처입니다. -우리는 먼저 [소개 발표](/blog/2020/12/21/data-fetching-with-react-server-components)와 [RFC](https://github.com/reactjs/rfcs/pull/188)에서 RSC에 대한 연구를 공유했습니다. 그 내용을 요약하면, 미리 실행하고 JavaScript 번들에서 제외할 수 있는 새로운 종류의 컴포넌트인 서버 컴포넌트를 소개하고 있습니다. 서버 컴포넌트는 빌드 중에 실행되어 파일 시스템에서 읽거나 정적 콘텐츠를 가져올 수 있습니다. 또한 서버에서 실행할 수 있어 API를 빌드할 필요 없이 데이터 계층에 접근할 수 있습니다. props를 통해 서버 컴포넌트에서 상호작용하는 브라우저의 클라이언트 컴포넌트로 데이터를 전달할 수 있습니다. +우리는 먼저 [소개 발표](/blog/2020/12/21/data-fetching-with-react-server-components)와 [RFC](https://github.com/reactjs/rfcs/pull/188)에서 RSC에 대한 연구를 공유했습니다. 그 내용을 요약하면, 미리 실행하고 자바스크립트 번들에서 제외할 수 있는 새로운 종류의 컴포넌트인 서버 컴포넌트를 소개하고 있습니다. 서버 컴포넌트는 빌드 중에 실행되어 파일 시스템에서 읽거나 정적 콘텐츠를 가져올 수 있습니다. 또한 서버에서 실행할 수 있어 API를 빌드할 필요 없이 데이터 계층에 접근할 수 있습니다. Props를 통해 서버 컴포넌트에서 상호작용하는 브라우저의 클라이언트 컴포넌트로 데이터를 전달할 수 있습니다. RSC는 서버 중심의 멀티 페이지 애플리케이션의 간단한 "요청/응답" 멘탈 모델에 클라이언트 중심의 싱글 페이지 애플리케이션의 원활한 상호작용을 결합하여 양쪽의 장점을 모두 제공합니다. 지난 업데이트 이후 우리는 제안을 승인하기 위해 [React 서버 컴포넌트 RFC](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md)를 병합했습니다. [React 서버 모듈 컨벤션](https://github.com/reactjs/rfcs/blob/main/text/0227-server-module-conventions.md) 제안과 관련된 남아 있는 문제를 해결했고, 동료들과 `"use client"` 컨벤션을 따르기로 합의했습니다. 이러한 문서들은 RSC와 호환할 수 있는 구현 방식이 지원해야 하는 것에 대한 명세로도 사용됩니다. -가장 큰 변경 점은 서버 컴포넌트에서 데이터를 가져오는 기본 방법으로 [`async` / `await`](https://github.com/reactjs/rfcs/pull/229)를 도입했다는 점입니다. 또한 Promise의 결과를 읽는 새로운 `use` Hook을 도입하여 클라이언트에서 데이터를 불러오는 것을 지원할 계획입니다. 비록 클라이언트 전용 애플리케이션의 임의의 컴포넌트에서 `async / await`를 지원할 수는 없지만, RSC 애플리케이션의 구조와 유사하게 클라이언트 전용 애플리케이션을 구성할 때를 위한 지원을 추가할 계획입니다. +가장 큰 변경 점은 서버 컴포넌트에서 데이터를 가져오는 기본 방법으로 [`async` / `await`](https://github.com/reactjs/rfcs/pull/229)을 도입했다는 점입니다. 또한 Promise의 결과를 읽는 새로운 `use` Hook을 도입하여 클라이언트에서 데이터를 불러오는 것을 지원할 계획입니다. 비록 클라이언트 전용 애플리케이션의 임의의 컴포넌트에서 `async` / `await`을 지원할 수는 없지만, RSC 애플리케이션의 구조와 유사하게 클라이언트 전용 애플리케이션을 구성할 때를 위한 지원을 추가할 계획입니다. -이제 데이터 가져오기가 어느 정도 잘 정리되었으므로 다른 방향을 살펴보고 있습니다. 바로 클라이언트에서 서버로 데이터를 전송하여 데이터베이스 변경을 실행하고 폼을 구현할 수 있도록 하는 것입니다. 서버와 클라이언트의 경계를 넘어 서버 액션 함수를 전달하면 클라이언트가 이를 호출하여 원활한 RPC를 제공할 수 있습니다. 서버 액션은 또한 JavaScript를 불러오기 전에 점진적으로 향상된 폼을 제공합니다. +이제 데이터 가져오기<sup>Fetching</sup>가 어느 정도 잘 정리되었으므로 다른 방향을 살펴보고 있습니다. 바로 클라이언트에서 서버로 데이터를 전송하여 데이터베이스 변경을 실행하고 폼을 구현할 수 있도록 하는 것입니다. 서버와 클라이언트의 경계를 넘어 서버 액션 함수를 전달하면 클라이언트가 이를 호출하여 원활한 RPC를 제공할 수 있습니다. 서버 액션은 또한 자바스크립트를 불러오기 전에 점진적으로 향상된 폼을 제공합니다. React 서버 컴포넌트는 [Next.js App 라우터](/learn/start-a-new-react-project#nextjs-app-router)에 포함되어 있습니다. Next.js에서는 라우터와 깊은 결합을 통해 RSC를 기본 요소로 받아들이는 것을 보여줍니다. 그러나 이 방법이 RSC와 호환할 수 있는 라우터나 프레임워크를 구축하는 유일한 방법은 아닙니다. RSC 명세와 구현에서 제공하는 기능에는 명확한 구분이 있습니다. React 서버 컴포넌트는 호환할 수 있는 React 프레임워크에서 동작하는 컴포넌트에 대한 명세입니다. @@ -37,9 +37,9 @@ React 서버 컴포넌트는 [Next.js App 라우터](/learn/start-a-new-react-pr ## 에셋 불러오기 {/*asset-loading*/} -[Suspense](/reference/react/Suspense)는 컴포넌트의 데이터나 코드를 불러오는 동안 화면에 표시할 내용을 지정할 수 있게 해줍니다. 이를 통해 사용자는 페이지를 불러오는 동안뿐만 아니라 더 많은 데이터와 코드를 불러오는 라우터 내비게이션 중에서도 점진적으로 더 많은 콘텐츠를 볼 수 있습니다. 그러나 사용자의 관점에서 새로운 콘텐츠가 준비되었는지를 고려할 때 데이터를 불러오고 렌더링하는 것이 모든 것을 알려주지는 않습니다. 기본적으로 브라우저는 스타일시트, 글꼴 및 이미지를 독립적으로 불러오기 때문에 UI 점프와 연속적인 레이아웃 이동이 발생할 수 있습니다. +[Suspense](/reference/react/Suspense)를 통해 컴포넌트의 데이터나 코드를 불러오는 동안 화면에 표시할 내용을 지정할 수 있습니다. 이를 통해 사용자는 페이지를 불러오는 동안 뿐만 아니라 더 많은 데이터와 코드를 불러오는 라우터 내비게이션 중에서도 점진적으로 더 많은 콘텐츠를 볼 수 있습니다. 그러나 사용자의 관점에서 새로운 콘텐츠가 준비되었는지를 고려할 때 데이터를 불러오고 렌더링하는 것이 모든 것을 알려주지는 않습니다. 기본적으로 브라우저는 스타일시트, 글꼴 및 이미지를 독립적으로 불러오기 때문에 UI 점프와 연속적인 레이아웃 이동이 발생할 수 있습니다. -우리는 Suspense가 스타일시트, 글꼴 및 이미지를 불러오는 생명주기와 완전히 통합되도록 작업하고 있습니다. 이를 통해 React가 콘텐츠가 화면에 표시할 준비가 되었는지 판단할 수 있도록 노력하고 있습니다. 업데이트는 React 컴포넌트 작성 방식에 어떠한 변경도 없이 더 일관되고 만족스러운 방식으로 진행할 것입니다. 최적화를 위해 글꼴과 같은 에셋을 컴포넌트에서 직접 미리 불러오는 수동 방법도 제공할 것입니다. +저희는 Suspense가 스타일시트, 글꼴 및 이미지를 불러오는 생명주기와 완전히 통합되도록 작업하고 있습니다. 이를 통해 React의 콘텐츠가 화면에 표시할 준비가 되었는지 판단할 수 있도록 노력하고 있습니다. 업데이트는 React 컴포넌트 작성 방식에 어떠한 변경도 없이, 더 일관되고 만족을 주는 방식으로 진행할 것입니다. 최적화를 위해 글꼴과 같은 에셋을 컴포넌트에서 직접 미리 불러오는 수동적인 방법도 제공할 것입니다. 현재 이러한 기능들을 구현하고 있으며 곧 더 많은 정보를 공유하겠습니다. @@ -49,7 +49,7 @@ React 서버 컴포넌트는 [Next.js App 라우터](/learn/start-a-new-react-pr 현재 개발자는 두 가지 기술 중 하나의 방법으로 이 문제를 해결합니다. -한 가지 방법은 `<title>`, `<meta>`, 그리고 그 안의 다른 태그들을 문서의 `<head>`로 이동시키는 특별한 서드파티 컴포넌트를 렌더링하는 방법입니다. 이 방법은 주요 브라우저에서는 작동하지만, Open Graph 파서와 같이 클라이언트 측에서 JavaScript를 실행하지 않는 클라이언트가 많기 때문에 보편적으로 적합하지 않습니다. +한 가지 방법은 `<title>`, `<meta>`, 그리고 그 안의 다른 태그들을 문서의 `<head>`로 이동시키는 특별한 서드파티 컴포넌트를 렌더링하는 방법입니다. 이 방법은 주요 브라우저에서는 작동하지만, Open Graph 파서<sup>Parser</sup>와 같이 클라이언트 측에서 자바스크립트를 실행하지 않는 클라이언트가 많기 때문에 보편적으로 적합하지 않습니다. 또 다른 방법은 페이지를 두 부분으로 나누어 서버 렌더링하는 방법입니다. 먼저 주요 콘텐츠를 렌더링한 후 이러한 모든 태그가 수집됩니다. 그런 다음 수집한 태그를 이용하여 `<head>`를 렌더링합니다. 마지막으로 `<head>`와 주요 콘텐츠를 브라우저로 전송합니다. 이 접근법은 잘 작동하지만, `<head>`가 전송되기 전에 모든 콘텐츠가 렌더링 때까지 기다려야 하므로 [React 18의 Streaming Server Renderer](/reference/react-dom/server/renderToReadableStream)의 장점을 활용할 수 없습니다. @@ -57,27 +57,27 @@ React 서버 컴포넌트는 [Next.js App 라우터](/learn/start-a-new-react-pr ## React 최적화 컴파일러 {/*react-optimizing-compiler*/} -지난 업데이트 이후 우리는 React의 최적화 컴파일러인 [React Forget](/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022#react-compiler)의 설계를 적극적으로 반복하며 작업하고 있습니다. 이전에 이를 "자동 memoizing 컴파일러"라고 언급했고, 어떤 의미에서는 사실입니다. 그러나 컴파일러를 구축하면서 React의 프로그래밍 모델을 더 깊이 이해하는 데 도움이 되었습니다. React Forget을 이해하는 더 좋은 방법은 자동 *반응성* 컴파일러입니다. +지난 업데이트 이후 우리는 React의 최적화 컴파일러인 [React Forget](/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022#react-compiler)의 설계를 적극적으로 반복하며 작업하고 있습니다. 이전에 이를 "자동 Memoizing 컴파일러"라고 언급했고, 어떤 의미에서는 사실입니다. 그러나 컴파일러를 구축하면서 React의 프로그래밍 모델을 더 깊이 이해하는 데 도움이 되었습니다. React Forget을 이해하는 더 좋은 방법은 자동 *반응성* 컴파일러입니다. -React의 핵심 아이디어는 개발자가 현재 state의 함수로 UI를 정의하는 것입니다. 숫자, 문자열, 배열, 객체와 같은 순수한 JavaScript의 값과 if/else, for 등 표준 JavaScript 관용구를 사용하여 컴포넌트 로직을 표현합니다. 멘탈 모델은 애플리케이션 state를 변경할 때마다 React가 다시 렌더링한다는 것입니다. 우리는 이런 간단한 멘탈 모델과 JavaScript 의미론에 가깝게 유지하는 것이 React 프로그래밍 모델의 중요한 원칙이라고 생각합니다. +React의 핵심 아이디어는 개발자가 현재 State의 함수로 UI를 정의하는 것입니다. 숫자, 문자열, 배열, 객체와 같은 순수한 자바스크립트의 값과 `if`/`else`, `for` 등 표준 자바스크립트트 관용구를 사용하여 컴포넌트 로직을 표현합니다. 멘탈 모델은 애플리케이션 State를 변경할 때마다 React가 다시 렌더링한다는 것입니다. 우리는 이런 간단한 멘탈 모델과 자바스크립트 의미론에 가깝게 유지하는 것이 React 프로그래밍 모델의 중요한 원칙이라고 생각합니다. -문제는 React는 너무 많이 다시 렌더링하는 등 때때로 *지나치게* 반응적일 수 있습니다. 예시로 JavaScript에서 두 개의 객체나 배열이 동등한지(동일한 key와 값을 가졌는지) 비교하는 저렴한 방법이 없으므로, 렌더링마다 새로운 객체나 배열을 생성하는 것은 React가 엄밀하게 필요한 것보다 더 많은 작업을 수행하게 될 수도 있습니다. 이는 개발자가 컴포넌트가 지나치게 반응적이지 않도록 명시적으로 컴포넌트를 메모해야 함을 의미합니다. +문제는 React가 너무 자주 다시 렌더링하는 등 때때로 *지나치게* 반응적일 수 있습니다. 예시로 자바스크립트에서 두 개의 객체나 배열이 동등한지(동일한 key와 값을 가졌는지) 비교하는 저렴한 방법이 없으므로, 렌더링마다 새로운 객체나 배열을 생성하는 것은 React가 엄밀하게 필요한 것보다 더 많은 작업을 수행하게 될 수도 있습니다. 이는 개발자가 컴포넌트가 지나치게 반응적이지 않도록 명시적으로 컴포넌트를 메모해야 함을 의미합니다. -React Forget의 목표는 React 애플리케이션이 기본적으로 적당한 반응성을 갖도록 하는 것입니다. 즉, 오직 state 값을 *의미 있게* 변경할 때만 애플리케이션을 다시 렌더링 되도록 하는 것입니다. 구현의 관점에서 이는 자동으로 메모하는 것을 의미하지만, 반응성 프레이밍이 React와 Forget을 이해하는 더 좋은 방법이라고 생각합니다. 이에 대해 생각해 볼 수 있는 하나의 방법은 현재의 React가 객체 ID가 변경될 때 다시 렌더링한다는 것입니다. Forget을 사용하면 React는 의미상으로 값을 변경할 때 다시 렌더링하지만, 깊은 비교를 위한 런타임 비용을 발생시키지 않습니다. +React Forget의 목표는 React 애플리케이션이 기본적으로 적당한 반응성을 갖도록 하는 것입니다. 즉, 오직 State 값을 *의미 있게* 변경할 때만 애플리케이션을 다시 렌더링 되도록 하는 것입니다. 구현의 관점에서 이는 자동으로 메모하는 것을 의미하지만, 반응성 프레이밍이 React와 Forget을 이해하는 더 좋은 방법이라고 생각합니다. 이에 대해 생각해 볼 수 있는 하나의 방법은 현재의 React가 객체 ID가 변경될 때 다시 렌더링한다는 것입니다. Forget을 사용하면 React는 의미상으로 값을 변경할 때 다시 렌더링하지만, 깊은 비교를 위한 런타임 비용을 발생시키지 않습니다. 구체적인 진행 상황을 이야기하자면, 지난 업데이트 이후 컴파일러 설계를 자동 반응성 방식에 맞추고 내부적으로 컴파일러를 사용하며 얻은 피드백을 포함하기 위해 상당히 많은 반복 작업을 가졌습니다. 작년 말부터 시작한 컴파일러에 대한 몇 가지 중요한 리팩토링을 진행한 후, 이제 Meta에서 제품 환경의 제한된 부분에서 이를 사용하기 시작했습니다. 제품 환경에서 검증이 끝나면 오픈소스로 공개하려고 합니다. -마지막으로 많은 사람이 컴파일러가 어떻게 작동하는지 관심을 표현해 주셨습니다. 컴파일러를 검증하고 오픈소스로 공개할 때 더 많은 세부 사항을 공유할 수 있기를 기대하고 있습니다. 하지만 당장 공유할 수 있는 몇 가지가 있습니다. +마지막으로, 많은 분들이 컴파일러가 어떻게 동작하는지에 대해 관심을 가져주셨습니다. 컴파일러를 검증하고 오픈소스로 공개할 때 더 많은 세부 사항을 공유할 수 있기를 기대합니다. 하지만 당장 공유할 수 있는 몇 가지가 있습니다. -컴파일러의 핵심 부분을 Babel과 거의 분리했고, 핵심 컴파일러 API는 원본 위치 데이터를 유지하면서 대략 오래된 AST를 입력받아 새로운 AST를 반환합니다. 내부적으로는 저수준의 의미 분석을 수행하기 위해 맞춤형 코드 표현과 변환 파이프라인을 사용합니다. 그러나 컴파일러에 대한 기본 공개 인터페이스는 Babel 및 다른 빌드 시스템 플러그인을 통해 이루어집니다. 테스트 용이성을 위해 컴파일러를 호출하여 각 함수의 새로운 버전을 생성하고 교체하는 매우 얇은 래퍼인 Babel 플러그인을 가지고 있습니다. +컴파일러의 핵심 부분을 Babel과 거의 분리했고, 핵심 컴파일러 API는 원본 위치 데이터를 유지하면서 (약간) 오래된 AST를 입력받아 새로운 AST를 반환합니다. 내부적으로는 저수준의 의미 분석을 수행하기 위해 맞춤형 코드 표현과 변환 파이프라인을 사용합니다. 그러나 컴파일러에 대한 기본 공개 인터페이스는 Babel 및 다른 빌드 시스템 플러그인을 통해 이루어집니다. 테스트 용이성을 위해 컴파일러를 호출하여 각 함수의 새로운 버전을 생성하고 교체하는 매우 얇은 래퍼인 Babel 플러그인을 가지고 있습니다. -지난 몇 달 동안 컴파일러를 리팩토링하며 조건문, 반복문, 재할당, 변형과 같은 복잡성을 처리할 수 있는 핵심 컴파일 모델을 개선하는 데 집중하고 싶었습니다. 그러나 JavaScript에는 if/else, 삼항 연산자, for, for-in, for-of 등 각각의 기능을 표현하는 다양한 방법이 있습니다. 처음부터 언어의 전체 기능을 지원하려고 하면 핵심 모델을 검증하는 시점이 지연되었을 것입니다. 대신, let/const, if/else, for 루프, 객체, 배열, 원시 값, 함수 호출 등 작지만 JavaScript 언어를 대표하는 하위 집합부터 시작했습니다. 핵심 모델에 대한 자신감을 얻고 내부 추상화를 개선하면서 지원하는 언어의 하위 집합을 확장했습니다. 또한 아직 지원하지 않는 문법에 대해 명시적으로 로깅 진단 정보를 남기고, 지원되지 않는 입력에 대한 컴파일을 건너뛰고 있습니다. Meta의 코드베이스에서 컴파일러를 사용한 후 가장 많이 지원되지 않는 기능이 무엇인지 확인할 수 있는 유틸리티를 가지고 있습니다. 이를 통해 해당 기능들을 우선으로 작업할 수 있습니다. 우리는 전체 언어를 지원하도록 점진적으로 확장할 계획입니다. +지난 몇 달 동안 컴파일러를 리팩토링하며 조건문, 반복문, 재할당, 변형과 같은 복잡성을 처리할 수 있는 핵심 컴파일 모델을 개선하는 데 집중하고 싶었습니다. 그러나 자바스크립트에는 if/else, 삼항 연산자, for, for-in, for-of 등 각각의 기능을 표현하는 다양한 방법이 있습니다. 처음부터 언어의 전체 기능을 지원하려고 하면 핵심 모델을 검증하는 시점이 지연되었을 것입니다. 대신, let/const, if/else, for 루프, 객체, 배열, 원시 값, 함수 호출 등 작지만 자바스크립트 언어를 대표하는 하위 집합부터 시작했습니다. 핵심 모델에 대한 자신감을 얻고 내부 추상화를 개선하면서 지원하는 언어의 하위 집합을 확장했습니다. 또한 아직 지원하지 않는 문법에 대해 명시적으로 로깅 진단 정보를 남기고, 지원되지 않는 입력에 대한 컴파일을 건너뛰고 있습니다. Meta의 코드베이스에서 컴파일러를 사용한 후 가장 많이 지원되지 않는 기능이 무엇인지 확인할 수 있는 유틸리티를 가지고 있습니다. 이를 통해 해당 기능들을 우선으로 작업할 수 있습니다. 우리는 전체 언어를 지원하도록 점진적으로 확장할 계획입니다. -React 컴포넌트의 순수한 JavaScript를 반응형으로 만들기 위해서 코드가 정확하게 무엇을 원하는지 이해할 수 있도록 의미론적으로 깊은 이해를 하는 컴파일러가 필요합니다. 이러한 접근법을 채택함으로써, 우리는 JavaScript 내에서 도메인 특화 언어에 국한되지 않고, 언어의 모든 표현 방법을 사용하여 어떠한 복잡도의 제품 코드라도 작성할 수 있는 반응성을 위한 시스템을 만들고 있습니다. +React 컴포넌트의 순수한 자바스크립트를 반응형으로 만들기 위해, 코드가 정확하게 무엇을 원하는지 이해할 수 있도록 의미론적으로 깊은 이해를 하는 컴파일러가 필요합니다. 이러한 접근법을 채택함으로써, 우리는 자바스크립트 내에서 도메인 특화 언어에 국한되지 않고, 언어의 모든 표현 방법을 사용하여 어떠한 복잡도의 제품 코드라도 작성할 수 있는 반응성을 위한 시스템을 만들고 있습니다. ## 오프스크린 렌더링 {/*offscreen-rendering*/} -오프스크린 렌더링은 React에 다가올 추가적인 성능 부담 없이 백그라운드에서 화면을 렌더링하는 기능입니다. [`content-visibility` CSS 프로퍼티](https://developer.mozilla.org/en-US/docs/Web/CSS/content-visibility)를 DOM 엘리먼트뿐만 아니라 React 컴포넌트에서도 작동하는 버전으로 이해하시면 됩니다. 이번 연구 중에 우리는 아래와 같은 다양한 사용 사례를 발견했습니다. +오프스크린 렌더링은 React에 추가될 추가적인 성능 부담 없이 백그라운드에서 화면을 렌더링하는 기능입니다. [`content-visibility` CSS 프로퍼티](https://developer.mozilla.org/en-US/docs/Web/CSS/content-visibility)를 DOM 엘리먼트뿐만 아니라 React 컴포넌트에서도 작동하는 버전으로 이해하시면 됩니다. 이번 연구 중에 아래와 같은 다양한 사용 사례를 발견했습니다. - 라우터는 백그라운드에서 화면을 사전 렌더링하여 사용자가 특정 화면으로 이동했을 때 즉시 사용하게 할 수 있습니다. - 탭 전환 컴포넌트는 숨겨진 탭의 state를 유지하여 사용자가 진행 상황을 잃지 않고 탭을 전환할 수 있습니다. @@ -86,9 +86,9 @@ React 컴포넌트의 순수한 JavaScript를 반응형으로 만들기 위해 대부분의 React 개발자는 React의 오프스크린 API와 직접 상호작용하지는 않을 것입니다. 대신, 오프스크린 렌더링은 라우터나 UI 라이브러리와 결합할 것이며, 해당 라이브러리를 사용하는 개발자는 추가적인 작업 없이 자연스럽게 이점을 누릴 수 있을 것입니다. -핵심은 컴포넌트를 작성하는 방법이 변경되지 않으면서 어떠한 React 트리라도 오프스크린에서 렌더링할 수 있어야 한다는 점입니다. 컴포넌트를 오프스크린에서 렌더링할 때 컴포넌트가 보이기 전까지 실제로 *마운트*하지 않으며 effect가 실행되지 않습니다. 예시로, 컴포넌트가 처음 나타날 때 `useEffect`를 사용하여 분석 로그를 남기는 경우, 사전 렌더링을 하는 것이 분석의 정확도를 손상하지 않을 것입니다. 마찬가지로 컴포넌트를 오프스크린으로 전환할 때 그 컴포넌트의 effect 또한 마운트가 해제됩니다. 오프스크린 렌더링의 핵심 기능은 컴포넌트의 가시성을 전환하면서도 그 state를 잃지 않는다는 점에 있습니다. +핵심은 컴포넌트를 작성하는 방법이 변경되지 않으면서 어떠한 React 트리라도 오프스크린에서 렌더링할 수 있어야 한다는 점입니다. 컴포넌트를 오프스크린에서 렌더링할 때 컴포넌트가 보이기 전까지 실제로 *마운트*하지 않으며 Effect가 실행되지 않습니다. 예시로, 컴포넌트가 처음 나타날 때 `useEffect`를 사용하여 분석 로그를 남기는 경우, 사전 렌더링을 하는 것이 분석의 정확도를 손상하지 않을 것입니다. 마찬가지로 컴포넌트를 오프스크린으로 전환할 때 그 컴포넌트의 Effect 또한 마운트 해제됩니다. 오프스크린 렌더링의 핵심 기능은 컴포넌트의 가시성을 전환하면서도 그 State를 잃지 않는다는 점에 있습니다. -지난 업데이트 이후 Meta 내부에서는 안드로이드와 iOS의 React Native 애플리케이션에서 실험적인 버전의 사전 렌더링을 테스트하였으며, 긍정적인 성능 결과를 얻었습니다. 또한 오프스크린 렌더링이 Suspense와 함께 작동하는 방식도 개선하여 오프스크린 트리 내부에서는 Suspense의 폴백이 발생하지 않도록 했습니다. 남아 남아있는 작업은 라이브러리 개발자에게 제공할 기본 요소를 마무리하는 것입니다. 올해 말 테스트와 피드백을 위한 실험적인 API와 함께 RFC를 게시할 예정입니다. +지난 업데이트 이후 Meta 내부에서는 안드로이드와 iOS의 React Native 애플리케이션에서 실험적인 버전의 사전 렌더링을 테스트하였으며, 긍정적인 성능 결과를 얻었습니다. 또한 오프스크린 렌더링이 Suspense와 함께 작동하는 방식도 개선하여 오프스크린 트리 내부에서는 Suspense의 폴백이 발생하지 않도록 했습니다. 남아있는 작업은 라이브러리 개발자에게 제공할 기본 요소를 마무리하는 것입니다. 올해 말 테스트와 피드백을 위한 실험적인 API와 함께 RFC를 게시할 예정입니다. ## 트랜지션 추적 {/*transition-tracing*/} From 0a4115472491c3aad43edad625a16be3ad36fbd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Tue, 31 Dec 2024 21:20:31 +0900 Subject: [PATCH 0463/1164] docs: update `react-canaries.md` --- src/content/blog/2023/05/03/react-canaries.md | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/content/blog/2023/05/03/react-canaries.md b/src/content/blog/2023/05/03/react-canaries.md index cb1666447..56bc2ef3f 100644 --- a/src/content/blog/2023/05/03/react-canaries.md +++ b/src/content/blog/2023/05/03/react-canaries.md @@ -1,5 +1,5 @@ --- -title: "React Canaries: Meta 외부에서 점진적 기능 롤아웃 활성화하기" +title: "React Canary: Meta 외부에서 점진적 기능 롤아웃 활성화하기" author: Dan Abramov, Sophie Alpert, Rick Hanlon, Sebastian Markbage, and Andrew Clark date: 2023/05/03 description: Meta가 오랫동안 내부적으로 최첨단 버전의 React를 사용해 온 것과 유사하게, 새로운 기능이 안정된 버전으로 출시되기 전에 디자인이 거의 완성되는 즉시 개별적인 새로운 기능을 채택할 수 있는 옵션을 React 커뮤니티에 제공하고자 합니다. 공식적으로 지원하는 새로운 Canary 릴리즈 채널을 소개합니다. 프레임워크와 같이 엄선된 설정을 통해 개별 React 기능의 채택을 React 릴리즈 일정에서 분리할 수 있습니다. @@ -17,22 +17,22 @@ Meta가 오랫동안 내부적으로 최첨단 버전의 React를 사용해 온 --- -## tl;dr {/*tldr*/} +## 요약 {/*tldr*/} -* 공식적으로 지원하는 React용 [Canary 릴리즈 채널](/community/versioning-policy#canary-channel)을 소개합니다. 공식적으로 지원되므로 회귀 문제가 발생하면 안정된 릴리즈의 버그와 비슷한 수준으로 긴급하게 처리할 것입니다. -* Canaries를 사용하면 Semantic Versioning에 안정된 릴리즈에 적용되기 전에 개별적인 새로운 React 기능을 사용할 수 있습니다. -* [실험](/community/versioning-policy#experimental-channel) 채널과 달리, React Canaries에는 채택할 준비가 되었다고 합리적으로 판단되는 기능만 포함됩니다. 프레임워크는 고정된 Canary React 릴리즈를 번들로 묶는 것을 고려할 것을 권장합니다. +* 공식적으로 지원하는 React용 [Canary 릴리즈 채널](/community/versioning-policy#canary-channel)을 소개합니다. 공식적으로 지원하므로 회귀<sup>Regression</sup> 문제가 발생하면 안정된 릴리즈의 버그와 비슷한 수준으로 긴급하게 처리할 것입니다. +* Canary를 사용하면 Semantic Versioning의 안정된 릴리즈에 적용되기 전에 개별적인 새로운 React 기능을 사용할 수 있습니다. +* [실험적 채널](/community/versioning-policy#experimental-channel)과 달리, React Canary에는 채택할 준비가 되었다고 합리적으로 판단되는 기능만 포함됩니다. 프레임워크는 고정된 Canary React 릴리즈를 번들로 묶는 것을 고려할 것을 권장합니다. * 중요한 변경 사항과 새로운 기능이 Canary 릴리즈에 적용되면 블로그에 공지할 예정입니다. -* **언제나 그렇듯이 React는 모든 안정된 릴리즈에 대해 Semantic Versioning을 계속 따릅니다.** +* **언제나 그렇듯이 React는 모든 안정된 릴리즈에 대해 Semantic Versioning을 따릅니다.** ## React 기능은 보통 어떻게 개발되나요? {/*how-react-features-are-usually-developed*/} 일반적으로 모든 React 기능은 동일한 단계를 거칩니다. 1. 초기 버전을 개발하고 `experimental_` 또는 `unstable_`접두사를 붙입니다. 이 기능은 `experimental` 릴리즈 채널에서만 사용할 수 있습니다. 이 시점에서 이 기능은 크게 변경될 것으로 예상됩니다. -2. 이 기능을 테스트하고 피드백을 제공하는 데 도움을 줄 Meta 팀을 찾았습니다. 이 피드백을 바탕으로 기능이 변경될 예정입니다. 기능이 안정화됨에 따라 Meta의 더 많은 팀과 협력하여 이 기능을 시험해 봅니다. -3. 결국 디자인에 자신감이 생겼습니다. API 이름에서 접두사를 제거하고 대부분의 Meta 제품이 사용하는 `main` 브랜치에서 이 기능을 기본적으로 사용할 수 있도록 했습니다. 이제 Meta의 모든 팀이 이 기능을 사용할 수 있습니다. -4. 방향에 대한 확신이 생기면 새 기능에 대한 RFC도 게시합니다. 이 시점에서 우리는 이 디자인이 광범위한 사례에 적합하다는 것을 알고 있지만, 마지막 순간에 몇 가지 조정을 할 수도 있습니다. +2. 이 기능을 테스트하고 피드백을 제공하는 데 도움을 줄 Meta 팀을 찾습니다. 이 피드백을 바탕으로 기능이 변경될 것입니다. 기능이 안정화됨에 따라 Meta의 더 많은 팀과 협력하여 이 기능을 시험해 봅니다. +3. 최종적으로 설계에 자신감이 생기면, API 이름에서 접두사를 제거하고 대부분의 Meta 제품이 사용하는 `main` 브랜치에서 이 기능을 기본적으로 사용할 수 있도록 합니다. 이제 Meta의 모든 팀이 이 기능을 사용할 수 있습니다. +4. 방향에 대한 확신이 생기면 새 기능에 대한 RFC도 게시합니다. 이 설계가 광범위한 사례에 적합하다는 것을 이 시점에 알고 있지만, 마지막 순간에 몇 가지 조정을 할 수도 있습니다. 5. 오픈 소스 릴리즈에 가까워지면 해당 기능에 대한 문서를 작성하고 최종적으로 안정된 React 릴리즈를 통해 기능을 출시합니다. 이 플레이북은 지금까지 출시된 대부분의 기능에 대해 잘 작동합니다. 하지만 일반적으로 기능을 사용할 준비가 된 시점(3단계)과 오픈 소스로 공개되는 시점(5단계) 사이에는 상당한 차이가 있을 수 있습니다. @@ -51,11 +51,11 @@ Meta에서는 `main` 브랜치에서 React를 빌드하고 매주 특정 고정 우리는 이 워크플로우를 다른 프레임워크와 선별된 설정에서 사용할 수 있도록 하고 싶습니다. 예를 들어, 이 플로우를 사용하면 React를 *기반으로 하는* 프레임워크가 안정된 React 릴리즈에 포함되기 *전에* React와 관련된 중요한 변경 사항을 포함할 수 있습니다. 일부 변경 사항은 프레임워크 통합에만 영향을 미치기 때문에 이 기능은 특히 유용합니다. 이를 통해 프레임워크는 Semantic Versioning을 중단시키지 않고 자체 마이너 버전에서 이러한 변경 사항을 릴리즈할 수 있습니다. -Canaries 채널을 통한 롤링 릴리즈를 통해 더욱 긴밀한 피드백 루프를 확보하고 새로운 기능이 커뮤니티에서 포괄적인 테스트를 거치도록 할 수 있습니다. 이 워크플로우는 자바스크립트 표준 위원회인 TC39가 [번호가 매겨진 단계로 변경 사항을 처리](https://tc39.es/process-document/)하는 방식에 가깝습니다. 새로운 JavaScript 기능이 명세의 일부로 공식적으로 승인되기 전에 브라우저에서 제공하는 것처럼, 새로운 React 기능은 React 안정 릴리즈에 포함되기 전에 React를 기반으로 구축된 프레임워크에서 사용할 수 있습니다. +Canary 채널을 통한 롤링 릴리즈를 통해 더욱 긴밀한 피드백 루프를 확보하고 새로운 기능이 커뮤니티에서 포괄적인 테스트를 거치도록 할 수 있습니다. 이 워크플로우는 자바스크립트 표준 위원회인 TC39가 [번호가 매겨진 단계로 변경 사항을 처리](https://tc39.es/process-document/)하는 방식에 가깝습니다. 새로운 자바스크립트 기능이 명세의 일부로 공식적으로 승인되기 전에 브라우저에서 제공하는 것처럼, 새로운 React 기능은 React 안정 릴리즈에 포함되기 전에 React를 기반으로 구축된 프레임워크에서 사용할 수 있습니다. ## 실험적 릴리즈를 사용하지 않는 이유는 무엇인가요? {/*why-not-use-experimental-releases-instead*/} -기술적으로는 [Experimental releases](/community/versioning-policy#canary-channel)를 사용*할 수* 있지만, 실험적 API는 안정화 과정에서 중대한 변경이 있을 수 있으므로(또는 심지어 완전히 제거될 수도 있으므로) 프로덕션 환경에서 사용하지 않는 것이 좋습니다. Canaries에도 실수가 있을 수 있지만(다른 릴리즈와 마찬가지로), 앞으로는 Canaries에 중대한 변경 사항이 있으면 블로그에 공지할 계획입니다. Canaries는 Meta가 내부적으로 실행하는 코드에 가장 가깝기 때문에 일반적으로 비교적 안정적일 것으로 기대할 수 있습니다. 하지만 버전을 고정*하고* 고정된 커밋 사이를 업데이트할 때는 GitHub 커밋 로그를 수동으로 스캔해야 합니다. +기술적으로는 [실험적 릴리즈](/community/versioning-policy#canary-channel)를 사용*할 수* 있지만, 실험적 API는 안정화 과정에서 중대한 변경이 있을 수 있으므로(또는 심지어 완전히 제거될 수도 있으므로) 프로덕션 환경에서 사용하지 않는 것이 좋습니다. Canary에도 실수가 있을 수 있지만(다른 릴리즈와 마찬가지로), 앞으로는 Canary에 중대한 변경 사항이 있으면 블로그에 공지할 계획입니다. Canary는 Meta가 내부적으로 실행하는 코드에 가장 가깝기 때문에 일반적으로 비교적 안정적일 것으로 기대할 수 있습니다. 하지만 버전을 고정*하고* 고정된 커밋 사이를 업데이트할 때는 GitHub 커밋 로그를 수동으로 스캔해야 합니다. **프레임워크와 같이 엄선된 환경 밖에서 React를 사용하는 대부분 사람은 Stable 릴리즈를 계속 사용하기를 원할 것으로 예상합니다.** 하지만 프레임워크를 구축하는 경우 특정 커밋에 고정된 React의 Canary 버전을 번들로 묶어 원하는 속도로 업데이트하는 것을 고려할 수 있습니다. 이 방법의 장점은 지난 몇 년 동안 React Native가 해왔던 방식과 유사하게, 완성된 개별 React 기능 및 버그 수정을 사용자에게 더 일찍, 자체 릴리즈 일정에 맞춰 제공할 수 있다는 것입니다. 단점은 어떤 React 커밋을 가져오는지 검토하고 릴리즈에 어떤 React 변경 사항이 포함되었는지 사용자에게 알리는 추가적인 책임을 져야 한다는 것입니다. @@ -65,27 +65,27 @@ Canaries 채널을 통한 롤링 릴리즈를 통해 더욱 긴밀한 피드백 Canary 릴리즈는 특정 시점에 다음 안정된 React 릴리즈에 포함될 내용에 대한 최선의 추측을 나타냅니다. -기존에는 릴리즈 주기가 *끝*날 때(주요 릴리즈를 할 때)만 중요한 변경 사항을 발표했습니다. 이제 Canary 릴리즈가 공식적으로 지원하는 React 사용 방식이 되었으므로, 중요한 변경 사항과 새로운 기능이 Canaries에 *적용될 때* 발표하는 방식으로 전환할 계획입니다. 예를 들어, Canary에 출시될 중요한 변경 사항을 병합하는 경우, 필요한 경우 코드모드 및 마이그레이션 지침을 포함하여 React 블로그에 이에 대한 게시물을 작성할 것입니다. 그런 다음, 프레임워크 작성자가 해당 변경 사항을 포함하도록 고정된 React Canary를 업데이트하는 주요 릴리즈를 자르는 경우 릴리즈 노트에서 블로그 게시물로 링크할 수 있습니다. 마지막으로, 안정된 주요 버전의 React가 준비되면 이미 게시된 블로그 게시물에 링크하여 팀이 더 빠르게 진행하는 데 도움이 되기를 바랍니다. +기존에는 릴리즈 주기가 *끝*날 때(주요 릴리즈를 할 때)만 중요한 변경 사항을 발표했습니다. 이제 Canary 릴리즈가 공식적으로 지원하는 React의 사용 방식이 되었으므로, 중요한 변경 사항과 새로운 기능이 Canary에 *적용될 때* 발표하는 방식으로 전환할 계획입니다. 예를 들어, Canary에 출시될 중요한 변경 사항을 병합하는 경우, 필요 시 코드모드 및 마이그레이션 지침을 포함하여 React 블로그에 이에 대한 게시물을 작성할 것입니다. 그런 다음, 프레임워크 작성자가 해당 변경 사항을 포함하도록 고정된 React Canary를 업데이트하는 주요 릴리즈를 자르는 경우 릴리즈 노트에서 블로그 게시물로 링크할 수 있습니다. 마지막으로, 안정된 주요 버전의 React가 준비되면 이미 게시된 블로그 게시물에 링크하여 팀이 더 빠르게 진행하는 데 도움이 되기를 바랍니다. -아직 Canaries 외부에서 사용할 수 없는 API라도 Canaries에 출시하는 대로 문서화할 계획입니다. Canaries에서만 사용할 수 있는 API는 해당 페이지에 특별 메모로 표시될 것입니다. 여기에는 [`use`](https://github.com/reactjs/rfcs/pull/229)와 같은 API와 일부 다른 API(예시: `cache` 및 `createServerContext`)가 포함되며, 이에 대한 RFC를 보내드릴 예정입니다. +아직 Canary 외부에서 사용할 수 없는 API라도 Canary에 출시하는 대로 문서화할 계획입니다. Canary에서만 사용할 수 있는 API는 해당 페이지에 특별 메모로 표시될 것입니다. 여기에는 [`use`](https://github.com/reactjs/rfcs/pull/229)와 같은 API와 일부 다른 API(예시: `cache` 및 `createServerContext`)가 포함되며, 이에 대한 RFC를 보내드릴 예정입니다. -## Canaries는 반드시 고정해야 합니다. {/*canaries-must-be-pinned*/} +## Canary는 반드시 고정해야 합니다. {/*canaries-must-be-pinned*/} -앱이나 프레임워크에 Canary 워크플로우를 채택하기로 한 경우 항상 사용 중인 Canary의 *정확한* 버전을 고정해야 합니다. Canaries는 사전 릴리즈이므로 여전히 변경 사항이 포함될 수 있습니다. +앱이나 프레임워크에 Canary 워크플로우를 채택하기로 한 경우 항상 사용 중인 Canary의 *정확한* 버전을 고정해야 합니다. Canary는 사전 릴리즈이므로 여전히 변경 사항이 포함될 수 있습니다. -## 예시: React Server 컴포넌트 {/*example-react-server-components*/} +## 예시: React 서버 컴포넌트 {/*example-react-server-components*/} -지난 [3월에 발표했듯이](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components) React Server 컴포넌트 컨벤션은 확정되었으며, 사용자 대면 API 계약과 관련된 중대한 변경 사항은 없을 것으로 예상됩니다. 그러나 서로 얽혀 있는 여러 프레임워크 전용 기능([에셋 로딩](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#asset-loading)과 같은)에 대한 작업이 진행 중이며, 더 많은 변경 사항이 있을 것으로 예상되기 때문에 아직 안정된 버전의 React에서 React Server 컴포넌트에 대한 지원을 릴리즈할 수는 없습니다. +지난 [3월에 발표했듯이](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components) React 서버 컴포넌트 컨벤션은 확정되었으며, 사용자 대면 API 계약과 관련된 중대한 변경 사항은 없을 것으로 예상합니다. 그러나 서로 얽혀 있는 여러 프레임워크 전용 기능([에셋 불러오기](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#asset-loading)와 같은)에 대한 작업이 진행 중이며, 더 많은 변경 사항이 있을 것으로 예상되기 때문에 아직 안정된 버전의 React에서 React 서버 컴포넌트에 대한 지원을 릴리즈할 수는 없습니다. -즉, React Server 컴포넌트가 프레임워크에 채택될 준비가 되었다는 뜻입니다. 그러나 다음 주요 React 릴리즈가 나올 때까지 프레임워크가 이를 채택할 수 있는 유일한 방법은 고정된 Canary 버전의 React를 출시하는 것입니다. (두 개의 React 복사본이 번들로 제공되는 것을 피하고자, 이를 원하는 프레임워크는 프레임워크와 함께 제공하는 고정된 Canary에 `react` 및 `react-dom`의 해결 방법을 적용하고 사용자에게 이를 설명해야 합니다. 예를 들어, 이것이 Next.js App Router가 하는 일입니다.) +즉, React 서버 컴포넌트가 프레임워크에 채택될 준비가 되었다는 뜻입니다. 그러나 다음 주요 React 릴리즈가 나올 때까지 프레임워크가 이를 채택할 수 있는 유일한 방법은 고정된 Canary 버전의 React를 출시하는 것입니다. (두 개의 React 복사본이 번들로 제공되는 것을 피하고자, 이를 원하는 프레임워크는 프레임워크와 함께 제공하는 고정된 Canary에 `react` 및 `react-dom`의 해결 방법을 적용하고 사용자에게 이를 설명해야 합니다. 예를 들어, 이것이 Next.js App Router가 하는 일입니다.) ## Stable 및 Canary 버전 모두에 대해 라이브러리 테스트하기 {/*testing-libraries-against-both-stable-and-canary-versions*/} -라이브러리 작성자가 모든 Canary 릴리즈를 테스트하는 것은 엄청나게 어렵기 때문에 기대하지 않습니다. 하지만 [3년 전 다양한 React 사전 릴리즈 채널을 처음 도입했을 때](https://legacy.reactjs.org/blog/2019/10/22/react-release-channels.html)와 마찬가지로, 라이브러리 작성자는 최신 Stable 버전과 최신 Canary 버전 *모두*에 대해 테스트를 실행할 것을 권장합니다. 발표되지 않은 동작의 변화를 발견하는 경우, 진단에 도움이 될 수 있도록 React 레포지토리에 버그를 제출해 주세요. 이 관행이 널리 채택되면 라이브러리가 출시될 때 우발적인 회귀를 발견할 수 있기 때문에 라이브러리를 새로운 주요 버전의 React로 업그레이드하는 데 필요한 노력이 줄어들 것으로 기대합니다. +라이브러리 작성자가 모든 Canary 릴리즈를 테스트하는 것은 엄청나게 어렵기 때문에 이를 기대하지는 않습니다. 하지만 [3년 전 다양한 React 사전 릴리즈 채널을 처음 도입했을 때](https://legacy.reactjs.org/blog/2019/10/22/react-release-channels.html)와 마찬가지로, 라이브러리 작성자는 최신 Stable 버전과 최신 Canary 버전 *모두*에 대해 테스트를 실행할 것을 권장합니다. 발표되지 않은 동작의 변화를 발견하는 경우, 진단에 도움이 될 수 있도록 React 저장소에 버그를 제출해 주세요. 이 관행이 널리 채택되면 라이브러리가 출시될 때 우발적인 회귀를 발견할 수 있기 때문에 라이브러리를 새로운 주요 버전의 React로 업그레이드하는 데 필요한 노력이 줄어들 것으로 기대합니다. <Note> -엄밀히 말하면, Canary는 *새로운* 릴리즈 채널이 아니며 이전에는 Next라고 불렀습니다. 하지만 Next.js와의 혼동을 피하고자 이름을 변경하기로 했습니다. 공식적으로 지원하는 React 사용 방법인 Canaries와 같은 새로운 기대치를 전달하기 위해 *새로운* 릴리즈 채널로 발표하게 되었습니다. +엄밀히 말하면, Canary는 *새로운* 릴리즈 채널이 아니며 이전에는 Next라고 불렀습니다. 하지만 Next.js와의 혼동을 피하고자 이름을 변경하기로 했습니다. 공식적으로 지원하는 React 사용 방법인 Canary와 같은 새로운 기대치를 전달하기 위해 *새로운* 릴리즈 채널로 발표하게 되었습니다. </Note> From 71c2f315770ef4d4f50e1b1640824bc152df49c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Tue, 31 Dec 2024 21:43:31 +0900 Subject: [PATCH 0464/1164] docs: update `react-labs-what-we-have-been-working-on-february-2024.md` --- ...t-we-have-been-working-on-february-2024.md | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md b/src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md index f7fea38f1..2fb2cd398 100644 --- a/src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md +++ b/src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md @@ -11,7 +11,7 @@ description: React Labs 게시글에는 활발히 연구 개발 중인 프로젝 <Intro> -React Labs 게시글에는 활발히 연구 개발 중인 프로젝트에 대한 내용을 작성합니다. 우리의 [지난 업데이트](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023) 이후 상당한 발전을 이루었고, 이러한 진전 사항을 공유하려고 합니다. +React Labs 게시글에는 활발히 연구 개발 중인 프로젝트에 대한 내용을 작성합니다. 우리는 [지난 업데이트](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023) 이후 상당한 발전을 이루었고, 이러한 진전 사항을 공유하려고 합니다. </Intro> @@ -29,22 +29,22 @@ React Conf 2024가 5월 15일부터 16일까지 네바다주 헨더슨에서 개 React 컴파일러는 더 이상 연구 프로젝트가 아닙니다. 컴파일러는 현재 instagram.com의 프로덕션 단계에서 작동하고 있으며, Meta의 더 많은 서비스에 컴파일러를 적용하고 첫 번째 오픈소스 배포를 준비하기 위해 노력하고 있습니다. -[이전 게시글](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-optimizing-compiler)에서 논의한 바와 같이, React는 state가 변경될 때 *이따금* 너무 많이 다시 렌더링 될 수 있습니다. React 초기부터 이런 경우에 대한 해답은 수동 memoization였습니다. 현재 API에서 이는 [`useMemo`](/reference/react/useMemo), [`useCallback`](/reference/react/useCallback), 그리고 [`memo`](/reference/react/memo) API를 적용하여 state 변경에 따른 React의 다시 렌더링되는 양을 수동으로 조정하는 것을 의미합니다. 그러나 수동 memoization는 절충안입니다. 이는 우리의 코드를 복잡하게 만들고, 잘못 이해하기 쉬우며, 최신 state를 유지하기 위해 추가 작업이 필요합니다. +[이전 게시글](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-optimizing-compiler)에서 논의한 바와 같이, React는 State가 변경될 때 *이따금* 너무 자주 다시 렌더링 될 수 있습니다. React 초기부터 이런 경우에 대한 해답은 수동 메모이제이션<sup>Memoization</sup>이었습니다. 현재 API에서 이는 [`useMemo`](/reference/react/useMemo), [`useCallback`](/reference/react/useCallback), 그리고 [`memo`](/reference/react/memo) API를 적용하여 State 변경에 따른 React의 다시 렌더링되는 양을 수동으로 조정하는 것을 의미합니다. 그러나 수동 메모이제이션은 절충안입니다. 이는 우리의 코드를 복잡하게 만들고, 잘못 이해하기 쉬우며, 최신 State를 유지하기 위해 추가 작업이 필요합니다. -수동 memoization는 합리적인 절충안이지만, 우리는 만족하지 않았습니다. 우리의 비전은 state 변경 시 React가 *핵심적인 멘탈 모델을 손상하지 않으면서* UI의 정확한 부분만 *자동으로* 다시 렌더링하는 것입니다. 우리는 UI가 표준 JavaScript 값과 패턴으로 이루어진 state의 단순한 함수라고 생각하는 React의 접근 방식이 바로 수많은 개발자가 React에 쉽게 접근할 수 있었던 핵심 이유라고 생각합니다. 이것이 우리가 React를 위한 최적화 컴파일러를 구축하기 위해 투자한 이유입니다. +수동 메모이제이션은 합리적인 절충안이지만, 만족하지 못했습니다. 우리의 비전은 State 변경 시 React가 *핵심적인 멘탈 모델을 손상하지 않으면서* UI의 정확한 부분만 *자동으로* 다시 렌더링하는 것입니다. 우리는 UI가 표준 자바스크립트 값과 패턴으로 이루어진 State의 단순한 함수라고 생각하는 React의 접근 방식이 바로 수많은 개발자가 React에 쉽게 접근할 수 있었던 핵심 이유라고 생각합니다. 이것이 우리가 React를 위한 최적화 컴파일러를 구축하기 위해 투자한 이유입니다. -JavaScript는 느슨한 규칙과 동적인 특징 때문에 최적화하기에 매우 까다로운 언어입니다. React 컴파일러는 JavaScript 규칙과 *함께* "React 규칙"을 모두 모델링하여 코드를 안전하게 컴파일할 수 있습니다. 예를 들어, React 컴포넌트는 동일한 입력이 주어지면 동일한 값을 반환하는 멱등성을 만족해야 하며, props나 state를 변경시키지 못합니다. 이러한 규칙은 개발자가 작업할 수 있는 범위를 제한하고 컴파일러가 최적화할 수 있는 안전한 공간을 만들어 나가는 데 도움을 줍니다. +자바스크립트는 느슨한 규칙과 동적인 특징 때문에 최적화하기에 매우 까다로운 언어입니다. React 컴파일러는 자바스크립트 규칙과 *함께* "React 규칙"을 모두 모델링하여 코드를 안전하게 컴파일할 수 있습니다. 예를 들어, React 컴포넌트는 동일한 입력이 주어지면 동일한 값을 반환하는 멱등성을 만족해야 하며, Props나 State를 변경하지 못합니다. 이러한 규칙은 개발자가 작업할 수 있는 범위를 제한하고 컴파일러가 최적화할 수 있는 안전한 공간을 만들어 나가는 데 도움을 줍니다. 물론, 개발자들이 가끔 규칙을 약간 비틀 수 있다는 것을 이해하고 있습니다. 우리의 목표는 React 컴파일러가 가능한 많은 코드에서 즉시 작동하도록 하는 것입니다. 컴파일러는 코드가 React 규칙을 엄격하게 따르고 있는지 탐지하려고 시도하며, 안전한 경우에는 컴파일하거나 안전하지 않은 경우에는 컴파일을 건너뛸 것입니다. 우리는 Meta의 크고 다양한 코드 베이스를 대상으로 테스트하며 이러한 접근법을 검증하는 데 도움을 주고 있습니다. 자신의 코드가 React 규칙을 따르고 있는지 확인하고 싶은 개발자들에게, 우리는 [Strict Mode를 활성화](/reference/react/StrictMode)하고 [React의 ESLint 플러그인을 설정하는 것](/learn/editor-setup#linting)을 권장합니다. 이러한 도구들은 React 코드에서의 미묘한 오류를 잡고, 현재 애플리케이션의 품질을 향상하는 데 도움을 줄 수 있습니다. 또한, React 컴파일러와 같은 향후 다가올 기능들에 대비하여 애플리케이션을 준비하는 데 도움을 줄 수 있습니다. 우리는 또한 React 규칙에 대한 통합 문서와 ESLint 플러그인 업데이트를 작업하고 있으며, 이를 통해 팀에서 이러한 규칙들을 이해하고 적용하여 더욱 견고한 애플리케이션을 만들 수 있도록 도울 것입니다. -컴파일러를 실제로 보고 싶다면, [지난가을에 진행한 강연](https://www.youtube.com/watch?v=qOQClO3g8-Y)을 확인해 보세요. 강연 당시, 우리는 instagram.com의 한 페이지에 React 컴파일러를 시도한 초기 실험 데이터를 가지고 있었습니다. 그 이후로, 우리는 컴파일러를 instagram.com의 프로덕션 단계 전반에 걸쳐 적용했습니다. 또한 저희 팀을 확장하여 메타에서 출시할 추가적인 서비스와 오픈 소스의 출시를 가속했습니다. 저희는 앞으로의 길에 대해 큰 기대를 가지고 있고, 향후 몇 달 안에 더 많은 소식을 공유할 것입니다. +컴파일러를 실제로 보고 싶다면, [지난 가을에 진행한 강연](https://www.youtube.com/watch?v=qOQClO3g8-Y)을 확인해 보세요. 강연 당시, 우리는 instagram.com의 한 페이지에 React 컴파일러를 시도한 초기 실험 데이터를 가지고 있었습니다. 그 이후로, 우리는 컴파일러를 instagram.com의 프로덕션 단계 전반에 걸쳐 적용했습니다. 또한 저희 팀을 확장하여 메타에서 출시할 추가적인 서비스와 오픈 소스의 출시를 가속했습니다. 저희는 앞으로의 길에 대해 큰 기대를 가지고 있고, 향후 몇 달 안에 더 많은 소식을 공유할 것입니다. ## 액션 {/*actions*/} -저희는 [이전에](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components) 서버 액션을 통한 클라이언트에서 서버로 데이터를 보내는 해결책을 탐색하고 있다고 공유했습니다. 이를 통해 데이터베이스 변이를 실행하고 폼을 구현할 수 있습니다. 서버 액션을 개발하는 동안, 이러한 API가 클라이언트 전용 애플리케이션에서도 데이터 처리를 지원하도록 확장했습니다. +저희는 [이전에](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components) 서버 액션을 통한 클라이언트에서 서버로 데이터를 보내는 해결책을 탐색하고 있다고 공유했습니다. 이를 통해 데이터베이스 변경을 실행하고 폼을 구현할 수 있습니다. 서버 액션을 개발하는 동안, 이러한 API가 클라이언트 전용 애플리케이션에서도 데이터 처리를 지원하도록 확장했습니다. 우리는 이러한 광범위한 기능 모음을 단순히 "액션"이라고 부릅니다. 액션을 사용하여 [`<form/>`](/reference/react-dom/components/form)과 같은 DOM 엘리먼트에 함수를 전달할 수 있습니다. @@ -55,13 +55,13 @@ JavaScript는 느슨한 규칙과 동적인 특징 때문에 최적화하기에 </form> ``` -`액션` 함수는 동기 또는 비동기적으로 실행할 수 있습니다. 클라이언트 측에서 표준 JavaScript를 사용하여 정의하거나, [`'use server'`](/reference/rsc/use-server)라는 지시어를 사용하여 서버에서 정의할 수 있습니다. 액션을 사용할 때, React는 [`useFormStatus`](/reference/react-dom/hooks/useFormStatus), [`useActionState`](/reference/react/useActionState)와 같은 hook을 제공하여 데이터 제출의 생명주기를 관리하고 현재 폼의 state와 응답에 접근할 수 있습니다. +`action` 함수는 동기적 또는 비동기적으로 실행할 수 있습니다. 클라이언트 측에서 표준 자바스크립트를 사용하여 정의하거나, [`'use server'`](/reference/rsc/use-server)라는 지시어를 사용하여 서버에서 정의할 수 있습니다. 액션을 사용할 때, React는 [`useFormStatus`](/reference/react-dom/hooks/useFormStatus), [`useActionState`](/reference/react/useActionState)와 같은 Hook을 제공하여 데이터 제출의 생명주기를 관리하고 현재 폼의 State와 응답에 접근할 수 있습니다. -기본적으로 액션은 [트랜지션](/reference/react/useTransition) 내에서 제출되어 현재 페이지가 상호작용을 하는 동안 액션을 처리합니다. 액션은 비동기 함수를 지원하므로, 트랜지션 내에서 `async/await`를 사용할 수 있도록 추가했습니다. 이를 통해 `fetch`와 같은 비동기 요청이 시작되면 트랜지션의 `isPending` state를 사용하여 대기 중인 UI를 표시하고, 업데이트가 적용될 때까지 대기 중인 UI를 계속 보여줄 수 있습니다. +기본적으로 액션은 [트랜지션](/reference/react/useTransition) 내에서 제출되어 현재 페이지가 상호작용을 하는 동안 액션을 처리합니다. 액션은 비동기 함수를 지원하므로, 트랜지션 내에서 `async`/`await`을 사용할 수 있도록 추가했습니다. 이를 통해 `fetch`와 같은 비동기 요청이 시작되면 트랜지션의 `isPending` State를 사용하여 대기 중인 UI를 표시하고, 업데이트가 적용될 때까지 대기 중인 UI를 계속 보여줄 수 있습니다. -액션과 함께, 낙관적 state 업데이트를 관리하기 위한 [`useOptimistic`](/reference/react/useOptimistic)이라는 기능을 소개합니다. 이 hook을 사용하여 최종 state가 커밋되면 자동으로 되돌릴 수 있는 일시적인 업데이트를 적용할 수 있습니다. 액션의 경우, 제출이 성공적이라고 가정하고 클라이언트에서 데이터의 최종 state를 낙관적으로 업데이트할 수 있습니다. 그리고 서버에서 받은 데이터를 통해 값을 되돌릴 수 있습니다. 이는 일반적인 `async`/`await` 방식을 사용하여 작동하므로, 클라이언트에서 `fetch`를 사용하든 서버에서 서버 액션을 사용하든 동일하게 작동합니다. +액션과 함께, 낙관적 State 업데이트를 관리하기 위한 [`useOptimistic`](/reference/react/useOptimistic)이라는 기능을 소개합니다. 이 Hook을 사용하여 최종 State가 커밋되면 자동으로 되돌릴 수 있는 일시적인 업데이트를 적용할 수 있습니다. 액션의 경우, 제출이 성공적이라고 가정하고 클라이언트에서 데이터의 최종 State를 낙관적으로 업데이트할 수 있습니다. 그리고 서버에서 받은 데이터를 통해 값을 되돌릴 수 있습니다. 이는 일반적인 `async`/`await` 방식을 사용하여 작동하므로, 클라이언트에서 `fetch`를 사용하든 서버에서 서버 액션을 사용하든 동일하게 작동합니다. -라이브러리 제작자는 각자의 컴포넌트에서 `useTransition`를 사용하여 사용자 지정 `action={fn}` props를 구현할 수 있습니다. 우리의 의도는 라이브러리가 컴포넌트 API를 설계할 때 액션 패턴을 채택하여 React 개발자들에게 일관적인 경험을 제공하는 것입니다. 예를 들어, 라이브러리에서 `<Calendar onSelect={eventHandler}>`와 같은 컴포넌트를 제공하는 경우, `<Calendar selectAction={action}>`와 같은 API도 노출하는 것을 고려해 보세요. +라이브러리 제작자는 각자의 컴포넌트에서 `useTransition`를 사용하여 사용자 지정 `action={fn}` Props를 구현할 수 있습니다. 우리의 의도는 라이브러리가 컴포넌트 API를 설계할 때 액션 패턴을 채택하여 React 개발자들에게 일관적인 경험을 제공하는 것입니다. 예를 들어, 라이브러리에서 `<Calendar onSelect={eventHandler}>`와 같은 컴포넌트를 제공하는 경우, `<Calendar selectAction={action}>`와 같은 API도 노출하는 것을 고려해 보세요. 우리는 처음에 서버 액션을 클라이언트-서버 사이 데이터 전송에 중점을 두었지만, React의 철학은 모둔 플랫폼과 환경에서 동일한 프로그래밍 모델을 제공하는 것입니다. 가능하다면 클라이언트의 기능을 소개한 경우 해당 기능이 서버에서도 작동하도록 하고, 그 반대의 경우도 마찬가지입니다. 이 철학을 통해 애플리케이션이 실행되는 위치와 관계없이 작동하는 단일 API 모음을 생성하여, 이후 다른 환경으로 업그레이드 하기 쉽게 만들 수 있습니다. @@ -75,21 +75,21 @@ Canary는 React의 개발 방식을 변경하는 것입니다. 이전에는 기 React 서버 컴포넌트, 에셋 불러오기, 문서 메타데이터 및 액션 모두 React Canary에 도입되었으며, 이러한 기능에 대한 문서를 react.dev에 추가했습니다. -- **지시어**: [`"use client"`](/reference/rsc/use-client)와 [`"use server"`](/reference/rsc/use-server)는 풀스택 React 프레임워크를 위해 설계한 번들러 기능입니다. 이들은 두 환경 사이의 "분할점"을 나타냅니다. "use client"는 [Astro Islands](https://docs.astro.build/en/concepts/islands/#creating-an-island)처럼 번들러에 `<script>` 태그를 생성하도록 지시합니다. 반면 `"use server"`는 [tRPC Mutations](https://trpc.io/docs/concepts)처럼 번들러에 POST 엔드포인트를 생성하도록 지시합니다. 두 지시어를 함께 사용하여 클라이이언트 측의 상호작용을 서버 측의 로직과 결합하는 재사용 가능한 컴포넌트를 작성할 수 있습니다. +- **지시어**: [`"use client"`](/reference/rsc/use-client)와 [`"use server"`](/reference/rsc/use-server)는 풀스택 React 프레임워크를 위해 설계한 번들러 기능입니다. 이들은 두 환경 사이의 "분할점"을 나타냅니다. `"use client"`는 [Astro Islands](https://docs.astro.build/en/concepts/islands/#creating-an-island)처럼 번들러에 `<script>` 태그를 생성하도록 지시합니다. 반면 `"use server"`는 [tRPC Mutations](https://trpc.io/docs/concepts)처럼 번들러에 POST 엔드포인트를 생성하도록 지시합니다. 두 지시어를 함께 사용하여 클라이이언트 측의 상호작용을 서버 측의 로직과 결합하는 재사용 가능한 컴포넌트를 작성할 수 있습니다. - **문서 메타데이터**: 우리는 컴포넌트 트리 어디에서든 [`<title>`](/reference/react-dom/components/title), [`<meta>`](/reference/react-dom/components/meta) 및 메타데이터 [`<link>`](/reference/react-dom/components/link) 태그를 렌더링하는 내장 지원을 추가했습니다. 이는 완전한 클라이언트 측 코드, SSR 및 RSC를 포함한 모든 환경에서 동일하게 작동합니다. 이는 [React Helmet](https://github.com/nfl/react-helmet)과 같은 라이브러리가 이미 제공하던 기능을 내장 지원으로 제공합니다. -- **에셋 불러오기**: 우리는 Suspense를 스타일시트, 폰트, 스크립트와 같은 리소스를 불러오는 생명주기와 통합했습니다. 이를 통해 React는 표시할 준비가 되었는지 결정하는데 [`<style>`](/reference/react-dom/components/style), [`<link>`](/reference/react-dom/components/link) 및 [`<script>`](/reference/react-dom/components/script)와 같은 엘리먼트 내부의 콘텐츠를 고려합니다. 또한 `preload`와 `preinit`과 같은 [새로운 리소스 불러오기 API](/reference/react-dom#resource-preloading-apis)를 추가하여 리소스를 언제 불러오고 초기화할지에 대한 더 많은 제어권을 제공했습니다. +- **에셋 불러오기**: 우리는 Suspense를 스타일시트, 글꼴, 스크립트와 같은 리소스를 불러오는 생명주기와 통합했습니다. 이를 통해 React는 표시할 준비가 되었는지 결정하는데 [`<style>`](/reference/react-dom/components/style), [`<link>`](/reference/react-dom/components/link) 및 [`<script>`](/reference/react-dom/components/script)와 같은 엘리먼트 내부의 콘텐츠를 고려합니다. 또한 `preload`와 `preinit`과 같은 [새로운 리소스 불러오기 API](/reference/react-dom#resource-preloading-apis)를 추가하여 리소스를 언제 불러오고 초기화할지에 대한 더 많은 제어권을 제공했습니다. - **액션**: 앞서 언급한 대로, 클라이언트에서 서버로 데이터를 전송하는 것을 관리하기 위해 액션을 추가했습니다. [`<form/>`](/reference/react-dom/components/form)과 같은 엘리먼트에 `action`을 추가할 수 있으며, [`useFormStatus`](/reference/react-dom/hooks/useFormStatus)를 사용하여 진행 상황에 접근하고, [`useActionState`](/reference/react/useActionState)를 사용하여 결과를 처리하며, [`useOptimistic`](/reference/react/useOptimistic)를 사용하여 UI를 낙관적으로 업데이트할 수 있습니다. -이러한 모든 기능은 함께 작동하기 때문에, 이들을 각각 안정적 채널에 배포하기는 어렵습니다. 폼 state에 접근하는 보조 hook 없이 액션을 배포하는 것은 액션의 실제 유용성을 제한할 것입니다. 서버 액션을 통합하지 않으면서 React 서버 컴포넌트를 도입하면 서버에서 데이터를 수정하기에 복잡해질 것입니다. +이러한 모든 기능은 함께 작동하기 때문에, 이들을 각각 안정적 채널에 배포하기는 어렵습니다. 폼 State에 접근하는 보조 Hook 없이 액션을 배포하는 것은 액션의 실제 유용성을 제한할 것입니다. 서버 액션을 통합하지 않으면서 React 서버 컴포넌트를 도입하면 서버에서 데이터를 수정하기에 복잡해질 것입니다. 저희는 이러한 기능들을 안정적 채널에 배포하기 전에, 이들이 함께 작동하고 개발자가 프로덕션 단계에서 사용하기 위해 필요한 모든 것을 갖추었는지 보장해야 합니다. React Canary를 통해 개발자는 이런 기능을 개별적으로 개발하고, 전체 기능 목록이 완성되기 전까지 점진적으로 안정된 API를 배포할 수 있습니다. 현재 React Canary에 포함된 기능들은 완성되어 배포할 준비가 되었습니다. -## React의 다음 주요 버전 {/*the-next-major-version-of-react*/} +## React의 다음 메이저 버전 {/*the-next-major-version-of-react*/} 몇 년간의 반복 작업 끝에, `react@canary`가 이제 `react@latest`로의 출시 준비가 되었습니다. 위에서 언급한 새로운 기능들은 애플리케이션이 실행되는 모든 환경과 호환되며, 프로덕션 단계에서 사용되기 위해 필요한 모든 것을 제공합니다. 에셋 불러오기와 문서 메타데이터는 일부 애플리케이션에서 큰 변화일 수 있습니다. 따라서 React의 다음 버전은 주요 버전인 **React 19**가 될 것입니다. @@ -105,9 +105,9 @@ Activity는 여전히 연구 중이며, 라이브러리 개발자에게 노출 * * * -이번 업데이트 외에도 우리 팀은 콘퍼런스에서 발표하고 팟캐스트 출연을 통해 우리의 작업에 관해 이야기를 나누고 질문에 답변했습니다. +이번 업데이트 외에도 우리 팀은 컨퍼런스에서 발표하고 팟캐스트 출연을 통해 우리의 작업에 관해 이야기를 나누고 질문에 답변했습니다. -- [Sathya Gunasekaran](/community/team#sathya-gunasekaran)은 [React India](https://www.youtube.com/watch?v=kjOacmVsLSE) 콘퍼런스에서 React 컴파일러에 관해 이야기했습니다. +- [Sathya Gunasekaran](/community/team#sathya-gunasekaran)은 [React India](https://www.youtube.com/watch?v=kjOacmVsLSE) 컨퍼런스에서 React 컴파일러에 관해 이야기했습니다. - [Dan Abramov](/community/team#dan-abramov)은 [RemixConf](https://www.youtube.com/watch?v=zMf_xeGPn6s)에서 "다른 차원의 React"를 주제로 강연했습니다. 이곳에서 React 서버 컴포넌트와 액션을 어떻게 만들었는지에 관한 대안적인 역사를 탐구했습니다. From 9f996d22c81deb800f3dd14ddb5c1b7b7338717e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Tue, 31 Dec 2024 22:40:38 +0900 Subject: [PATCH 0465/1164] docs: update `react-19-upgrade-guide` --- src/content/blog/2024/04/25/react-19-upgrade-guide.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/content/blog/2024/04/25/react-19-upgrade-guide.md b/src/content/blog/2024/04/25/react-19-upgrade-guide.md index 44802014e..fbeb80edc 100644 --- a/src/content/blog/2024/04/25/react-19-upgrade-guide.md +++ b/src/content/blog/2024/04/25/react-19-upgrade-guide.md @@ -112,13 +112,8 @@ This will run the following codemods from `react-codemod`: - [`replace-reactdom-render`](https://github.com/reactjs/react-codemod?tab=readme-ov-file#replace-reactdom-render) - [`replace-string-ref`](https://github.com/reactjs/react-codemod?tab=readme-ov-file#replace-string-ref) - [`replace-act-import`](https://github.com/reactjs/react-codemod?tab=readme-ov-file#replace-act-import) -<<<<<<< HEAD - [`replace-use-form-state`](https://github.com/reactjs/react-codemod?tab=readme-ov-file#replace-use-form-state) -- [`prop-types-typescript`](TODO) -======= -- [`replace-use-form-state`](https://github.com/reactjs/react-codemod?tab=readme-ov-file#replace-use-form-state) - [`prop-types-typescript`](https://codemod.com/registry/react-prop-types-typescript) ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc This does not include the TypeScript changes. See [TypeScript changes](#typescript-changes) below. @@ -396,7 +391,7 @@ npx codemod@latest react/19/replace-act-import #### Removed: `ReactDOM.render` {/*removed-reactdom-render*/} -`ReactDOM.render` was deprecated in [March 2022 (v18.0.0)](https://react.dev/blog/2022/03/08/react-18-upgrade-guide). In React 19, we're removing `ReactDOM.render` and you'll need to migrate to using [`ReactDOM.createRoot`](https://react.dev/reference/react-dom/client/createRoot): +`ReactDOM.render` was deprecated in [March 2022 (v18.0.0)](/blog/2022/03/08/react-18-upgrade-guide). In React 19, we're removing `ReactDOM.render` and you'll need to migrate to using [`ReactDOM.createRoot`](/reference/react-dom/client/createRoot): ```js // Before @@ -421,7 +416,7 @@ npx codemod@latest react/19/replace-reactdom-render #### Removed: `ReactDOM.hydrate` {/*removed-reactdom-hydrate*/} -`ReactDOM.hydrate` was deprecated in [March 2022 (v18.0.0)](https://react.dev/blog/2022/03/08/react-18-upgrade-guide). In React 19, we're removing `ReactDOM.hydrate` you'll need to migrate to using [`ReactDOM.hydrateRoot`](https://react.dev/reference/react-dom/client/hydrateRoot), +`ReactDOM.hydrate` was deprecated in [March 2022 (v18.0.0)](/blog/2022/03/08/react-18-upgrade-guide). In React 19, we're removing `ReactDOM.hydrate` you'll need to migrate to using [`ReactDOM.hydrateRoot`](/reference/react-dom/client/hydrateRoot), ```js // Before From 5095e26c18618fe9deaa1c3d858e69801ed96045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Tue, 31 Dec 2024 23:01:20 +0900 Subject: [PATCH 0466/1164] docs: update `react-compiler.md` --- src/content/learn/react-compiler.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 241611c94..1ac53f74f 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -105,7 +105,7 @@ function TableContainer({ items }) { // ... } ``` -[_React 컴파일러 플레이그라운드에서 이 예시를 확인하세요_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) +[_React 컴파일러 플레이그라운드에서 이 예시를 확인하세요_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA). 그러나 `expensivelyProcessAReallyLargeArrayOfObjects`가 실제로 비용이 많이 드는 함수라면 다음과 같은 이유로 React 외부에서 해당 함수의 별도 메모이제이션을 고려해야 할 수도 있습니다. @@ -349,11 +349,7 @@ React 컴파일러는 React의 많은 규칙을 정적으로 검증할 수 있 ### 컴포넌트가 최적화되었는지 어떻게 알 수 있을까요? {/*how-do-i-know-my-components-have-been-optimized*/} -<<<<<<< HEAD -[React Devtools](/learn/react-developer-tools) (v5.0+)에는 React 컴파일러를 내장 지원하며, 컴파일러에 의해 최적화된 컴포넌트 옆에 "Memo ✨" 배지를 표시합니다. -======= -[React DevTools](/learn/react-developer-tools) (v5.0+) and [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) have built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler. ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +[React DevTools](/learn/react-developer-tools) (v5.0+)와 [React Native DevTools](https://reactnative.dev/docs/react-native-devtools)는 React 컴파일러를 내장 지원하며, 컴파일러에 의해 최적화된 컴포넌트 옆에 "Memo ✨" 배지를 표시합니다. ### 컴파일 후 작동하지 않는 문제 {/*something-is-not-working-after-compilation*/} From 179e0fcf8475ac60984f26419f61c1ec75228d50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Tue, 31 Dec 2024 23:19:45 +0900 Subject: [PATCH 0467/1164] docs: resolve conflict in `react-19.md` --- src/content/blog/2024/12/05/react-19.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/content/blog/2024/12/05/react-19.md b/src/content/blog/2024/12/05/react-19.md index 213581816..cc58a1040 100644 --- a/src/content/blog/2024/12/05/react-19.md +++ b/src/content/blog/2024/12/05/react-19.md @@ -330,7 +330,7 @@ We've added two new APIs to `react-dom/static` for static site generation: - [`prerender`](/reference/react-dom/static/prerender) - [`prerenderToNodeStream`](/reference/react-dom/static/prerenderToNodeStream) -These new APIs improve on `renderToString` by waiting for data to load for static HTML generation. They are designed to work with streaming environments like Node.js Streams and Web Streams. For example, in a Web Stream environment, you can prerender a React tree to static HTML with `prerender`: +These new APIs improve on `renderToString` by waiting for data to load for static HTML generation. They are designed to work with streaming environments like Node.js Streams and Web Streams. For example, in a Web Stream environment, you can prerender a React tree to static HTML with `prerender`: ```js import { prerender } from 'react-dom/static'; @@ -362,11 +362,7 @@ React 19 includes all of the React Server Components features included from the #### How do I build support for Server Components? {/*how-do-i-build-support-for-server-components*/} -<<<<<<< HEAD:src/content/blog/2024/04/25/react-19.md -While React Server Components in React 19 are stable and will not break between major versions, the underlying APIs used to implement a React Server Components bundler or framework do not follow semver and may break between minors in React 19.x. -======= -While React Server Components in React 19 are stable and will not break between minor versions, the underlying APIs used to implement a React Server Components bundler or framework do not follow semver and may break between minors in React 19.x. ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc:src/content/blog/2024/12/05/react-19.md +While React Server Components in React 19 are stable and will not break between minor versions, the underlying APIs used to implement a React Server Components bundler or framework do not follow semver and may break between minors in React 19.x. To support React Server Components as a bundler or framework, we recommend pinning to a specific React version, or using the Canary release. We will continue working with bundlers and frameworks to stabilize the APIs used to implement React Server Components in the future. From 3a6a612ca776a7bd862055498f2726e1b1e16d4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Wed, 1 Jan 2025 18:26:06 +0900 Subject: [PATCH 0468/1164] chore: translate `sidebarX.json` --- src/sidebarBlog.json | 2 +- src/sidebarHome.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sidebarBlog.json b/src/sidebarBlog.json index 8ff8995c1..1093aae19 100644 --- a/src/sidebarBlog.json +++ b/src/sidebarBlog.json @@ -4,7 +4,7 @@ "routes": [ { "hasSectionHeader": true, - "sectionHeader": "STAY INFORMED" + "sectionHeader": "최신 소식" }, { "title": "블로그", diff --git a/src/sidebarHome.json b/src/sidebarHome.json index 3b018bcc1..fee1a73d9 100644 --- a/src/sidebarHome.json +++ b/src/sidebarHome.json @@ -4,7 +4,7 @@ "routes": [ { "hasSectionHeader": true, - "sectionHeader": "GET STARTED" + "sectionHeader": "시작하기" }, { "title": "빠르게 시작하기", @@ -16,7 +16,7 @@ }, { "hasSectionHeader": true, - "sectionHeader": "LEARN REACT" + "sectionHeader": "React 학습하기" }, { "title": "UI 표현하기", @@ -76,7 +76,7 @@ }, { "hasSectionHeader": true, - "sectionHeader": "GET INVOLVED" + "sectionHeader": "참여하기" }, { "title": "React 커뮤니티", @@ -84,7 +84,7 @@ }, { "hasSectionHeader": true, - "sectionHeader": "STAY INFORMED" + "sectionHeader": "최신 소식" }, { "title": "React 블로그", From f10061da92c872b98aec43910ebafab1767a21ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Wed, 1 Jan 2025 18:36:15 +0900 Subject: [PATCH 0469/1164] docs: update `community/index.md` --- src/content/community/index.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/content/community/index.md b/src/content/community/index.md index 351b71cd9..7874616ef 100644 --- a/src/content/community/index.md +++ b/src/content/community/index.md @@ -8,17 +8,17 @@ React는 수백만의 개발자로 구성된 커뮤니티를 가지고 있습니 </Intro> -## 행동 규칙 {/*code-of-conduct*/} +## 행동 강령 {/*code-of-conduct*/} -React의 커뮤니티에 참여하기 전에 [행동 규칙을 반드시 읽어보세요.](https://github.com/facebook/react/blob/main/CODE_OF_CONDUCT.md) 우리는 [기여자 서약](https://www.contributor-covenant.org/)을 채택했고, 모든 커뮤니티 구성원이 서약 포함된 지침을 준수할 것을 기대합니다. +React 커뮤니티에 참여하기 전에 [반드시 행동 강령을 읽어주세요](https://github.com/facebook/react/blob/main/CODE_OF_CONDUCT.md). 우리는 [기여자 서약](https://www.contributor-covenant.org/)을 채택했고, 모든 커뮤니티 구성원들이 지침을 준수할 것을 기대합니다. ## Stack Overflow {/*stack-overflow*/} -Stack Overflow는 코드 수준의 질문을 하거나 특정 오류에 대한 해결 방법을 찾고자 할 때 유용한 포럼입니다. **reactjs**로 태그된 [기존의 질문을](https://stackoverflow.com/questions/tagged/reactjs) 읽어보거나 [직접 질문하세요](https://stackoverflow.com/questions/ask?tags=reactjs)! +Stack Overflow는 코드 관련 질문을 하거나 특정 오류에 대한 해결 방법을 찾고자 할 때 유용한 포럼입니다. **reactjs**로 태그된 [기존의 질문을](https://stackoverflow.com/questions/tagged/reactjs) 읽어보거나 [직접 질문하세요](https://stackoverflow.com/questions/ask?tags=reactjs)! ## 인기 있는 토론 포럼 {/*popular-discussion-forums*/} -React의 베스트 프랙티스, 애플리케이션 아키텍처, 그리고 React의 미래를 주제로 토론할 수 있는 많은 온라인 포럼이 존재합니다. 코드 수준에서 답할 수 있는 질문이 있다면, 대개 Stack Overflow가 더 적합합니다. +React의 베스트 프랙티스, 애플리케이션 아키텍처, 그리고 React의 미래를 주제로 토론할 수 있는 많은 온라인 포럼이 존재합니다. 코드 레벨에서 답할 수 있는 질문이 있다면, 대개 Stack Overflow가 더 적합합니다. 각 커뮤니티는 수천 명의 React 사용자로 구성되어 있습니다. From 0fda6a9524e68b3b968e1a3e55ba77b55beac30d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Wed, 1 Jan 2025 18:50:08 +0900 Subject: [PATCH 0470/1164] docs: update `videos.md` --- src/content/community/videos.md | 34 ++++++++++++++++----------------- src/sidebarCommunity.json | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/content/community/videos.md b/src/content/community/videos.md index fe5b13118..cb14245d9 100644 --- a/src/content/community/videos.md +++ b/src/content/community/videos.md @@ -1,10 +1,10 @@ --- -title: React 영상들 +title: React 영상 --- <Intro> -React와 React 에코시스템에 대한 토론을 위한 영상들입니다. +React와 React 생태계<sup>Ecosystem</sup>에 대한 토론 영상들입니다. </Intro> @@ -20,7 +20,7 @@ React와 React 에코시스템에 대한 토론을 위한 영상들입니다. ### 애플리케이션 개발자를 위한 React 18 {/*react-18-for-application-developers*/} -React 18로 업그레이드하는 데모는 여기에서 [Shruti Kapoor](https://twitter.com/shrutikapoor08)의 강연을 참조하세요: +React 18로 업그레이드하는 데모는 여기에서 [Shruti Kapoor](https://twitter.com/shrutikapoor08)의 강연을 참조하세요. <YouTubeIframe src="https://www.youtube.com/embed/ytudH8je5ko" title="YouTube video player" /> @@ -30,7 +30,7 @@ React 18에는 Suspense를 사용한 서버 측 렌더링 성능 개선 사항 스트리밍 서버 렌더링을 사용하면 서버의 React 컴포넌트에서 HTML을 생성하고 해당 HTML을 사용자에게 스트리밍할 수 있습니다. React 18에서는 'Suspense'를 사용하여 앱을 더 작은 독립 단위로 분해하여 나머지 앱을 차단하지 않고 서로 독립적으로 스트리밍할 수 있습니다. 이는 사용자가 콘텐츠를 더 빨리 보고 훨씬 빠르게 상호작용을 시작할 수 있다는 것을 의미합니다. -더 자세히 알아보려면 [Shaundai Person](https://twitter.com/shaundai)의 강연을 참조하세요: +더 자세히 알아보려면 [Shaundai Person](https://twitter.com/shaundai)의 강연을 참조하세요. <YouTubeIframe src="https://www.youtube.com/embed/pj5N-Khihgc" title="YouTube video player" /> @@ -38,7 +38,7 @@ React 18에는 Suspense를 사용한 서버 측 렌더링 성능 개선 사항 React 18에서는 전문가, 개발자, 라이브러리 관리자, 교육자들로 구성된 패널과 협력하기 위해 첫 번째 워킹 그룹을 만들었습니다. 우리는 함께 점진적인 채택 전략을 세우고 `useId`, `useSyncExternalStore`, `useInsertionEffect`와 같은 새로운 API를 개선하기 위해 노력했습니다. -이 작업에 대한 개요는 [Aakansha' Doshi](https://twitter.com/aakansha1216)의 강연을 참조하세요: +이 작업에 대한 개요는 [Aakansha' Doshi](https://twitter.com/aakansha1216)의 강연을 참조하세요. <YouTubeIframe src="https://www.youtube.com/embed/qn7gRClrC9U" title="YouTube video player" /> @@ -46,38 +46,38 @@ React 18에서는 전문가, 개발자, 라이브러리 관리자, 교육자들 이번 릴리즈의 새로운 기능을 지원하기 위해 새로 구성된 React 개발자 도구 팀과 개발자가 React 앱을 디버깅하는 데 도움이 되는 새로운 타임라인 프로파일러도 발표했습니다. -새로운 개발자 도구 기능에 대한 자세한 내용과 데모는 [Brian Vaughn](https://twitter.com/brian_d_vaughn)의 강연을 참조하세요: +새로운 개발자 도구 기능에 대한 자세한 내용과 데모는 [Brian Vaughn](https://twitter.com/brian_d_vaughn)의 강연을 참조하세요. <YouTubeIframe src="https://www.youtube.com/embed/oxDfrke8rZg" title="YouTube video player" /> ### memo 없는 React {/*react-without-memo*/} -미래를 내다보며, [Xuan Huang(黄玄)](https://twitter.com/Huxpro)이 자동 메모화 컴파일러에 대한 React Labs 연구의 업데이트를 공유했습니다. 이 강연에서 자세한 정보와 컴파일러 프로토타입 데모를 확인하세요: +미래를 내다보며, [Xuan Huang(黄玄)](https://twitter.com/Huxpro)이 자동 메모화 컴파일러에 대한 React Labs 연구의 업데이트를 공유했습니다. 이 강연에서 자세한 정보와 컴파일러 프로토타입 데모를 확인하세요. <YouTubeIframe src="https://www.youtube.com/embed/lGEMwh32soc" title="YouTube video player" /> ### React 문서 기조연설 {/*react-docs-keynote*/} -[Rachel Nabors](https://twitter.com/rachelnabors)가 React의 새로운 문서에 대한 투자에 대한 기조연설로 React로 학습하고 디자인하는 방법에 대한 강연을 시작했습니다([현재 react.dev로 제공됨](/blog/2023/03/16/introducing-react-dev)): +[Rachel Nabors](https://twitter.com/rachelnabors)가 React의 새 문서에 대한 투자와 관련한 기조연설로 React로 학습하고 디자인하는 방법에 대한 강연을 시작했습니다. ([현재 react.dev로 제공됨](/blog/2023/03/16/introducing-react-dev).) <YouTubeIframe src="https://www.youtube.com/embed/mneDaMYOKP8" title="YouTube video player" /> ### 그리고... {/*and-more*/} -**React로 학습하고 디자인하는 방법에 대한 강연:** +**React로 학습하고 설계하는 방법에 대한 강연.** * Debbie O'Brien: [새로운 React 문서에서 배운 것들](https://youtu.be/-7odLW_hG7s). * Sarah Rainsberger: [브라우저에서 학습하기](https://youtu.be/5X-WEQflCL0). * Linton Ye: [React로 디자인함에서의 ROI](https://youtu.be/7cPWmID5XAk). -* Delba de Oliveira: [React를 이용한 인터랙티브 놀이터](https://youtu.be/zL8cz2W0z34). +* Delba de Oliveira: [React를 이용한 상호작용 놀이터](https://youtu.be/zL8cz2W0z34). -**Relay, React Native, PyTorch 팀의 강연:** +**Relay, React Native, PyTorch 팀의 강연.** * Robert Balicki: [Relay 다시 소개](https://youtu.be/lhVGdErZuN4). * Eric Rozell과 Steven Moyes: [React Native 데스크톱](https://youtu.be/9L4FFrvwJwY). -* Roman Rädle: [React Native를 위한 온디바이스 머신러닝](https://youtu.be/NLj73vrc2I8) +* Roman Rädle: [React Native를 위한 온디바이스 머신러닝](https://youtu.be/NLj73vrc2I8). -**접근성, 툴링 및 서버 컴포넌트에 대한 커뮤니티 강연:** +**접근성, 툴링 및 서버 컴포넌트에 대한 커뮤니티 강연.** * Daishi Kato: [외부 스토어 라이브러리를 위한 React 18](https://youtu.be/oPfSC5bQPR8). * Diego Haz: [React 18에서 접근 가능한 컴포넌트 구축하기](https://youtu.be/dcm8fjBfro8). @@ -112,12 +112,12 @@ React.js Conf 2016의 영상 플레이리스트. React.js Conf 2015의 영상 플레이리스트. <YouTubeIframe title="React.js Conf 2015" src="https://www.youtube-nocookie.com/embed/playlist?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" /> -### Best Practices 다시 생각해 보기 {/*rethinking-best-practices*/} +### Best Practice 다시 생각해 보기 {/*rethinking-best-practices*/} -JSConf EU 2013에서 Pete Hunt의 강연: 템플릿 개념을 버리고 JavaScript를 사용하여 view를 구축하는 방법, 데이터가 변경될 때 전체 애플리케이션을 "re-rendering"하는 방법, DOM 및 이벤트를 경량으로 구현하는 방법 등 세 가지 주제를 다루고 있습니다. - (2013 - 0h30m). +JSConf EU 2013에서 Pete Hunt의 강연. 템플릿 개념을 버리고 자바스크립트를 사용하여 뷰<sup>View</sup>를 구축하는 방법, 데이터가 변경될 때 전체 애플리케이션을 리렌더링하는 방법, DOM 및 이벤트를 경량으로 구현하는 방법 등 세 가지 주제를 다루고 있습니다. (2013 - 0h30m). <YouTubeIframe title="Pete Hunt: React: Rethinking Best Practices - JSConf EU 2013" src="https://www.youtube-nocookie.com/embed/x7cQ3mrcKaY" /> -### React 소개하기 {/*introduction-to-react*/} +### React 소개 {/*introduction-to-react*/} -Facebook Seattle에서 Tom Occhino와 Jordan Walke의 React 소개 - (2013 - 1h20m). +Facebook Seattle에서 Tom Occhino와 Jordan Walke의 React 소개 (2013 - 1h20m). <YouTubeIframe title="Tom Occhino and Jordan Walke introduce React at Facebook Seattle" src="https://www.youtube-nocookie.com/embed/XxVg_s8xAms" /> diff --git a/src/sidebarCommunity.json b/src/sidebarCommunity.json index d3a9d8171..3918c05ee 100644 --- a/src/sidebarCommunity.json +++ b/src/sidebarCommunity.json @@ -20,7 +20,7 @@ "path": "/community/meetups" }, { - "title": "React 비디오", + "title": "React 영상", "path": "/community/videos" }, { From b1387b09dafd74764c0788ac9326e2a64824f36b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Wed, 1 Jan 2025 19:02:53 +0900 Subject: [PATCH 0471/1164] docs: update `docs-contributors` --- src/content/community/docs-contributors.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/content/community/docs-contributors.md b/src/content/community/docs-contributors.md index b49fefb56..ba1a1c8af 100644 --- a/src/content/community/docs-contributors.md +++ b/src/content/community/docs-contributors.md @@ -4,7 +4,7 @@ title: 문서 기여자 <Intro> -React 문서는 [React 팀](/community/team) 과 [외부 기여자](https://github.com/reactjs/react.dev/graphs/contributors)에 의해 작성되고 유지되고 있습니다. 우리는 이 페이지에서, 사이트에 상당한 기여를 한 사람들에게 감사를 전하고 싶습니다. +React 문서는 [React 팀](/community/team)과 [외부 기여자](https://github.com/reactjs/react.dev/graphs/contributors)에 의해 작성되고 유지되고 있습니다. 우리는 이 페이지에서, 사이트에 상당한 기여를 한 사람들에게 감사를 전하고 싶습니다. </Intro> @@ -39,4 +39,8 @@ React 문서는 [React 팀](/community/team) 과 [외부 기여자](https://git * [Harish Kumar](https://www.strek.in/): 개발과 유지보수 * [Luna Ruan](https://twitter.com/lunaruan): Sandbox 개선 -우리는 길을 따라 피드백을 제공한 수 많은 알파 테스터들과 커뮤니티 멤버들에게도 감사를 전하고 싶습니다. +## 한국어 번역 {/*korean-translations*/} + +* [루밀(LuMir)](https://github.com/lumirlumir): 사이트 개발, 유지보수, 번역 등 + +저희에게 피드백을 제공한 수 많은 알파 테스터들과 커뮤니티 멤버들에게도 감사를 전하고 싶습니다. From 3e688e338aa33db9d87eeab6af81d4383a8037e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Wed, 1 Jan 2025 19:07:23 +0900 Subject: [PATCH 0472/1164] docs: update `acknowledgements.md` --- src/content/community/acknowledgements.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/content/community/acknowledgements.md b/src/content/community/acknowledgements.md index 5726771b3..1f5f4dcf4 100644 --- a/src/content/community/acknowledgements.md +++ b/src/content/community/acknowledgements.md @@ -35,6 +35,7 @@ React는 원래 [Jordan Walke](https://github.com/jordwalke)에 의해 만들어 * [Josh Duck](https://github.com/joshduck) * [Joe Critchley](https://github.com/joecritch) * [Jeff Morrison](https://github.com/jeffmo) +* [LuMir](https://github.com/lumirlumir) * [Luna Ruan](https://github.com/lunaruan) * [Kathryn Middleton](https://github.com/kmiddleton14) * [Keyan Zhang](https://github.com/keyz) @@ -59,7 +60,7 @@ React는 원래 [Jordan Walke](https://github.com/jordwalke)에 의해 만들어 이 목록이 전체 목록은 아닙니다. -수년간 지도와 지원을 주신 [Tom Occhino](https://github.com/tomocchino)와 [Adam Wolff](https://github.com/wolffiex)에게 특별한 감사를 드립니다. [React를 다른 언어로 번역한](https://translations.react.dev/) 모든 자원봉사자에게도 감사합니다. +수년간 지도와 지원을 주신 [Tom Occhino](https://github.com/tomocchino)와 [Adam Wolff](https://github.com/wolffiex)에게 특별한 감사를 드립니다. [React를 다른 언어로 번역한](https://translations.react.dev/) [루밀(LuMir)](https://github.com/lumirlumir) 및 모든 자원봉사자에게도 감사드립니다. ## 특별한 감사 인사 {/*additional-thanks*/} From d6deb02fa001bf507b26c16e8a5d68f8982ee80f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Wed, 1 Jan 2025 19:40:31 +0900 Subject: [PATCH 0473/1164] docs: update `versioning-policy.md` --- src/content/community/versioning-policy.md | 46 +++++++++++----------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/content/community/versioning-policy.md b/src/content/community/versioning-policy.md index 241619139..3516d5f5e 100644 --- a/src/content/community/versioning-policy.md +++ b/src/content/community/versioning-policy.md @@ -3,19 +3,21 @@ title: 버전 관리 정책 --- <Intro> -React의 모든 안정적인 빌드는 높은 수준의 테스트를 거치고 시맨틱 버전(semver)을 따릅니다. React는 또한 실험적인 기능에 대한 초기 피드백을 장려하기 위해 불안정한 릴리스 채널을 제공합니다. 이 페이지에서는 React 릴리스에서 기대할 수 있는 것에 관해 설명합니다. +React의 모든 안정적인 빌드는 높은 수준의 테스트를 거치고 유의적 버전<sup>Sementic Versioning, semver</sup>을 따릅니다. React는 또한 실험적인 기능에 대한 초기 피드백을 장려하기 위해 불안정한 릴리스 채널을 제공합니다. 이 페이지에서는 React 릴리스에서 기대할 수 있는 것에 대해 설명합니다. </Intro> -지난 버전을 확인하려면, [Versions](/versions) 페이지를 참고해주세요. +지난 버전을 확인하려면, [React 버전](/versions) 페이지를 참고해주세요. ## Stable releases {/*stable-releases*/} +Stable React releases (also known as “Latest” release channel) follow [semantic versioning (semver)](https://semver.org/lang/ko/) principles. + 버전 번호 **x.y.z**를 사용할 때 다음과 같습니다. * **치명적인 버그 수정**을 릴리즈할 때는 **패치 릴리즈**를 만들어 **z** 숫자를 변경합니다. (예: 15.6.2에서 15.6.3으로) * **새로운 기능**이나 **치명적이지 않은 버그 수정**을 릴리즈할 때는 **마이너 릴리즈**를 만들어 **y** 숫자를 변경합니다. (예: 15.6.2에서 15.7.0으로) -* **breaking changes**를 릴리즈할 때는 **메이저 릴리즈**를 만들어 **x** 숫자를 변경합니다. (예: 15.6.2에서 16.0.0으로) +* **Breaking Change**를 릴리즈할 때는 **메이저 릴리즈**를 만들어 **x** 숫자를 변경합니다. (예: 15.6.2에서 16.0.0으로) 메이저 릴리즈는 새로운 기능을 포함할 수도 있고, 어떤 릴리즈든 버그 수정을 포함할 수도 있습니다. @@ -23,28 +25,28 @@ React의 모든 안정적인 빌드는 높은 수준의 테스트를 거치고 ### Breaking Changes {/*breaking-changes*/} -Breaking Changes는 모두에게 불편하기에 우리는 메이저 릴리즈의 수를 최소화하려고 노력합니다. 예를 들어, React 15는 2016년 4월에 릴리즈되었고, React 16은 2017년 9월에 릴리즈되었고, React 17은 2020년 10월에 릴리즈되었습니다. +Breaking Changes는 모두에게 불편하기에 우리는 메이저 릴리즈의 수를 최소화하려고 노력합니다. 예를 들어, React 15는 2016년 4월에 릴리즈, React 16은 2017년 9월에 릴리즈, React 17은 2020년 10월에 릴리즈되었습니다. 대신, 새로운 기능들을 마이너 버전으로 릴리즈합니다. 이는 마이너 릴리즈가 그 이름이 덜 주목받을지라도 종종 메이저 릴리즈보다 더 흥미로우며 매력적이라는 것을 의미합니다. ### 안정성에 기여하기 {/*commitment-to-stability*/} -시간이 지남에 따라 React를 변경할 때, 새로운 기능을 활용하는 데 필요한 노력을 최소화하려고 노력합니다. 가능한 경우, 오래된 API를 별개의 패키지에 넣는 한이 있더라도 작동하도록 합니다. 예를 들어, [믹스인은 몇 년 동안 권장되지 않았지만](https://legacy.reactjs.org/blog/2016/07/13/mixins-considered-harmful.html) [`create-react-class`를 통해](https://legacy.reactjs.org/docs/react-without-es6.html#mixins) 지금까지 지원되고 있으며, 많은 코드베이스가 이를 안정적인 레거시 코드로 계속 사용하고 있습니다. +시간이 지남에 따라 React를 변경할 때, 새로운 기능을 활용하는 데 필요한 노력을 최소화하려고 노력합니다. 가능한 경우, 오래된 API를 별개의 패키지에 넣는 한이 있더라도 작동하도록 합니다. 예를 들어, [믹스인<sup>Mixin</sup>은 몇 년 동안 권장되지 않았지만](https://legacy.reactjs.org/blog/2016/07/13/mixins-considered-harmful.html) [`create-react-class`를 통해](https://legacy.reactjs.org/docs/react-without-es6.html#mixins) 지금까지 지원하고 있으며, 많은 코드베이스가 이를 안정적인 레거시 코드로 계속 사용하고 있습니다. -100만 명 이상의 개발자가 React를 사용하며 수백만 개의 컴포넌트를 일괄적으로 유지 관리합니다. 페이스북 코드베이스에만 5만개가 넘는 React 컴포넌트가 있습니다. 이는 우리가 새로운 React 버전으로 업그레이드하는 것을 가능한 한 쉽게 만들어야 한다는 것을 의미합니다. 만약 마이그레이션 과정 없이 큰 변화를 만든다면, 사람들은 오래된 버전에 갇히게 될 것입니다. 페이스북에서는 이러한 업그레이드 과정을 테스트합니다. 10 명이 되지 않는 우리 팀이 5만 개가 넘는 컴포넌트를 업데이트할 수 있다면, React를 사용하는 사람이라면 누구나 업그레이드를 관리할 수 있을 것입니다. 대부분의 경우, 우리는 컴포넌트 문법을 업그레이드하기 위해 [자동화된 명령문](https://github.com/reactjs/react-codemod)을 작성하고, 이를 오픈소스 릴리즈에 포함해 모두가 사용할 수 있도록 합니다. +100만 명 이상의 개발자가 React를 사용하며 수백만 개의 컴포넌트를 일괄적으로 유지 관리합니다. 페이스북 코드베이스에만 5만개가 넘는 React 컴포넌트가 있습니다. 이는 우리가 새로운 React 버전으로 업그레이드하는 것을 가능한 한 쉽게 만들어야 한다는 것을 의미합니다. 만약 마이그레이션 과정 없이 큰 변화를 만든다면, 사람들은 오래된 버전에 갇히게 될 것입니다. 페이스북에서는 이러한 업그레이드 과정을 테스트합니다. 10명이 되지 않는 저희 팀이 5만 개가 넘는 컴포넌트를 업데이트할 수 있다면, React를 사용하는 사람이라면 누구나 업그레이드를 관리할 수 있을 것입니다. 대부분의 경우, 우리는 컴포넌트 문법을 업그레이드하기 위해 [자동화된 명령문](https://github.com/reactjs/react-codemod)을 작성하고, 이를 오픈소스 릴리즈에 포함해 모두가 사용할 수 있도록 합니다. ### 경고를 활용한 점진적 업그레이드 {/*gradual-upgrades-via-warnings*/} -React의 개발 빌드에는 유용한 경고가 많이 포함되어 있습니다. 가능한 경우, 우리는 미래의 breaking changes를 위해 경고를 추가합니다. 이렇게 함으로써 앱에 최신 릴리즈에 대한 경고가 없다면, 다음 메이저 릴리즈와 호환될 것입니다. 이는 앱을 하나의 컴포넌트씩 업그레이드할 수 있도록 해줍니다. +React의 개발 빌드에는 유용한 경고가 많이 포함되어 있습니다. 가능한 경우, 우리는 미래의 Breaking Change를 위해 경고를 추가합니다. 이 방법을 따르면, 최신 릴리스에서 경고가 없는 앱은 다음 메이저 릴리스와 호환됩니다. 이는 앱을 하나의 컴포넌트씩 업그레이드할 수 있도록 해줍니다. -개발 빌드에서 나타나는 경고는 앱의 런타임 동작에 영향을 미치지 않습니다. 즉, 개발 빌드와 프로덕션 빌드 간 앱이 동일하게 동작할 것이라는 확신을 가질 수 있습니다. -- 유일한 차이점은 프로덕션 빌드에서 경고가 출력되지 않고 더 효율적이라는 것입니다. (만약 그렇지 않다면, 이슈를 제출해 주세요.) +개발 빌드에서 나타나는 경고는 앱의 런타임 동작에 영향을 미치지 않습니다. 즉, 개발 빌드와 프로덕션 빌드 간 앱이 동일하게 동작할 것이라는 확신을 가질 수 있습니다. 유일한 차이점은 프로덕션 빌드에서 경고가 출력되지 않고 더 효율적이라는 것입니다. (만약 그렇지 않다면, 이슈를 제출해 주세요.) -### 어떤 것들이 breaking change로 간주되나요? {/*what-counts-as-a-breaking-change*/} +### 어떤 것들이 Breaking Change로 간주되나요? {/*what-counts-as-a-breaking-change*/} 일반적으로, 다음 변경 사항들은 메이저 버전 번호를 변경하지 *않습니다*. -* **개발 빌드 경고.** 프로덕션 동작에 영향을 미치지 않으므로, 우리는 메이저 버전 사이에 새로운 경고를 추가하거나 기존 경고를 수정할 수 있습니다. 이를 통해 앞으로 다가올 breaking changes에 대해 안정적으로 경고할 수 있습니다. +* **개발 빌드 경고.** 프로덕션 동작에 영향을 미치지 않으므로, 우리는 메이저 버전 사이에 새로운 경고를 추가하거나 기존 경고를 수정할 수 있습니다. 이를 통해 앞으로 다가올 Breaking Change에 대해 안정적으로 경고할 수 있습니다. * **`unstable_`로 시작하는 API.** 이 API들은 아직 확정되지 않은 실험적 기능들로서 제공됩니다. `unstable_` 접두사를 사용하여 이들을 릴리즈함으로써, 더 빠르게 릴리즈를 반복하고 안정적인 API에 더 빠르게 도달할 수 있습니다. -* **Alpha 버전과 카나리 버전의 React.** 이른 시일 내에 새로운 기능을 테스트하기 위해 Alpha 버전의 React를 제공하지만, Alpha 기간 동안 배운 것을 바탕으로 변경할 수 있는 유연성이 필요합니다. 이러한 버전을 사용하는 경우, 안정적인 릴리즈 이전에 API가 변경될 수 있음을 유의해야 합니다. +* **Alpha 버전과 Canary 버전의 React.** 이른 시일 내에 새로운 기능을 테스트하기 위해 Alpha 버전의 React를 제공하지만, Alpha 기간 동안 배운 것을 바탕으로 변경할 수 있는 유연성이 필요합니다. 이러한 버전을 사용하는 경우, 안정적인 릴리즈 이전에 API가 변경될 수 있음을 유의해야 합니다. * **문서화되지 않은 API와 내부 데이터 구조.** `__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED`나 `__reactInternalInstance$uk43rzhitjg`와 같은 내부 속성 이름에 접근하는 경우, 이에 대한 보장이 없습니다. 당신 스스로 해결해야 합니다. 당신이 골머리를 앓는 것을 바라지 않기에, 이 정책은 실용적으로 설계되었습니다. 만약 이러한 변화를 모두 메이저 버전으로 릴리즈한다면, 더 많은 메이저 버전을 릴리즈하게 되고, 궁극적으로 버전 관리에 대해 커뮤니티에 더 많은 고통을 야기할 것입니다. 이는 우리가 원하는 만큼 React를 빠르게 개선할 수 없다는 것을 의미합니다. @@ -63,11 +65,11 @@ React의 개발 빌드에는 유용한 경고가 많이 포함되어 있습니 이러한 이유로 인해, 패치 릴리즈를 가장 중요한 버그와 보안 취약점에 대해서만 사용합니다. -만약 릴리즈에 내부적인 리팩터, 구현 세부 사항의 변경, 성능 개선, 작은 버그 수정과 같은 필수적이지 않은 변경 사항이 포함된다면, 새로운 기능이 없어도 마이너 버전을 증가시킵니다. +만약 릴리즈에 내부적인 리팩토링, 구현 세부 사항의 변경, 성능 개선, 작은 버그 수정과 같은 필수적이지 않은 변경 사항이 포함된다면, 새로운 기능이 없어도 마이너 버전을 증가시킵니다. ## 모든 릴리즈 채널 {/*all-release-channels*/} -React는 버그의 제출, 풀 리퀘스트의 생성, [RFC의 제출](https://github.com/reactjs/rfcs)을 위해 활발한 오픈소스 커뮤니티에 의존합니다. 피드백을 장려하기 위해 때때로 릴리즈되지 않은 기능을 포함하는 특별한 빌드를 공유합니다. +React는 버그 제출, 풀 리퀘스트 생성, [RFC 제출](https://github.com/reactjs/rfcs)을 위해 활발한 오픈소스 커뮤니티에 의존합니다. 피드백을 장려하기 위해 때때로 릴리즈되지 않은 기능을 포함하는 특별한 빌드를 공유합니다. <Note> @@ -77,16 +79,16 @@ React는 버그의 제출, 풀 리퀘스트의 생성, [RFC의 제출](https://g 각각의 React 릴리즈 채널은 서로 다른 사용 사례를 위해 설계되었습니다. -- [**최신 채널**](#latest-channel)은 안정적인 시맨틱 버전 React 릴리즈를 위한 채널입니다. npm에서 React를 설치할 때 확인할 수 있습니다. 최신 채널은 당신이 이미 사용하고 있는 채널입니다. **React를 직접 사용하는 사용자 인터페이스 애플리케이션은 이 채널을 사용합니다.** +- [**최신 채널**](#latest-channel)은 안정적인 시맨틱 버전 React 릴리즈를 위한 채널입니다. npm에서 React를 설치할 때 확인할 수 있습니다. 최신 채널은 여러분들이 이미 사용하고 있는 채널입니다. **React를 직접 사용하는 사용자 인터페이스 애플리케이션은 이 채널을 사용합니다.** - [**카나리 채널**](#canary-channel)은 React 저장소의 메인 브랜치를 따릅니다. 다음 시맨틱 버전 릴리즈를 위한 릴리즈 후보로 간주할 수 있습니다. **[프레임워크나 엄선된 설정에서 고정 버전의 React와 함께 이 채널을 사용할 수 있습니다.](/blog/2023/05/03/react-canaries) 또한 React와 서드파티 프로젝트 간의 통합 테스트를 위해 카나리 채널을 사용할 수 있습니다.** - [**실험적 채널**](#experimental-channel)은 아직 안정된 릴리즈에 포함되지 않은 실험적인 API와 기능을 포함합니다. 추가적인 기능 플래그를 활성화한 채로 메인 브랜치를 따릅니다. 이 채널을 사용하여 릴리즈되기 전에 새로운 기능을 시도할 수 있습니다. 모든 릴리즈는 npm에 공개되지만, 최신 채널만 시맨틱 버전을 사용합니다. 사전 릴리즈(카나리 채널과 실험적 채널)는 릴리즈의 내용과 커밋 날짜의 해시로부터 생성된 버전을 사용합니다. 예를 들어, 카나리 채널의 경우 `18.3.0-canary-388686f29-20230503`이고, 실험적 채널의 경우 `0.0.0-experimental-388686f29-20230503`입니다. -**최신 채널과 카나리 채널 모두 사용자 인터페이스 애플리케이션에 대해 공식적으로 지원되지만, 기대하는 바는 다릅니다.** +**최신 채널과 카나리 채널 모두 사용자 인터페이스 애플리케이션을 공식적으로 지원하지만, 기대하는 바는 다릅니다.** * 최신 채널 릴리즈는 전통적인 시맨틱 버전 모델을 따릅니다. -* 카나리 릴리즈는 [고정 버전](/blog/2023/05/03/react-canaries)이어야 하며, breaking changes를 포함할 수 있습니다. 자체적인 릴리즈 일정에 따라 새로운 React 기능과 버그 수정을 점진적으로 릴리즈하고자 하는 엄선된 설정(프레임워크와 같은)을 위해 존재합니다. +* 카나리 릴리즈는 [고정 버전](/blog/2023/05/03/react-canaries)이어야 하며, Breaking Changes를 포함할 수 있습니다. 자체적인 릴리즈 일정에 따라 새로운 React 기능과 버그 수정을 점진적으로 릴리즈하고자 하는 엄선된 설정(프레임워크와 같은)을 위해 존재합니다. 실험적 릴리즈는 테스트 목적으로만 제공되며 릴리즈 간에 동작이 변경되지 않는다는 보장을 제공하지 않습니다. 최신 채널 릴리즈에 사용하는 시맨틱 버전 프로토콜을 따르지 않습니다. @@ -96,7 +98,7 @@ React는 버그의 제출, 풀 리퀘스트의 생성, [RFC의 제출](https://g 최신 채널은 안정된 React 릴리즈를 위한 채널입니다. npm의 `latest` 태그에 해당합니다. 최신 채널은 실제 사용자들이 사용하게 되는 모든 React 앱에 대한 권장 채널입니다. -**만약 어떤 채널을 사용해야 할지 불확실하다면, 최신 채널을 사용하세요.** 직접적으로 React를 사용하고 있다면, 이미 사용하고 있는 채널입니다. 최신 채널의 업데이트는 매우 안정적이라고 기대할 수 있습니다. [안정적인 릴리즈](#stable-releases)에서 설명했듯, 버전은 시맨틱 버전 프로토콜을 따릅니다. +**만약 어떤 채널을 사용해야 할지 불확실하다면, 최신 채널을 사용하세요.** 직접적으로 React를 사용하고 있다면, 이미 사용하고 있는 채널일 것입니다. 최신 채널의 업데이트는 매우 안정적이라고 기대할 수 있습니다. [안정적인 릴리즈](#stable-releases)에서 설명했듯, 버전은 시맨틱 버전 프로토콜을 따릅니다. ### 카나리 채널 {/*canary-channel*/} @@ -137,11 +139,11 @@ Next.js는 이 워크플로우를 사용하는 프로젝트입니다. 예시로 카나리 채널과 마찬가지로 실험적 채널은 React 저장소의 메인 브랜치를 따르는 사전 릴리즈 채널입니다. 카나리 채널과 달리, 실험적 릴리즈에는 더 광범위한 릴리즈를 위해 준비되지 않은 추가 기능과 API가 포함됩니다. -통상적으로, 카나리 채널의 업데이트는 상응하는 실험적 채널의 업데이트를 동반합니다. 같은 소스 버전을 기반으로 하지만, 다른 기능 플래그들을 사용하여 빌드됩니다. +통상적으로, 카나리 채널의 업데이트는 상응하는 실험적 채널의 업데이트를 동반합니다. 같은 소스 버전을 기반으로 하지만, 다른 기능 플래그들을 사용하여 빌드합니다. -실험적 릴리즈는 카나리 채널이나 최신 채널 릴리즈와 크게 다를 수 있습니다. **사용자 인터페이스 애플리케이션에서 실험적 릴리즈를 사용하지 마세요.** 실험적 채널의 릴리즈 사이에는 자주 breaking changes이 발생할 수 있습니다. +실험적 릴리즈는 카나리 채널이나 최신 채널 릴리즈와 크게 다를 수 있습니다. **사용자 인터페이스 애플리케이션에서 실험적 릴리즈를 사용하지 마세요.** 실험적 채널의 릴리즈 사이에는 자주 Breaking Change가 발생할 수 있습니다. -실험적 릴리즈는 npm에 'experimental' 태그와 함께 게시됩니다. 버전은 `0.0.0-experimental-68053d940-20210623`와 같이 빌드 내용과 커밋 날짜의 해시로부터 생성됩니다. +실험적 릴리즈는 npm에 `experimental` 태그와 함께 게시됩니다. 버전은 `0.0.0-experimental-68053d940-20210623`와 같이 빌드 내용과 커밋 날짜의 해시로부터 생성됩니다. #### 실험적 릴리즈에는 무엇이 포함되나요? {/*what-goes-into-an-experimental-release*/} @@ -157,6 +159,6 @@ Next.js는 이 워크플로우를 사용하는 프로젝트입니다. 예시로 문서화되지 않은 기능들은 [RFC](https://github.com/reactjs/rfcs)가 함께 제공될 수 있습니다. -새로운 실험적 기능들이 준비되면 [React 블로그](/blog)에 게시가 될 것입니다. 그러나, 모든 실험적 기능들을 공개한다는 의미는 아닙니다. +새로운 실험적 기능들이 준비되면 [React 블로그](/blog)에 게시될 것입니다. 그러나, 모든 실험적 기능들을 공개한다는 의미는 아닙니다. -변경 사항에 대한 보다 자세한 내용은 Github 저장소의 [커밋 로그](https://github.com/facebook/react/commits/main)에서 확인할 수 있습니다. +변경 사항에 대한 보다 자세한 내용은 깃허브 저장소의 [커밋 로그](https://github.com/facebook/react/commits/main)에서 확인할 수 있습니다. From 4a51b083e38fe7d5d6e7e2ca8ed7faab3a367d21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Wed, 1 Jan 2025 19:46:25 +0900 Subject: [PATCH 0474/1164] docs: update `reference/react/index.md` --- src/content/reference/react/index.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/content/reference/react/index.md b/src/content/reference/react/index.md index 1caced987..e454d60f4 100644 --- a/src/content/reference/react/index.md +++ b/src/content/reference/react/index.md @@ -1,20 +1,20 @@ --- -title: React 참조 개요 +title: React 참고서 개요 --- <Intro> -이 섹션은 React와 관련된 작업에 대한 상세한 참조 문서를 제공합니다. React에 대한 소개는 [학습](/learn) 섹션을 참조하십시오. +이 섹션은 React와 관련된 작업에 대한 상세한 참고서를 제공합니다. React에 대한 소개는 [학습](/learn) 섹션을 참조하세요. </Intro> -React 참조 문서는 다음과 같은 기능적인 하위 섹션으로 구성되어 있습니다. +React 참고서는 다음과 같은 기능적인 하위 섹션으로 구성되어 있습니다. ## React {/*react*/} React의 프로그래밍 기능. -* [Hooks](/reference/react/hooks) - 컴포넌트에서 다양한 React 기능을 사용하세요. +* [Hook](/reference/react/hooks) - 컴포넌트에서 다양한 React 기능을 사용하세요. * [컴포넌트](/reference/react/components) - JSX에서 사용할 수 있는 내장 컴포넌트입니다. * [API](/reference/react/apis) - 컴포넌트 정의에 유용한 API들을 다룹니다. * [지시어](/reference/rsc/directives) - React 서버 컴포넌트와 호환되는 번들러에게 지시를 제공합니다. @@ -23,20 +23,20 @@ React의 프로그래밍 기능. React DOM은 브라우저 DOM 환경에서 실행되는 웹 애플리케이션에서만 지원되는 기능을 포함하고 있습니다. 이 섹션은 다음과 같이 나뉩니다. -* [Hooks](/reference/react-dom/hooks) - 브라우저 DOM 환경에서 실행되는 웹 애플리케이션을 위한 Hooks입니다. +* [Hook](/reference/react-dom/hooks) - 브라우저 DOM 환경에서 실행되는 웹 애플리케이션을 위한 Hook입니다. * [컴포넌트](/reference/react-dom/components) - React는 브라우저 내장 HTML 및 SVG 컴포넌트를 모두 지원합니다. -* [API](/reference/react-dom) - `react-dom` 패키지에는 웹 애플리케이션에서만 지원되는 메소드가 포함되어 있습니다. +* [API](/reference/react-dom) - `react-dom` 패키지에는 웹 애플리케이션에서만 지원되는 메서드가 포함되어 있습니다. * [클라이언트 API](/reference/react-dom/client) - `react-dom/client` API를 사용하면 브라우저에서 React 컴포넌트를 렌더링할 수 있습니다. * [서버 API](/reference/react-dom/server) - `react-dom/server` API를 사용하면 서버에서 React 컴포넌트를 HTML로 렌더링할 수 있습니다. ## React의 규칙 {/*rules-of-react*/} -React에는 패턴을 이해하기 쉽게 하며 고품질의 애플리케이션을 만들 수 있게 하는 일종의 규칙 혹은 모범적인 방식이 있습니다. +React에는 패턴 이해를 쉽게 하며 고품질의 애플리케이션을 만들 수 있게 하는 일종의 규칙 혹은 모범적인 방식이 있습니다. * [컴포넌트와 Hook은 순수해야 합니다](/reference/rules/components-and-hooks-must-be-pure) – 순수성은 코드를 더 쉽게 이해하고 디버그할 수 있도록 하며, React가 올바르게 컴포넌트와 Hook을 자동으로 최적화할 수 있도록 합니다. * [React가 컴포넌트와 Hook을 호출하는 방식](/reference/rules/react-calls-components-and-hooks) – React는 사용자 경험을 최적화하기 위해 필요할 때마다 컴포넌트와 Hook을 렌더링합니다. -* [Hook의 규칙](/reference/rules/rules-of-hooks) – Hook은 JavaScript 함수로 정의되지만 호출 위치에 제약이 있는 특별한 유형의 재사용 가능한 UI 로직입니다. +* [Hook의 규칙](/reference/rules/rules-of-hooks) – Hook은 자바스크립트 함수로 정의되지만 호출 위치에 제약이 있는 특별한 유형의 재사용 가능한 UI 로직입니다. ## 레거시 API {/*legacy-apis*/} -* [레거시 API](/reference/react/legacy) - `react` 패키지에서 내보낸 것이지만 새로 작성되는 코드에서는 권장되지 않습니다. +* [레거시 API](/reference/react/legacy) - `react` 패키지에서 내보낸 것이지만 새로 작성하는 코드에서는 권장하지 않습니다. From e28d7a051b1a5f9ef39aed67e65f47386be67316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Wed, 1 Jan 2025 19:59:27 +0900 Subject: [PATCH 0475/1164] docs: update `legacy.md` --- src/content/reference/react/index.md | 2 +- src/content/reference/react/legacy.md | 37 ++++++++------------------- 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/src/content/reference/react/index.md b/src/content/reference/react/index.md index e454d60f4..e8245b21b 100644 --- a/src/content/reference/react/index.md +++ b/src/content/reference/react/index.md @@ -39,4 +39,4 @@ React에는 패턴 이해를 쉽게 하며 고품질의 애플리케이션을 ## 레거시 API {/*legacy-apis*/} -* [레거시 API](/reference/react/legacy) - `react` 패키지에서 내보낸 것이지만 새로 작성하는 코드에서는 권장하지 않습니다. +* [레거시 API](/reference/react/legacy) - `react` 패키지에서 내보냈지만<sup>Exported</sup> 새로 작성할 코드에서는 권장하지 않습니다. diff --git a/src/content/reference/react/legacy.md b/src/content/reference/react/legacy.md index 9127bae91..b744d8756 100644 --- a/src/content/reference/react/legacy.md +++ b/src/content/reference/react/legacy.md @@ -1,10 +1,10 @@ --- -title: "Legacy React APIs" +title: "Legacy React API" --- <Intro> -이 API는 `react` 패키지에서 추출했지만 새로 작성할 코드에서 사용을 추천하지 않습니다. 링크를 통해 각각의 API 페이지에서 제시한 대안을 확인해주세요. +아래 API는 `react` 패키지에서 내보냈지만<sup>Exported</sup> 새로 작성할 코드에서는 권장하지 않습니다. 링크를 통해 각각의 API 페이지에서 제시한 대안을 확인해주세요. </Intro> @@ -12,42 +12,25 @@ title: "Legacy React APIs" ## Legacy APIs {/*legacy-apis*/} -<<<<<<< HEAD -* [`Children`](/reference/react/Children)은 `children` prop으로 받은 JSX를 조작하고 변형할 수 있습니다. [대안 확인하기](/reference/react/Children#alternatives) -* [`cloneElement`](/reference/react/cloneElement)를 통해 다른 엘리먼트를 시작점으로 사용하여 React 엘리먼트를 생성할 수 있습니다. [대안 확인하기](/reference/react/cloneElement#alternatives) -* [`Component`](/reference/react/Component)는 Javascript 클래스로써 React 컴포넌트를 정의합니다. [대안 확인하기](/reference/react/Component#alternatives) +* [`Children`](/reference/react/Children)은 `children` Prop으로 받은 JSX를 조작하고 변형할 수 있습니다. [대안 확인하기](/reference/react/Children#alternatives). +* [`cloneElement`](/reference/react/cloneElement)를 통해 다른 엘리먼트를 시작점으로 사용하여 React 엘리먼트를 생성할 수 있습니다. [대안 확인하기](/reference/react/cloneElement#alternatives). +* [`Component`](/reference/react/Component)는 자바스크립트 클래스로써 React 컴포넌트를 정의합니다. [대안 확인하기](/reference/react/Component#alternatives). * [`createElement`](/reference/react/createElement)로 React 엘리먼트를 생성합니다. 일반적으로 JSX를 대신 사용합니다. -* [`createRef`](/reference/react/createRef)는 임의의 값을 포함할 수 있는 참조 객체를 생성합니다. [대안 확인하기](/reference/react/createRef#alternatives) +* [`createRef`](/reference/react/createRef)는 임의의 값을 포함할 수 있는 참조 객체를 생성합니다. [대안 확인하기](/reference/react/createRef#alternatives). +* [`forwardRef`](/reference/react/forwardRef) lets your component expose a DOM node to parent component with a [ref](/learn/manipulating-the-dom-with-refs). * [`isValidElement`](/reference/react/isValidElement)는 값의 React 엘리먼트 여부를 확인합니다. 일반적으로 [`cloneElement`](/reference/react/cloneElement)와 함께 사용합니다. -* [`PureComponent`](/reference/react/PureComponent)는 [`Component`](/reference/react/Component)와 유사하지만, 동일한 props의 재렌더는 생략합니다. [대안 확인하기](/reference/react/PureComponent#alternatives) -======= -* [`Children`](/reference/react/Children) lets you manipulate and transform the JSX received as the `children` prop. [See alternatives.](/reference/react/Children#alternatives) -* [`cloneElement`](/reference/react/cloneElement) lets you create a React element using another element as a starting point. [See alternatives.](/reference/react/cloneElement#alternatives) -* [`Component`](/reference/react/Component) lets you define a React component as a JavaScript class. [See alternatives.](/reference/react/Component#alternatives) -* [`createElement`](/reference/react/createElement) lets you create a React element. Typically, you'll use JSX instead. -* [`createRef`](/reference/react/createRef) creates a ref object which can contain arbitrary value. [See alternatives.](/reference/react/createRef#alternatives) -* [`forwardRef`](/reference/react/forwardRef) lets your component expose a DOM node to parent component with a [ref.](/learn/manipulating-the-dom-with-refs) -* [`isValidElement`](/reference/react/isValidElement) checks whether a value is a React element. Typically used with [`cloneElement`.](/reference/react/cloneElement) -* [`PureComponent`](/reference/react/PureComponent) is similar to [`Component`,](/reference/react/Component) but it skip re-renders with same props. [See alternatives.](/reference/react/PureComponent#alternatives) ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +* [`PureComponent`](/reference/react/PureComponent)는 [`Component`](/reference/react/Component)와 유사하지만, 동일한 Prop의 재렌더링은 생략합니다. [대안 확인하기](/reference/react/PureComponent#alternatives). --- ## Removed APIs {/*removed-apis*/} -These APIs were removed in React 19: +아래 API들은 React 19에서 제거되었습니다. -<<<<<<< HEAD -이 API는 추후 React major 버전에서 제거될 예정입니다. - -</Deprecated> - -* [`createFactory`](/reference/react/createFactory)는 특정 유형의 React 엘리먼트를 생성하는 함수를 만듭니다. -======= * [`createFactory`](https://18.react.dev/reference/react/createFactory): use JSX instead. * Class Components: [`static contextTypes`](https://18.react.dev//reference/react/Component#static-contexttypes): use [`static contextType`](#static-contexttype) instead. * Class Components: [`static childContextTypes`](https://18.react.dev//reference/react/Component#static-childcontexttypes): use [`static contextType`](#static-contexttype) instead. * Class Components: [`static getChildContext`](https://18.react.dev//reference/react/Component#getchildcontext): use [`Context.Provider`](/reference/react/createContext#provider) instead. * Class Components: [`static propTypes`](https://18.react.dev//reference/react/Component#static-proptypes): use a type system like [TypeScript](https://www.typescriptlang.org/) instead. * Class Components: [`this.refs`](https://18.react.dev//reference/react/Component#refs): use [`createRef`](/reference/react/createRef) instead. ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc + From 74d59fdaa916c5d2c645fea3149d2163c0e42516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Wed, 1 Jan 2025 20:25:23 +0900 Subject: [PATCH 0476/1164] docs: update `Children.md` --- src/content/reference/react/Children.md | 60 ++++++++++++------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/content/reference/react/Children.md b/src/content/reference/react/Children.md index d1955b689..470b75c69 100644 --- a/src/content/reference/react/Children.md +++ b/src/content/reference/react/Children.md @@ -4,13 +4,13 @@ title: Children <Pitfall> -`Children`을 사용하는 것은 일반적이지 않고 취약한 코드가 될 수 있습니다. [일반적으로 사용하는 대안을 살펴보세요.](#alternatives) +`Children`을 사용하는 것은 일반적이지 않고 불안정한 코드를 만들 수 있습니다. [일반적으로 사용하는 대안을 살펴보세요.](#alternatives) </Pitfall> <Intro> -`Children`을 사용해서 [`children` prop](/learn/passing-props-to-a-component#passing-jsx-as-children)로 받은 JSX를 조작하고 변환할 수 있습니다. +`Children`을 사용해서 [`children` Prop](/learn/passing-props-to-a-component#passing-jsx-as-children)로 받은 JSX를 조작하고 변환할 수 있습니다. ```js const mappedChildren = Children.map(children, child => @@ -46,11 +46,11 @@ function RowList({ children }) { } ``` -[아래 예시 보기](#counting-children) +[아래 예시 보기](#counting-children). #### 매개변수 {/*children-count-parameters*/} -* `children`: 컴포넌트에서 받은 [`children` prop](/learn/passing-props-to-a-component#passing-jsx-as-children)의 값. +* `children`: 컴포넌트에서 받은 [`children` Prop](/learn/passing-props-to-a-component#passing-jsx-as-children)의 값. #### 반환값 {/*children-count-returns*/} @@ -58,7 +58,7 @@ function RowList({ children }) { #### 주의 사항 {/*children-count-caveats*/} -- 빈 노드(`null`, `undefined` 혹은 Boolean), 문자열, 숫자, [React 엘리먼트](/reference/react/createElement)는 개별 노드로 간주합니다. 배열 자체는 개별 노드가 아니지만 배열의 자식 요소는 개별 노드로 간주합니다. **React 엘리먼트의 하위 요소는 순회하지 않습니다.** React 엘리먼트는 렌더링 되지 않으며 자식 요소를 순회하지 않습니다. [Fragments](/reference/react/Fragment) 역시 순회하지 않습니다. +- 빈 노드(`null`, `undefined` 혹은 Boolean), 문자열, 숫자, [React 엘리먼트](/reference/react/createElement)는 개별 노드로 간주합니다. 배열 자체는 개별 노드가 아니지만 배열의 자식 요소는 개별 노드로 간주합니다. **React 엘리먼트의 하위 요소는 순회하지 않습니다.** React 엘리먼트는 렌더링 되지 않으며 자식 요소를 순회하지 않습니다. [Fragment](/reference/react/Fragment) 역시 순회하지 않습니다. --- @@ -78,11 +78,11 @@ function SeparatorList({ children }) { // ... ``` -[아래 예시 보기](#running-some-code-for-each-child) +[아래 예시 보기](#running-some-code-for-each-child). #### 매개변수 {/*children-foreach-parameters*/} -* `children`: 컴포넌트에서 받은 [`children` prop](/learn/passing-props-to-a-component#passing-jsx-as-children)의 값. +* `children`: 컴포넌트에서 받은 [`children` Prop](/learn/passing-props-to-a-component#passing-jsx-as-children)의 값. * `fn`: [배열의`forEach` 메서드](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) 콜백처럼 각 자식 요소에서 실행할 함수. 자식 요소를 첫 번째 인수로, 인덱스를 두 번째 인수로 받습니다. 인덱스는 0에서 시작해서 호출할 때마다 증가합니다. * **optional** `thisArg`: `fn` 함수가 호출될 때 사용될 [`this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this)의 값. 생략 시 `undefined`로 간주합니다. @@ -116,11 +116,11 @@ function RowList({ children }) { } ``` -[아래 예시 보기](#transforming-children) +[아래 예시 보기](#transforming-children). #### 매개변수 {/*children-map-parameters*/} -* `children`: 컴포넌트에서 받은 [`children` prop](/learn/passing-props-to-a-component#passing-jsx-as-children)의 값. +* `children`: 컴포넌트에서 받은 [`children` Prop](/learn/passing-props-to-a-component#passing-jsx-as-children)의 값. * `fn`: [베열의 `map` 메서드](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) 콜백같은 매핑 함수. 자식 요소를 첫 번째 인수로, 인덱스를 두 번째 인수로 받습니다. 인덱스는 0에서 시작해서 호출할 때마다 증가합니다. 함수는 빈 노드(`null`, `undefined` 혹은 Boolean), 문자열, 숫자, React 엘리먼트 혹은 다른 React 노드의 배열과 같은 React 노드를 반환해야 합니다. * **optional** `thisArg`: `fn` 함수가 호출될 때 사용될 [`this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this)의 값. 생략시 `undefined`로 간주합니다. @@ -151,12 +151,12 @@ function Box({ children }) { #### 매개변수 {/*children-only-parameters*/} -* `children`: 컴포넌트에서 받은 [`children` prop](/learn/passing-props-to-a-component#passing-jsx-as-children)의 값. +* `children`: 컴포넌트에서 받은 [`children` Prop](/learn/passing-props-to-a-component#passing-jsx-as-children)의 값. #### 반환값 {/*children-only-returns*/} `children`이 [유효한 엘리먼트](/reference/react/isValidElement)라면 그 엘리먼트를 반환합니다. -그렇지 않다면, 에러를 throw합니다. +그렇지 않다면, 에러를 던집니다. #### 주의 사항 {/*children-only-caveats*/} @@ -179,7 +179,7 @@ export default function ReversedList({ children }) { #### 매개변수 {/*children-toarray-parameters*/} -* `children`: 컴포넌트에서 받은 [`children` prop](/learn/passing-props-to-a-component#passing-jsx-as-children)의 값. +* `children`: 컴포넌트에서 받은 [`children` Prop](/learn/passing-props-to-a-component#passing-jsx-as-children)의 값. #### 반환값 {/*children-toarray-returns*/} @@ -188,7 +188,7 @@ export default function ReversedList({ children }) { #### 주의 사항 {/*children-toarray-caveats*/} -- 빈 노드(`null`, `undefined`, 혹은 Booleans)는 반환된 배열에서 생략됩니다. **반환된 엘리먼트의 key는 기존 엘리먼트의 key, 중첩 수준과 위치를 기준으로 계산되므로** 배열을 평면화하더라도 동작이 변경되지 않습니다. +- 빈 노드(`null`, `undefined`, 혹은 Boolean)는 반환된 배열에서 생략됩니다. **반환된 엘리먼트의 key는 기존 엘리먼트의 key, 중첩 수준과 위치를 기준으로 계산되므로** 배열을 평면화하더라도 동작이 변경되지 않습니다. --- @@ -196,7 +196,7 @@ export default function ReversedList({ children }) { ### `children` 변환하기 {/*transforming-children*/} -`Children.map`은 [`children` prop로 받은](/learn/passing-props-to-a-component#passing-jsx-as-children) JSX를 변환합니다. +`Children.map`은 [`children` Prop로 받은](/learn/passing-props-to-a-component#passing-jsx-as-children) JSX를 변환합니다. ```js {6,10} import { Children } from 'react'; @@ -214,7 +214,7 @@ function RowList({ children }) { } ``` -위 예시에서 `RowList`는 모든 자식 요소를 `<div className="Row">`로 감싸줍니다. 부모 컴포넌트가 `RowList`에 세 개의 `<p>` 태그를 `children` prop로 넘겨준다고 가정해 봅시다. +위 예시에서 `RowList`는 모든 자식 요소를 `<div className="Row">`로 감싸줍니다. 부모 컴포넌트가 `RowList`에 세 개의 `<p>` 태그를 `children` Prop로 넘겨준다고 가정해 봅시다. ```js <RowList> @@ -293,11 +293,11 @@ export default function RowList({ children }) { <DeepDive> -#### `children` prop는 왜 항상 배열이 아닌가요? {/*why-is-the-children-prop-not-always-an-array*/} +#### `children` Prop는 왜 항상 배열이 아닌가요? {/*why-is-the-children-prop-not-always-an-array*/} -React에서 `children` prop는 *불분명한* 데이터 구조로 취급됩니다. `children`이 구조화된 방식에 의존할 수 없다는 의미입니다. 변환하거나 필터링하거나 개수를 세기 위해서는 `Children` 메서드를 사용해야 합니다. +React에서 `children` Prop는 *불분명한* 데이터 구조로 취급됩니다. `children`이 구조화된 방식에 의존할 수 없다는 의미입니다. 변환하거나 필터링하거나 개수를 세기 위해서는 `Children` 메서드를 사용해야 합니다. -실제로 `children` 데이터 구조는 내부적으로 배열로 표현되고는 합니다. 그러나 만약 하나의 자식만 있다면 React는 불필요한 메모리 오버헤드를 방지하기 위해 배열을 추가로 생성하지 않습니다. `children` prop에 직접 접근하지 않고 `Children` 메서드를 사용한다면, 실제로 React가 데이터 구조를 어떻게 구현했더라도 코드는 깨지지 않습니다. +실제로 `children` 데이터 구조는 내부적으로 배열로 표현되고는 합니다. 그러나 만약 하나의 자식만 있다면 React는 불필요한 메모리 오버헤드를 방지하기 위해 배열을 추가로 생성하지 않습니다. `children` Prop에 직접 접근하지 않고 `Children` 메서드를 사용한다면, 실제로 React가 데이터 구조를 어떻게 구현했더라도 코드는 깨지지 않습니다. `children`이 배열이더라도 `Children.map`을 유용하게 쓸 수 있습니다. 예를 들어 `Children.map`은 반환된 엘리먼트의 [key](/learn/rendering-lists#keeping-list-items-in-order-with-key)를 전달받은 `children`의 key와 병합합니다. 이를 통해 위 예시처럼 감싸지더라도 원본 JSX 자식 요소는 key를 잃어버리지 않습니다. @@ -305,12 +305,12 @@ React에서 `children` prop는 *불분명한* 데이터 구조로 취급됩니 <Pitfall> -`children` 데이터 구조는 JSX로 전달된 컴포넌트의 **렌더링 결과를 포함하지 않습니다.** 아래 예시에서 `RowList`가 받은 `children`에는 세 개가 아닌 두 개의 아이템만 포함됩니다. +`children` 데이터 구조는 JSX로 전달된 컴포넌트의 **렌더링 결과를 포함하지 않습니다.** 아래 예시에서 `RowList`가 받은 `children`에는 세 개가 아닌 두 개의 아이템만 포함합니다. 1. `<p>This is the first item.</p>` 2. `<MoreRows />` -그렇기 때문에 아래 예시에서는 두 개의 래퍼만 생성됩니다. +그렇기 때문에 아래 예시에서는 두 개의 래퍼만 생성합니다. <Sandpack> @@ -492,7 +492,7 @@ export default function RowList({ children }) { ### `children` 배열로 병합하기 {/*converting-children-to-an-array*/} -`Children.toArray(children)`는 `children` 데이터 구조를 일반적인 JavaScript 배열로 변경합니다. 이것을 사용해서 [`filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), [`sort`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort), [`reverse`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse)와 같은 배열의 내장 메서드를 조작할 수 있습니다. +`Children.toArray(children)`는 `children` 데이터 구조를 일반적인 자바스크립트 배열로 변경합니다. 이것을 사용해서 [`filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), [`sort`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort), [`reverse`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse)와 같은 배열의 내장 메서드를 조작할 수 있습니다. <Sandpack> @@ -540,7 +540,7 @@ export default function ReversedList({ children }) { import { Children } from 'react'; ``` -소문자 `c`인 [`children`prop](/learn/passing-props-to-a-component#passing-jsx-as-children)와 혼동해서는 안 됩니다. [`children`prop](/learn/passing-props-to-a-component#passing-jsx-as-children)는 좋은 방법이고 권장되는 방식입니다. +소문자 `c`인 [`children` Prop](/learn/passing-props-to-a-component#passing-jsx-as-children)와 혼동해서는 안 됩니다. [`children` Prop](/learn/passing-props-to-a-component#passing-jsx-as-children)는 좋은 방법이고 권장되는 방식입니다. </Note> @@ -679,9 +679,9 @@ export function Row({ children }) { --- -### prop로 객체 배열 받기 {/*accepting-an-array-of-objects-as-a-prop*/} +### Prop로 객체 배열 받기 {/*accepting-an-array-of-objects-as-a-prop*/} -prop로 명시적으로 배열을 전달할 수 있습니다. 예를 들어, 아래 예시에서 `RowList`는 `rows` 배열을 prop로 받습니다. +Prop로 명시적으로 배열을 전달할 수 있습니다. 예를 들어, 아래 예시에서 `RowList`는 `rows` 배열을 Prop로 받습니다. <Sandpack> @@ -730,9 +730,9 @@ export function RowList({ rows }) { </Sandpack> -`rows`는 일반적인 JavaScript 배열이기 때문에, `RowList` 컴포넌트는 [`map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)과 같은 내장 배열 메서드를 사용할 수 있습니다. +`rows`는 일반적인 자바스크립트 배열이기 때문에, `RowList` 컴포넌트는 [`map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)과 같은 내장 배열 메서드를 사용할 수 있습니다. -이 패턴은 구조화된 데이터를 자식 요소와 함께 전달할 때 더 유용합니다. 아래 예시에서 `TabSwitcher` 컴포넌트는 `tabs` prop로 객체 배열을 받습니다. +이 패턴은 구조화된 데이터를 자식 요소와 함께 전달할 때 더 유용합니다. 아래 예시에서 `TabSwitcher` 컴포넌트는 `tabs` Prop로 객체 배열을 받습니다. <Sandpack> @@ -794,7 +794,7 @@ JSX로 자식 요소를 전달할 때와 달리 이런 방식은 각 아이템 --- -### 렌더링 prop로 렌더링 커스텀하기 {/*calling-a-render-prop-to-customize-rendering*/} +### 렌더링 Prop로 렌더링 커스텀하기 {/*calling-a-render-prop-to-customize-rendering*/} 모든 개별 항목에 대해 JSX를 생성하는 대신 JSX를 반환하는 함수를 전달하고 필요할 때 해당 함수를 호출할 수도 있습니다. 아래 예시에서 `App` 컴포넌트는 `renderContent` 함수를 `TabSwitcher` 컴포넌트에 전달합니다. `TabSwitcher` 컴포넌트는 선택된 탭에 대해서만 `renderContent`를 호출합니다. @@ -845,10 +845,10 @@ export default function TabSwitcher({ tabIds, getHeader, renderContent }) { </Sandpack> -`renderContent`와 같이 사용자 인터페이스의 일부를 어떻게 렌더링할지 정의하는 prop를 *렌더링 prop*라고 합니다. 하지만 특별한 것은 아닙니다. 단지 일반적인 함수의 prop일 뿐입니다. +`renderContent`와 같이 사용자 인터페이스의 일부를 어떻게 렌더링할지 정의하는 Prop를 *렌더링 Prop*라고 합니다. 하지만 특별한 것은 아닙니다. 단지 일반적인 함수의 Prop일 뿐입니다. -렌더링 props는 함수이므로 정보를 전달할 수 있습니다. -아래 예시에서 `RowList` 컴포넌트는 각 row의 `id`와 `index`를 `renderRow`에 렌더링 prop로 전달하고, `index`가 짝수인 row를 강조합니다. +렌더링 Prop은은 함수이므로 정보를 전달할 수 있습니다. +아래 예시에서 `RowList` 컴포넌트는 각 row의 `id`와 `index`를 `renderRow`에 렌더링 Prop로 전달하고, `index`가 짝수인 row를 강조합니다. <Sandpack> From 91664e9f39767d6de2df6789e6120930b1e3d805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Wed, 1 Jan 2025 20:28:39 +0900 Subject: [PATCH 0477/1164] docs: update `cloneElement.md` --- src/content/reference/react/cloneElement.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/reference/react/cloneElement.md b/src/content/reference/react/cloneElement.md index 99cc1c514..980478fd8 100644 --- a/src/content/reference/react/cloneElement.md +++ b/src/content/reference/react/cloneElement.md @@ -4,7 +4,7 @@ title: cloneElement <Pitfall> -`cloneElement`를 사용하는 것은 흔하지 않으며, 불안정한 코드를 만들 수 있습니다. [일반적인 대안을 확인하세요.](#alternatives) +`cloneElement`사용하는 것은 일반적이지 않고 불안정한 코드를 만들 수 있습니다. [일반적으로 사용하는 대안을 살펴보세요.](#alternatives) </Pitfall> @@ -554,9 +554,9 @@ button { --- -### Custom Hook으로 로직 추출하기 {/*extracting-logic-into-a-custom-hook*/} +### 커스텀 Hook으로 로직 추출하기 {/*extracting-logic-into-a-custom-hook*/} -다른 접근 방식으로는 자체 hook을 통해 "비시각적인" 로직을 추출하는 것을 시도해 볼 수 있습니다. 그리고 hook에 의해서 반환된 정보를 사용하여 렌더링할 내용을 정합니다. 예를 들어 다음과 같이 `useList` 같은 custom hook을 작성할 수 있습니다. +다른 접근 방식으로는 자체 hook을 통해 "비시각적인" 로직을 추출하는 것을 시도해 볼 수 있습니다. 그리고 hook에 의해서 반환된 정보를 사용하여 렌더링할 내용을 정합니다. 예를 들어 다음과 같이 `useList` 같은 커스텀 hook을 작성할 수 있습니다. ```js import { useState } from 'react'; From bea2d127bb71e2bbf74143fb6841585d8425afeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Wed, 1 Jan 2025 21:03:24 +0900 Subject: [PATCH 0478/1164] docs: update `Component.md` --- src/content/reference/react/Component.md | 109 +---------------------- 1 file changed, 3 insertions(+), 106 deletions(-) diff --git a/src/content/reference/react/Component.md b/src/content/reference/react/Component.md index e405966ec..8bb096417 100644 --- a/src/content/reference/react/Component.md +++ b/src/content/reference/react/Component.md @@ -50,11 +50,7 @@ class Greeting extends Component { ### `context` {/*context*/} -<<<<<<< HEAD -클래스 컴포넌트의 [context](/learn/passing-data-deeply-with-context)는 `this.context`로 사용할 수 있습니다. [`static contextType`](#static-contexttype)(modern) 또는 [`static contextTypes`](#static-contexttypes)(deprecated)를 사용하여 *어떤* context를 받길 원하는지 지정해야만 사용할 수 있습니다. -======= -The [context](/learn/passing-data-deeply-with-context) of a class component is available as `this.context`. It is only available if you specify *which* context you want to receive using [`static contextType`](#static-contexttype). ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +클래스 컴포넌트의 [context](/learn/passing-data-deeply-with-context)는 `this.context`로 사용할 수 있습니다. [`static contextType`](#static-contexttype)를 사용하여 *어떤* context를 받을지 지정해야만 사용할 수 있습니다. 클래스 컴포넌트는 한 번에 하나의 context만 읽을 수 있습니다. @@ -109,21 +105,6 @@ class Greeting extends Component { --- -<<<<<<< HEAD -### `refs` {/*refs*/} - -<Deprecated> - -이 API는 React의 향후 주요 버전에서 제거될 예정입니다. [대신 `createRef`를 사용하세요.](/reference/react/createRef) - -</Deprecated> - -컴포넌트에 대한 [legacy string refs](https://ko.reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs)에 액세스할 수 있습니다. - ---- - -======= ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc ### `state` {/*state*/} 클래스 컴포넌트의 state는 `this.state`로 사용할 수 있습니다. `state` 필드는 반드시 객체여야합니다. state를 직접 변경하지 마세요. state를 변경하려면 새 state로 `setState`를 호출하세요. @@ -501,21 +482,6 @@ class ChatRoom extends Component { --- -<<<<<<< HEAD -### `getChildContext()` {/*getchildcontext*/} - -<Deprecated> - -이 API는 향후 React의 주요 버전에서 제거될 예정입니다. [대신 `Context.Provider`를 사용하세요.](/reference/react/createContext#provider) - -</Deprecated> - -이 컴포넌트가 제공하는 [legacy context](https://ko.reactjs.org/docs/legacy-context.html)에 대한 값을 지정할 수 있습니다. - ---- - -======= ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc ### `getSnapshotBeforeUpdate(prevProps, prevState)` {/*getsnapshotbeforeupdate*/} `getSnapshotBeforeUpdate`를 구현하면 React가 DOM을 업데이트하기 바로 전에 호출합니다. 이를 통해 컴포넌트가 잠재적으로 변경되기 전에 DOM에서 일부 정보(예: 스크롤 위치)를 캡처할 수 있습니다. 이 생명주기 메서드가 반환하는 모든 값은 [`componentDidUpdate`](#componentdidupdate)에 매개변수로 전달됩니다. @@ -746,15 +712,9 @@ class Rectangle extends Component { #### 매개변수 {/*shouldcomponentupdate-parameters*/} -<<<<<<< HEAD - `nextProps`: 컴포넌트가 렌더링할 다음 props입니다. `nextProps`와 [`this.props`](#props)를 비교하여 무엇이 변경되었는지 확인합니다. - `nextState`: 컴포넌트가 렌더링할 다음 state입니다. `nextState`와 [`this.state`](#props)를 비교하여 무엇이 변경되었는지 확인합니다. -- `nextContext`: 컴포넌트가 렌더링할 다음 context입니다. `nextContext`를 [`this.context`](#context)와 비교하여 변경된 내용을 확인합니다. [`static contextType`](#static-contexttype)(modern) 또는 [`static contextTypes`](#static-contexttypes)(legacy)를 지정한 경우에만 사용할 수 있습니다. -======= -- `nextProps`: The next props that the component is about to render with. Compare `nextProps` to [`this.props`](#props) to determine what changed. -- `nextState`: The next state that the component is about to render with. Compare `nextState` to [`this.state`](#props) to determine what changed. -- `nextContext`: The next context that the component is about to render with. Compare `nextContext` to [`this.context`](#context) to determine what changed. Only available if you specify [`static contextType`](#static-contexttype). ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +- `nextContext`: 컴포넌트가 렌더링할 다음 context입니다. `nextContext`를 [`this.context`](#context)와 비교하여 변경된 내용을 확인합니다. [`static contextType`](#static-contexttype)(modern)을 지정한 경우에만 사용할 수 있습니다. #### 반환값 {/*shouldcomponentupdate-returns*/} @@ -828,13 +788,8 @@ React에 재렌더링을 건너뛸 수 있음을 알리려면 `false`를 반환 #### 매개변수 {/*unsafe_componentwillreceiveprops-parameters*/} -<<<<<<< HEAD - `nextProps`: 컴포넌트가 부모 컴포넌트로부터 받으려는 다음 props입니다. `nextProps`와 [`this.props`](#props)를 비교하여 무엇이 변경되었는지 확인합니다. -- `nextContext`: 컴포넌트가 가장 가까운 공급자(provider)로부터 받으려는 다음 props입니다. `nextContext`를 [`this.context`](#context)와 비교하여 변경된 내용을 확인합니다. [`static contextType`](#static-contexttype)(modern) 또는 [`static contextTypes`](#static-contexttypes)(legacy)를 지정한 경우에만 사용할 수 있습니다. -======= -- `nextProps`: The next props that the component is about to receive from its parent component. Compare `nextProps` to [`this.props`](#props) to determine what changed. -- `nextContext`: The next context that the component is about to receive from the closest provider. Compare `nextContext` to [`this.context`](#context) to determine what changed. Only available if you specify [`static contextType`](#static-contexttype). ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +- `nextContext`: 컴포넌트가 가장 가까운 공급자(provider)로부터 받으려는 다음 props입니다. `nextContext`를 [`this.context`](#context)와 비교하여 변경된 내용을 확인합니다. [`static contextType`](#static-contexttype)(modern)을 지정한 경우에만 사용할 수 있습니다. #### 반환값 {/*unsafe_componentwillreceiveprops-returns*/} @@ -899,33 +854,6 @@ React에 재렌더링을 건너뛸 수 있음을 알리려면 `false`를 반환 --- -<<<<<<< HEAD -### `static childContextTypes` {/*static-childcontexttypes*/} - -<Deprecated> - -이 API는 향후 React의 주요 버전에서 제거될 예정입니다. [대신 `static contextType`을 사용하세요.](#static-contexttype) - -</Deprecated> - -이 컴포넌트가 제공하는 [legacy context](https://ko.reactjs.org/docs/legacy-context.html)를 지정할 수 있습니다. - ---- - -### `static contextTypes` {/*static-contexttypes*/} - -<Deprecated> - -이 API는 향후 React의 주요 버전에서 제거될 예정입니다. [대신 `static contextType`을 사용하세요.](#static-contexttype) - -</Deprecated> - -이 컴포넌트가 사용할 [legacy context](https://ko.reactjs.org/docs/legacy-context.html)를 지정할 수 있습니다. - ---- - -======= ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc ### `static contextType` {/*static-contexttype*/} 클래스 컴포넌트에서 [`this.context`](#context-instance-field) 를 읽으려면 읽어야 하는 context를 지정해야 합니다. `static contextType`으로 지정하는 context는 이전에 [`createContext`](/reference/react/createContext)로 생성한 값이어야 합니다. @@ -1000,37 +928,6 @@ class Button extends Component { --- -<<<<<<< HEAD -### `static propTypes` {/*static-proptypes*/} - -[`prop-types`](https://www.npmjs.com/package/prop-types) 라이브러리와 함께 `static propTypes`를 정의하여 컴포넌트에서 허용되는 props의 유형을 선언할 수 있습니다. 이러한 유형은 렌더링 중과 개발 중에만 확인됩니다. - -```js -import PropTypes from 'prop-types'; - -class Greeting extends React.Component { - static propTypes = { - name: PropTypes.string - }; - - render() { - return ( - <h1>Hello, {this.props.name}</h1> - ); - } -} -``` - -<Note> - -런타임에 prop 타입을 확인하는 대신 [TypeScript](https://www.typescriptlang.org/ko/)를 사용하는 것을 추천합니다. - -</Note> - ---- - -======= ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc ### `static getDerivedStateFromError(error)` {/*static-getderivedstatefromerror*/} `static getDerivedStateFromError`를 정의하면 렌더링 도중 자식 컴포넌트(멀리 떨어진 자식 포함)가 에러를 throw 할 때 React가 이를 호출합니다. 이렇게 하면 UI를 지우는 대신 오류 메시지를 표시할 수 있습니다. From 59a0958c38b607196326e1bf56ea2de5c872b448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Wed, 1 Jan 2025 21:12:30 +0900 Subject: [PATCH 0479/1164] docs: resolve conflict in `createElement.md` --- src/content/reference/react/createElement.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/content/reference/react/createElement.md b/src/content/reference/react/createElement.md index 4e5531cc0..594101b1c 100644 --- a/src/content/reference/react/createElement.md +++ b/src/content/reference/react/createElement.md @@ -48,17 +48,10 @@ function Greeting({ name }) { `createElement`는 아래 프로퍼티를 가지는 React 엘리먼트 객체를 반환합니다. -<<<<<<< HEAD * `type`: 전달받은 `type`. -* `props`: `ref`와 `key`를 제외한 전달받은 `props`. `type`이 레거시 `type.defaultProps`를 가지는 컴포넌트라면, 누락되거나 정의되지 않은 `props`는 `type.defaultProps` 값을 가져옵니다. +* `props`: `ref`와 `key`를 제외한 전달받은 `props`. * `ref`: 전달받은 `ref`. 누락된 경우 `null`. * `key`: 전달받은 `key`를 강제 변환한 문자열. 누락된 경우 `null`. -======= -* `type`: The `type` you have passed. -* `props`: The `props` you have passed except for `ref` and `key`. -* `ref`: The `ref` you have passed. If missing, `null`. -* `key`: The `key` you have passed, coerced to a string. If missing, `null`. ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc 일반적으로 엘리먼트는 컴포넌트에서 반환되거나 다른 엘리먼트의 자식으로 만듭니다. 엘리먼트의 프로퍼티에는 접근할 수 있지만, 엘리먼트 생성 후에는 모든 엘리먼트에 접근할 수 없는 것처럼 대하고 렌더링만 하는 것이 좋습니다. From 44d14e019bedaf9c4c9ed20fb485c966d91e4176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Wed, 1 Jan 2025 21:14:19 +0900 Subject: [PATCH 0480/1164] docs: update `createRef.md` --- src/content/reference/react/createRef.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/createRef.md b/src/content/reference/react/createRef.md index 4821c862a..56b580caa 100644 --- a/src/content/reference/react/createRef.md +++ b/src/content/reference/react/createRef.md @@ -60,7 +60,7 @@ createRef`는 단일 속성을 가진 객체를 반환합니다. --- -## 사용 {/*usage*/} +## 사용법 {/*usage*/} ### 클래스 컴포넌트에서 ref 선언하기 {/*declaring-a-ref-in-a-class-component*/} From 9e1559b4ee40a26cb6d4f8db857633ee6343d25a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Wed, 1 Jan 2025 21:20:51 +0900 Subject: [PATCH 0481/1164] docs: update `forwardRef.md` --- src/content/reference/react/forwardRef.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/forwardRef.md b/src/content/reference/react/forwardRef.md index da74210a0..fc6fffa90 100644 --- a/src/content/reference/react/forwardRef.md +++ b/src/content/reference/react/forwardRef.md @@ -12,7 +12,7 @@ In React 19, `forwardRef` is no longer necessary. Pass `ref` as a prop instead. <Intro> -`forwardRef` 를 사용하면 컴포넌트가 [ref.](/learn/manipulating-the-dom-with-refs)를 사용하여 부모 컴포넌트의 DOM 노드를 노출할 수 있습니다. +`forwardRef`를 사용하면 컴포넌트가 [ref](/learn/manipulating-the-dom-with-refs)를 사용하여 부모 컴포넌트의 DOM 노드를 노출할 수 있습니다. ```js const SomeComponent = forwardRef(render) From 8a927c128f6ed030052c9bf76025d7bd10c75c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Wed, 1 Jan 2025 21:39:35 +0900 Subject: [PATCH 0482/1164] refactor: translate `<RSC>` callout component --- src/components/MDX/ExpandableCallout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MDX/ExpandableCallout.tsx b/src/components/MDX/ExpandableCallout.tsx index b4239fbb5..dd7199d15 100644 --- a/src/components/MDX/ExpandableCallout.tsx +++ b/src/components/MDX/ExpandableCallout.tsx @@ -76,7 +76,7 @@ const variantMap = { 'linear-gradient(rgba(249, 247, 243, 0), rgba(249, 247, 243, 1)', }, rsc: { - title: 'React Server Components', + title: 'React 서버 컴포넌트', Icon: null, containerClasses: 'bg-blue-10 dark:bg-blue-60 dark:bg-opacity-20', textColor: 'text-blue-50 dark:text-blue-40', From 4a8c0ad915892f2a21da4ea2557a203989831fec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Thu, 2 Jan 2025 00:46:13 +0900 Subject: [PATCH 0483/1164] docs: update `server-components.md` --- .../reference/rsc/server-components.md | 39 +++++++------------ 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/src/content/reference/rsc/server-components.md b/src/content/reference/rsc/server-components.md index ab92d673e..c152b8427 100644 --- a/src/content/reference/rsc/server-components.md +++ b/src/content/reference/rsc/server-components.md @@ -1,10 +1,5 @@ --- -<<<<<<< HEAD -title: React 서버 컴포넌트 -canary: true -======= -title: Server Components ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +title: 서버 컴포넌트 --- <RSC> @@ -27,20 +22,16 @@ Server Components are for use in [React Server Components](/learn/start-a-new-re #### 서버 컴포넌트를 지원하려면 어떻게 해야 하나요? {/*how-do-i-build-support-for-server-components*/} -<<<<<<< HEAD -React 19의 서버 컴포넌트는 안정적이며 메이저(Major) 버전 간에는 변경되지 않습니다. 그러나 React 서버 컴포넌트 번들러나 프레임워크를 구현하는 데 사용되는 기본 API는 시맨틱 버전(semver)을 따르지 않으며 React 19.x의 마이너(Minor) 버전 간에 변경될 수 있습니다. -======= -While React Server Components in React 19 are stable and will not break between minor versions, the underlying APIs used to implement a React Server Components bundler or framework do not follow semver and may break between minors in React 19.x. ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +React 19의 서버 컴포넌트는 안정적이며 마이너(Minor) 버전 간에는 변경되지 않습니다. 그러나 React 서버 컴포넌트 번들러나 프레임워크를 구현하는 데 사용되는 기본 API는 시맨틱 버전(semver)을 따르지 않으며 React 19.x의 마이너(Minor) 버전 간에 변경될 수 있습니다. React 서버 컴포넌트를 번들러나 프레임워크로 지원하려면, 특정 React 버전에 고정하거나 Canary 릴리즈를 사용하는 것을 권장합니다. 향후 React 서버 컴포넌트를 구현하는 데 사용되는 API를 안정화하기 위해 번들러 및 프레임워크와 계속 협력할 것입니다. </Note> ### 서버 없이 서버 컴포넌트 사용하기 {/*server-components-without-a-server*/} -서버 컴포넌트는 빌드 시간에 파일 시스템에서 읽거나 정적 콘텐츠를 가져올 수 있으므로 웹 서버가 필요하지 않습니다. 예를 들어, 콘텐츠 관리 시스템(CMS)에서 정적 데이터를 읽고 싶을 때 유용합니다. +서버 컴포넌트는 빌드 시간에 파일 시스템을 읽거나 정적 콘텐츠를 가져올 수 있으므로 웹 서버가 필요하지 않습니다. 예를 들어, 콘텐츠 관리 시스템<sup>CMS</sup>에서 정적 데이터를 읽고 싶을 때 유용합니다. -서버 컴포넌트 없이 클라이언트에서 정적 데이터를 가져오는 일반적인 패턴은 다음과 같습니다. +서버 컴포넌트 없이 클라이언트에서 Effect를 사용해 정적 데이터를 가져오는 일반적인 패턴은 다음과 같습니다. ```js // bundle.js import marked from 'marked'; // 35.9K (11.2K gzipped) @@ -67,7 +58,7 @@ app.get(`/api/content/:page`, async (req, res) => { }); ``` -이 패턴은 사용자가 정적 콘텐츠를 렌더링하기 위해 페이지가 로드된 후 추가 75K (gzipped) 라이브러리를 다운로드하고 파싱해야 하며, 데이터를 가져오기 위해 두 번째 요청을 기다려야 합니다. +이 패턴은 사용자가 정적 콘텐츠를 렌더링하기 위해 페이지가 로드된 후 추가 75K (gzipped) 라이브러리를 다운로드하고 파싱해야 하며, 데이터를 가져오기 위한 두 번째 요청을 기다려야 합니다. 서버 컴포넌트를 사용하면 이러한 컴포넌트를 빌드 시간에 한 번만 렌더링할 수 있습니다. @@ -83,7 +74,7 @@ async function Page({page}) { } ``` -렌더링된 출력은 서버 측 렌더링(SSR)을 통해 HTML로 변환되어 CDN에 업로드될 수 있습니다. 앱이 로드될 때, 클라이언트는 기존의 `Page` 컴포넌트나 마크다운 렌더링을 위한 고비용의 라이브러리를 보지 않게 됩니다. 클라이언트는 렌더링된 출력만 보게 됩니다. +렌더링된 출력은 서버 측 렌더링<sup>SSR</sup>을 통해 HTML로 변환되어 CDN에 업로드될 수 있습니다. 앱이 로드될 때, 클라이언트는 기존의 `Page` 컴포넌트나 마크다운 렌더링을 위한 고비용의 라이브러리를 보지 않게 됩니다. 클라이언트는 렌더링된 출력만 보게 됩니다. ```js <div><!-- html for markdown --></div> @@ -108,9 +99,9 @@ async function Page({page}) { </Note> ### 서버와 함께 서버 컴포넌트 사용하기 {/*server-components-with-a-server*/} -서버 컴포넌트는 웹 서버에서 페이지 요청 시 실행될 수도 있어, API를 구축할 필요 없이 데이터 레이어에 접근할 수 있게 해줍니다. 이들은 애플리케이션이 번들링되기 전에 렌더링되며, 데이터와 JSX를 클라이언트 컴포넌트에 props로 전달할 수 있습니다. +서버 컴포넌트는 웹 서버에서 페이지 요청 시 실행될 수 있어, API를 구축할 필요 없이 데이터 레이어에 접근할 수 있습니다. 이들은 애플리케이션이 번들링되기 전에 렌더링되며, 데이터와 JSX를 클라이언트 컴포넌트에 Props로 전달할 수 있습니다. -서버 컴포넌트 없이 클라이언트에서 동적 데이터를 가져오는 일반적인 패턴은 다음과 같습니다. +서버 컴포넌트 없이 클라이언트에서 Effect를 사용해 동적 데이터를 가져오는 일반적인 패턴은 다음과 같습니다. ```js // bundle.js @@ -192,7 +183,7 @@ async function Author({id}) { </div> ``` -서버 컴포넌트는 서버에서 다시 페칭함으로써 데이터에 액세스하고 다시 렌더링하여 동적으로 만들 수 있습니다. 이 새로운 애플리케이션 아키텍처는 서버 중심의 다중 페이지 앱(Server-Centric Multi-Page Apps)의 간단한 "request/response" 모델과 클라이언트 중심의 단일 페이지 앱(Client-Centric Single-Page Apps)의 원활한 상호작용을 결합하여 두 가지의 장점을 모두 제공합니다. +서버 컴포넌트는 서버에서 다시 페칭함으로써 데이터에 액세스하고 다시 렌더링하여 동적으로 만들 수 있습니다. 이 새로운 애플리케이션 아키텍처는 서버 중심의 다중 페이지 앱(Server-Centric Multi-Page Apps)의 간단한 "request/response" 모델과 클라이언트 중심의 단일 페이지 앱(Client-Centric Single-Page Apps)의 원활한 상호작용을 결합하여 두 가지 장점을 모두 제공합니다. ### 서버 컴포넌트에 상호작용 추가하기 {/*adding-interactivity-to-server-components*/} @@ -202,18 +193,14 @@ async function Author({id}) { #### 서버 컴포넌트에 대한 지시어는 없습니다. {/*there-is-no-directive-for-server-components*/} -<<<<<<< HEAD -서버 컴포넌트는 `"use server"`로 표시된다는 오해가 있지만, 서버 컴포넌트에 대한 지시어는 없습니다. `"use server"` 지시어는 서버 액션에 사용됩니다. -======= -A common misunderstanding is that Server Components are denoted by `"use server"`, but there is no directive for Server Components. The `"use server"` directive is used for Server Functions. ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +서버 컴포넌트는 `"use server"`로 표시된다는 오해가 있지만, 서버 컴포넌트에 대한 지시어는 없습니다. `"use server"` 지시어는 서버 함수에 사용됩니다. 자세한 내용은 [지시어](/reference/rsc/directives)를 참조하세요. </Note> -다음 예시에서는 `Notes` 서버 컴포넌트가 상태를 사용하여 `expanded` 상태를 토글하는 `Expandable` 클라이언트 컴포넌트를 가져옵니다. +다음 예시에서는 `Notes` 서버 컴포넌트가 State를 사용하여 `expanded` 상태를 토글하는 `Expandable` 클라이언트 컴포넌트를 가져옵니다. ```js // Server Component import Expandable from './Expandable'; @@ -250,7 +237,7 @@ export default function Expandable({children}) { } ``` -이 예시는 먼저 `Notes`를 서버 컴포넌트로 렌더링한 다음 번들러에 `Expandable` 클라이언트 컴포넌트의 번들을 생성하도록 지시합니다. 브라우저에서는 클라이언트 컴포넌트가 서버 컴포넌트의 출력을 props로 받게 됩니다. +이 예시는 먼저 `Notes`를 서버 컴포넌트로 렌더링한 다음 번들러에 `Expandable` 클라이언트 컴포넌트의 번들을 생성하도록 지시합니다. 브라우저에서는 클라이언트 컴포넌트가 서버 컴포넌트의 출력을 Props로 받게 됩니다. ```js <head> @@ -272,7 +259,7 @@ export default function Expandable({children}) { ### 서버 컴포넌트와 함께 비동기 컴포넌트 사용하기 {/*async-components-with-server-components*/} -서버 컴포넌트는 `async`와 `await`을 사용하는 새로운 방법을 소개합니다. 비동기 컴포넌트에서 `await`을 사용할 때, React는 렌더링을 지연(Suspend)하고 Promise가 해결될 때까지 기다린 후 렌더링을 다시 시작합니다. 이는 서버와 클라이언트의 경계를 넘어 동작하며, Suspense에 대한 스트리밍을 지원합니다. +서버 컴포넌트는 `async`와 `await`을 사용하는 새로운 방법을 소개합니다. 비동기 컴포넌트에서 `await`을 사용할 때, React는 렌더링을 지연<sup>Suspend</sup>하고 Promise가 해결될 때까지 기다린 후 렌더링을 다시 시작합니다. 이는 서버와 클라이언트의 경계를 넘어 동작하며, Suspense에 대한 스트리밍을 지원합니다. 심지어 서버에서 Promise를 생성하고 클라이언트에서 이를 기다릴 수 있습니다. From e27c132ebee1a7f82197dba1f1f7aa84b67e849b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Thu, 2 Jan 2025 01:44:02 +0900 Subject: [PATCH 0484/1164] docs: update `server-functions.md` --- src/content/reference/rsc/server-actions.md | 212 ------------------ src/content/reference/rsc/server-functions.md | 83 +++---- src/sidebarHome.json | 6 +- src/sidebarReference.json | 10 +- 4 files changed, 50 insertions(+), 261 deletions(-) delete mode 100644 src/content/reference/rsc/server-actions.md diff --git a/src/content/reference/rsc/server-actions.md b/src/content/reference/rsc/server-actions.md deleted file mode 100644 index b8914e705..000000000 --- a/src/content/reference/rsc/server-actions.md +++ /dev/null @@ -1,212 +0,0 @@ ---- -title: 서버 액션 -canary: true ---- - -<Intro> - -서버 액션(Server Action)을 사용하면 클라이언트 컴포넌트가 서버에서 실행되는 비동기 함수를 호출할 수 있습니다. - -</Intro> - -<InlineToc /> - -<Note> - -#### 서버 액션을 지원하려면 어떻게 해야 하나요? {/*how-do-i-build-support-for-server-actions*/} - -React 19의 서버 액션은 안정적이며 메이저(Major) 버전 간에는 변경되지 않습니다. 그러나 React 서버 컴포넌트 번들러나 프레임워크에서 서버 액션을 구현하는 데 사용되는 기본 API는 시맨틱 버전(semver)을 따르지 않으며 React 19.x의 마이너(Minor) 버전 간에 변경될 수 있습니다. - -서버 액션을 번들러나 프레임워크로 지원하려면, 특정 React 버전에 고정하거나 Canary 릴리즈를 사용하는 것을 권장합니다. 향후 서버 액션을 구현하는 데 사용되는 API를 안정화하기 위해 번들러 및 프레임워크와 계속 협력할 것입니다. - -</Note> - -서버 액션이 `"use server"` 지시어로 정의되면, 프레임워크는 자동으로 서버 함수에 대한 참조를 생성하고 해당 참조를 클라이언트 컴포넌트에 전달합니다. 클라이언트에서 해당 함수가 호출되면, React는 서버에 함수를 실행하라는 요청(Request)을 보내고 결과를 반환합니다. - -서버 액션은 서버 컴포넌트에서 생성하여 클라이언트 컴포넌트에 props로 전달할 수 있으며, 클라이언트 컴포넌트에서 가져와서 사용할 수도 있습니다. - -### 서버 컴포넌트에서 서버 액션 만들기 {/*creating-a-server-action-from-a-server-component*/} - -서버 컴포넌트는 `"use server"` 지시어로 서버 액션을 정의할 수 있습니다. - -```js [[2, 7, "'use server'"], [1, 5, "createNoteAction"], [1, 12, "createNoteAction"]] -// Server Component -import Button from './Button'; - -function EmptyNote () { - async function createNoteAction() { - // Server Action - 'use server'; - - await db.notes.create(); - } - - return <Button onClick={createNoteAction}/>; -} -``` - -React가 `EmptyNote` 서버 컴포넌트를 렌더링할 때, `createNoteAction` 함수에 대한 참조를 생성하고, 그 참조를 `Button` 클라이언트 컴포넌트에 전달합니다. 버튼을 클릭하면, React는 제공된 참조를 통해 `createNoteAction` 함수를 실행하도록 서버에 요청(Request)을 보냅니다. - -```js {5} -"use client"; - -export default function Button({onClick}) { - console.log(onClick); - // {$$typeof: Symbol.for("react.server.reference"), $$id: 'createNoteAction'} - return <button onClick={() => onClick()}>Create Empty Note</button> -} -``` - -자세한 내용은 [`"use server"`](/reference/rsc/use-server) 문서를 참조하세요. - -### 클라이언트 컴포넌트에서 서버 액션 가져오기 {/*importing-server-actions-from-client-components*/} - -클라이언트 컴포넌트는 `"use server"` 지시어를 사용하는 파일에서 서버 액션을 가져올 수 있습니다. - -```js [[1, 3, "createNoteAction"]] -"use server"; - -export async function createNoteAction() { - await db.notes.create(); -} - -``` - -번들러가 `EmptyNote` 클라이언트 컴포넌트를 빌드할 때, 번들에서 `createNoteAction` 함수에 대한 참조를 생성합니다. 버튼을 클릭하면, React는 제공된 참조를 통해 `createNoteAction` 함수를 실행하도록 서버에 요청(Request)을 보냅니다. - -```js [[1, 2, "createNoteAction"], [1, 5, "createNoteAction"], [1, 7, "createNoteAction"]] -"use client"; -import {createNoteAction} from './actions'; - -function EmptyNote() { - console.log(createNoteAction); - // {$$typeof: Symbol.for("react.server.reference"), $$id: 'createNoteAction'} - return <button onClick={createNoteAction} /> -} -``` - -자세한 내용은 [`"use server"`](/reference/rsc/use-server) 문서를 참조하세요. - -### 액션으로 서버 액션 구성하기 {/*composing-server-actions-with-actions*/} - -서버 액션은 클라이언트의 액션(Action)과 함께 구성할 수 있습니다. - -```js [[1, 3, "updateName"]] -"use server"; - -export async function updateName(name) { - if (!name) { - return {error: 'Name is required'}; - } - await db.users.updateName(name); -} -``` - -```js [[1, 3, "updateName"], [1, 13, "updateName"], [2, 11, "submitAction"], [2, 23, "submitAction"]] -"use client"; - -import {updateName} from './actions'; - -function UpdateName() { - const [name, setName] = useState(''); - const [error, setError] = useState(null); - - const [isPending, startTransition] = useTransition(); - - const submitAction = async () => { - startTransition(async () => { - const {error} = await updateName(name); - if (!error) { - setError(error); - } else { - setName(''); - } - }) - } - - return ( - <form action={submitAction}> - <input type="text" name="name" disabled={isPending}/> - {state.error && <span>Failed: {state.error}</span>} - </form> - ) -} -``` - -이렇게 하면 클라이언트의 액션으로 래핑하여 서버 액션의 `isPending` 상태에 접근할 수 있습니다. - -자세한 내용은 [`<form>` 외부에서 서버 액션 호출하기](/reference/rsc/use-server#calling-a-server-action-outside-of-form) 문서를 참조하세요. - -### 서버 액션을 사용한 폼 액션 {/*form-actions-with-server-actions*/} - -서버 액션은 React 19의 새로운 폼(Form) 기능과 함께 동작합니다. - -서버 액션을 폼에 전달하여 폼을 서버에 자동으로 제출할 수 있습니다. - - -```js [[1, 3, "updateName"], [1, 7, "updateName"]] -"use client"; - -import {updateName} from './actions'; - -function UpdateName() { - return ( - <form action={updateName}> - <input type="text" name="name" /> - </form> - ) -} -``` - -폼 제출이 성공하면, React는 자동으로 폼을 재설정합니다. `useActionState`를 추가하여 대기(Pending) 상태 혹은 마지막 응답(Response)에 접근하거나, 점진적 향상을 지원할 수 있습니다. - -자세한 내용은 [서버 액션 형식](/reference/rsc/use-server#server-actions-in-forms) 문서를 참조하세요. - -### `useActionState`를 사용한 서버 액션 {/*server-actions-with-use-action-state*/} - -액션 대기(Pending) 상태와 마지막으로 반환된 응답(Response)에 접근하는 일반적인 경우에는 `useActionState`를 사용하여 서버 액션을 구성할 수 있습니다. - -```js [[1, 3, "updateName"], [1, 6, "updateName"], [2, 6, "submitAction"], [2, 9, "submitAction"]] -"use client"; - -import {updateName} from './actions'; - -function UpdateName() { - const [state, submitAction, isPending] = useActionState(updateName, {error: null}); - - return ( - <form action={submitAction}> - <input type="text" name="name" disabled={isPending}/> - {state.error && <span>Failed: {state.error}</span>} - </form> - ); -} -``` - -서버 액션과 함께 `useActionState`를 사용하는 경우, React는 Hydration이 완료되기 전에 입력된 폼 제출을 자동으로 다시 실행합니다. 즉, 사용자는 앱이 Hydration 되기 전에도 앱과 상호작용을 할 수 있습니다. - -자세한 내용은 [`useActionState`](/reference/react/useActionState) 문서를 참조하세요. - -### `useActionState`를 통한 점진적 향상 {/*progressive-enhancement-with-useactionstate*/} - -서버 액션은 `useActionState`의 세 번째 인수를 통한 점진적 향상도 지원합니다. - -```js [[1, 3, "updateName"], [1, 6, "updateName"], [2, 6, "/name/update"], [3, 6, "submitAction"], [3, 9, "submitAction"]] -"use client"; - -import {updateName} from './actions'; - -function UpdateName() { - const [, submitAction] = useActionState(updateName, null, `/name/update`); - - return ( - <form action={submitAction}> - ... - </form> - ); -} -``` - -<CodeStep step={2}>permalink</CodeStep>가 `useActionState`에 제공될 때, 자바스크립트 번들이 로드되기 전에 폼이 제출되면 React는 제공된 URL로 리디렉션합니다. - -자세한 내용은 [`useActionState`](/reference/react/useActionState) 문서를 참조하세요. diff --git a/src/content/reference/rsc/server-functions.md b/src/content/reference/rsc/server-functions.md index 74aab615c..3d4e22fe0 100644 --- a/src/content/reference/rsc/server-functions.md +++ b/src/content/reference/rsc/server-functions.md @@ -1,5 +1,5 @@ --- -title: Server Functions +title: 서버 함수 --- <RSC> @@ -12,7 +12,7 @@ Server Functions are for use in [React Server Components](/learn/start-a-new-rea <Intro> -Server Functions allow Client Components to call async functions executed on the server. +서버 함수<sup>Server Functions</sup>를 사용하면 클라이언트 컴포넌트가 서버에서 실행되는 비동기 함수를 호출할 수 있습니다. </Intro> @@ -20,58 +20,58 @@ Server Functions allow Client Components to call async functions executed on the <Note> -#### How do I build support for Server Functions? {/*how-do-i-build-support-for-server-functions*/} +#### 서버 함수를 지원하려면 어떻게 해야 하나요? {/*how-do-i-build-support-for-server-functions*/} -While Server Functions in React 19 are stable and will not break between minor versions, the underlying APIs used to implement Server Functions in a React Server Components bundler or framework do not follow semver and may break between minors in React 19.x. +React 19의 서버 함수는 안정적이며 마이너<sup>Minor</sup> 버전 간에는 변경되지 않습니다. 그러나 React 서버 컴포넌트 번들러나 프레임워크에서 서버 함수를 구현하는 데 사용되는 기본 API는 시맨틱 버전(semver)을 따르지 않으며 React 19.x의 마이너<sup>Minor</sup> 버전 간에 변경될 수 있습니다. -To support Server Functions as a bundler or framework, we recommend pinning to a specific React version, or using the Canary release. We will continue working with bundlers and frameworks to stabilize the APIs used to implement Server Functions in the future. +서버 함수를 번들러나 프레임워크로 지원하려면, 특정 React 버전에 고정하거나 Canary 릴리즈를 사용하는 것을 권장합니다. 향후 서버 함수를 구현하는 데 사용되는 API를 안정화하기 위해 번들러 및 프레임워크와 계속 협력할 것입니다. </Note> -When a Server Functions is defined with the [`"use server"`](/reference/rsc/use-server) directive, your framework will automatically create a reference to the server function, and pass that reference to the Client Component. When that function is called on the client, React will send a request to the server to execute the function, and return the result. +서버 함수가 [`"use server"`](/reference/rsc/use-server) 지시어로 정의되면, 프레임워크는 자동으로 서버 함수에 대한 참조를 생성하고 해당 참조를 클라이언트 컴포넌트에 전달합니다. 클라이언트에서 해당 함수가 호출되면, React는 서버에 함수를 실행하라는 요청<sup>Request</sup>을 보내고 결과를 반환합니다. -Server Functions can be created in Server Components and passed as props to Client Components, or they can be imported and used in Client Components. +서버 함수는 서버 컴포넌트에서 생성하여 클라이언트 컴포넌트에 Props로 전달할 수 있으며, 클라이언트 컴포넌트에서 가져와서 사용할 수도 있습니다. -## Usage {/*usage*/} +## 사용법 {/*usage*/} -### Creating a Server Function from a Server Component {/*creating-a-server-function-from-a-server-component*/} +### 서버 컴포넌트에서 서버 함수 만들기 {/*creating-a-server-function-from-a-server-component*/} -Server Components can define Server Functions with the `"use server"` directive: +서버 컴포넌트는 `"use server"` 지시어로 서버 함수를 정의할 수 있습니다. -```js [[2, 7, "'use server'"], [1, 5, "createNoteAction"], [1, 12, "createNoteAction"]] +```js [[2, 7, "'use server'"], [1, 5, "createNote"], [1, 12, "createNote"]] // Server Component import Button from './Button'; function EmptyNote () { - async function createNoteAction() { + async function createNote() { // Server Function 'use server'; - + await db.notes.create(); } - return <Button onClick={createNoteAction}/>; + return <Button onClick={createNote}/>; } ``` -When React renders the `EmptyNote` Server Function, it will create a reference to the `createNoteAction` function, and pass that reference to the `Button` Client Component. When the button is clicked, React will send a request to the server to execute the `createNoteAction` function with the reference provided: +React가 `EmptyNote` 서버 컴포넌트를 렌더링할 때, `createNote` 함수에 대한 참조를 생성하고, 그 참조를 `Button` 클라이언트 컴포넌트에 전달합니다. 버튼을 클릭하면, React는 제공된 참조를 통해 `createNote` 함수를 실행하도록 서버에 요청<sup>Request</sup>을 보냅니다. ```js {5} "use client"; -export default function Button({onClick}) { - console.log(onClick); +export default function Button({onClick}) { + console.log(onClick); // {$$typeof: Symbol.for("react.server.reference"), $$id: 'createNoteAction'} return <button onClick={() => onClick()}>Create Empty Note</button> } ``` -For more, see the docs for [`"use server"`](/reference/rsc/use-server). +자세한 내용은 [`"use server"`](/reference/rsc/use-server) 문서를 참조하세요. -### Importing Server Functions from Client Components {/*importing-server-functions-from-client-components*/} +### 클라이언트 컴포넌트에서 서버 함수 가져오기 {/*importing-server-functions-from-client-components*/} -Client Components can import Server Functions from files that use the `"use server"` directive: +클라이언트 컴포넌트는 `"use server"` 지시어를 사용하는 파일에서 서버 함수를 가져올 수 있습니다. ```js [[1, 3, "createNote"]] "use server"; @@ -82,10 +82,11 @@ export async function createNote() { ``` -When the bundler builds the `EmptyNote` Client Component, it will create a reference to the `createNoteAction` function in the bundle. When the `button` is clicked, React will send a request to the server to execute the `createNoteAction` function using the reference provided: +번들러가 `EmptyNote` 클라이언트 컴포넌트를 빌드할 때, 번들에서 `createNote` 함수에 대한 참조를 생성합니다. 버튼을 클릭하면, React는 제공된 참조를 통해 `createNote` 함수를 실행하도록 서버에 요청<sup>Request</sup>을 보냅니다. -```js [[1, 2, "createNote"], [1, 5, "createNote"], [1, 7, "createNote"]] +```js [[1, 3, "createNote"], [1, 6, "createNote"], [1, 8, "createNote"]] "use client"; + import {createNote} from './actions'; function EmptyNote() { @@ -95,11 +96,11 @@ function EmptyNote() { } ``` -For more, see the docs for [`"use server"`](/reference/rsc/use-server). +자세한 내용은 [`"use server"`](/reference/rsc/use-server) 문서를 참조하세요. -### Server Functions with Actions {/*server-functions-with-actions*/} +### 액션으로 서버 함수 구성하기 {/*server-functions-with-actions*/} -Server Functions can be called from Actions on the client: +서버 함수는 클라이언트의 액션<sup>Action</sup>과 함께 구성할 수 있습니다. ```js [[1, 3, "updateName"]] "use server"; @@ -133,7 +134,7 @@ function UpdateName() { } }) } - + return ( <form action={submitAction}> <input type="text" name="name" disabled={isPending}/> @@ -143,15 +144,15 @@ function UpdateName() { } ``` -This allows you to access the `isPending` state of the Server Function by wrapping it in an Action on the client. +이렇게 하면 클라이언트의 액션으로 래핑하여 서버 함수의 `isPending` 상태에 접근할 수 있습니다. -For more, see the docs for [Calling a Server Function outside of `<form>`](/reference/rsc/use-server#calling-a-server-function-outside-of-form) +자세한 내용은 [`<form>` 외부에서 서버 함수 호출하기](/reference/rsc/use-server#calling-a-server-action-outside-of-form) 문서를 참조하세요. -### Server Functions with Form Actions {/*using-server-functions-with-form-actions*/} +### 서버 함수를 사용한 폼 액션 {/*using-server-functions-with-form-actions*/} -Server Functions work with the new Form features in React 19. +서버 함수는 React 19의 새로운 폼<sup>Form</sup> 기능과 함께 동작합니다. -You can pass a Server Function to a Form to automatically submit the form to the server: +서버 함수를 폼에 전달하여 폼을 서버에 자동으로 제출할 수 있습니다. ```js [[1, 3, "updateName"], [1, 7, "updateName"]] @@ -168,13 +169,13 @@ function UpdateName() { } ``` -When the Form submission succeeds, React will automatically reset the form. You can add `useActionState` to access the pending state, last response, or to support progressive enhancement. +폼 제출이 성공하면, React는 자동으로 폼을 재설정합니다. `useActionState`를 추가하여 대기<sup>Pending</sup> 상태 혹은 마지막 응답<sup>Response</sup>에 접근하거나, 점진적 향상을 지원할 수 있습니다. -For more, see the docs for [Server Functions in Forms](/reference/rsc/use-server#server-functions-in-forms). +자세한 내용은 [폼<sup>Form</sup>에서의 서버 함수](/reference/rsc/use-server#server-functions-in-forms) 문서를 참조하세요. -### Server Functions with `useActionState` {/*server-functions-with-use-action-state*/} +### `useActionState`를 사용한 서버 함수 {/*server-functions-with-use-action-state*/} -You can call Server Functions with `useActionState` for the common case where you just need access to the action pending state and last returned response: +액션 대기<sup>Pending</sup> 상태와 마지막으로 반환된 응답<sup>Response</sup>에 접근하는 일반적인 경우에는 `useActionState`를 사용하여 서버 함수를 호출할 수 있습니다. ```js [[1, 3, "updateName"], [1, 6, "updateName"], [2, 6, "submitAction"], [2, 9, "submitAction"]] "use client"; @@ -193,13 +194,13 @@ function UpdateName() { } ``` -When using `useActionState` with Server Functions, React will also automatically replay form submissions entered before hydration finishes. This means users can interact with your app even before the app has hydrated. +서버 함수 함께 `useActionState`를 사용하는 경우, React는 Hydration이 완료되기 전에 입력된 폼 제출을 자동으로 다시 실행합니다. 즉, 사용자는 앱이 Hydration 되기 전에도 앱과 상호작용을 할 수 있습니다. -For more, see the docs for [`useActionState`](/reference/react-dom/hooks/useFormState). +자세한 내용은 [`useActionState`](/reference/react/useActionState) 문서를 참조하세요. -### Progressive enhancement with `useActionState` {/*progressive-enhancement-with-useactionstate*/} +### `useActionState`를 통한 점진적 향상 {/*progressive-enhancement-with-useactionstate*/} -Server Functions also support progressive enhancement with the third argument of `useActionState`. +서버 함수는 `useActionState`의 세 번째 인수를 통한 점진적 향상도 지원합니다. ```js [[1, 3, "updateName"], [1, 6, "updateName"], [2, 6, "/name/update"], [3, 6, "submitAction"], [3, 9, "submitAction"]] "use client"; @@ -217,6 +218,6 @@ function UpdateName() { } ``` -When the <CodeStep step={2}>permalink</CodeStep> is provided to `useActionState`, React will redirect to the provided URL if the form is submitted before the JavaScript bundle loads. +<CodeStep step={2}>permalink</CodeStep>가 `useActionState`에 제공될 때, 자바스크립트 번들이 로드되기 전에 폼이 제출되면 React는 제공된 URL로 리디렉션합니다. -For more, see the docs for [`useActionState`](/reference/react-dom/hooks/useFormState). +자세한 내용은 [`useActionState`](/reference/react/useActionState) 문서를 참조하세요. diff --git a/src/sidebarHome.json b/src/sidebarHome.json index fee1a73d9..e986ce6e8 100644 --- a/src/sidebarHome.json +++ b/src/sidebarHome.json @@ -23,11 +23,11 @@ "path": "/learn/describing-the-ui" }, { - "title": "상호작용성 더하기", + "title": "상호작용 추가하기", "path": "/learn/adding-interactivity" }, { - "title": "State 다루기", + "title": "State 관리하기", "path": "/learn/managing-state" }, { @@ -39,7 +39,7 @@ "sectionHeader": "REACT API" }, { - "title": "훅", + "title": "Hook", "path": "/reference/react" }, { diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 2e9dfe1eb..d97cbc749 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -11,7 +11,7 @@ "path": "/reference/react" }, { - "title": "Hooks", + "title": "Hook", "path": "/reference/react/hooks", "routes": [ { @@ -155,7 +155,7 @@ "sectionHeader": "react-dom@{{version}}" }, { - "title": "Hooks", + "title": "Hook", "path": "/reference/react-dom/hooks", "routes": [ { @@ -293,7 +293,7 @@ ] }, { - "title": "Static APIs", + "title": "정적 API", "path": "/reference/react-dom/static", "routes": [ { @@ -337,8 +337,8 @@ "path": "/reference/rsc/server-components" }, { - "title": "서버 액션", - "path": "/reference/rsc/server-actions" + "title": "서버 함수", + "path": "/reference/rsc/server-functions" }, { "title": "지시어", From 44b4a7f10dab56a538cc33da662123379a4427d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Thu, 2 Jan 2025 01:46:47 +0900 Subject: [PATCH 0485/1164] docs: resolve conflict in `directives.md` --- src/content/reference/rsc/directives.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/content/reference/rsc/directives.md b/src/content/reference/rsc/directives.md index a5f4256a3..9fb85de18 100644 --- a/src/content/reference/rsc/directives.md +++ b/src/content/reference/rsc/directives.md @@ -1,19 +1,10 @@ --- -<<<<<<< HEAD title: "지시어" -canary: true -======= -title: Directives ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc --- <RSC> -<<<<<<< HEAD -이 지시어는 [React 서버 컴포넌트를 사용하거나](/learn/start-a-new-react-project#bleeding-edge-react-frameworks) 이와 호환되는 라이브러리를 빌드하는 경우에만 필요합니다. -======= Directives are for use in [React Server Components](/learn/start-a-new-react-project#bleeding-edge-react-frameworks). ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc </RSC> From afd8b82f9fb6bccd660d1ec756044deb038325ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Thu, 2 Jan 2025 21:04:16 +0900 Subject: [PATCH 0486/1164] docs: update `use-client.md` --- src/content/reference/rsc/use-client.md | 95 ++++++++----------------- 1 file changed, 31 insertions(+), 64 deletions(-) diff --git a/src/content/reference/rsc/use-client.md b/src/content/reference/rsc/use-client.md index 75c19d276..448860414 100644 --- a/src/content/reference/rsc/use-client.md +++ b/src/content/reference/rsc/use-client.md @@ -1,23 +1,13 @@ --- title: "'use client'" -<<<<<<< HEAD titleForTitleTag: "'use client' 지시어" -canary: true -======= -titleForTitleTag: "'use client' directive" ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc --- <RSC> -<<<<<<< HEAD -`'use client'`는 [React 서버 컴포넌트를 사용](/learn/start-a-new-react-project#bleeding-edge-react-frameworks)하거나 그와 호환되는 라이브러리를 만들 때만 사용합니다. -</Canary> -======= `'use client'` is for use with [React Server Components](/learn/start-a-new-react-project#bleeding-edge-react-frameworks). </RSC> ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc <Intro> @@ -51,13 +41,13 @@ export default function RichTextEditor({ timestamp, text }) { } ``` -서버 컴포넌트에서 `'use client'`라고 표시된 파일을 가져오면 [호환되는 번들러](/learn/start-a-new-react-project#bleeding-edge-react-frameworks)는 import를 서버 실행 코드와 클라이언트 실행 코드 사이의 경계로 처리합니다. +서버 컴포넌트에서 `'use client'`라 표시된 파일을 가져오면 [호환되는 번들러](/learn/start-a-new-react-project#bleeding-edge-react-frameworks)는 모듈 불러오기<sup>Module Import</sup>를 서버 실행 코드와 클라이언트 실행 코드 사이의 경계로 처리합니다. -`RichTextEditor`의 의존성으로 `formatDate`와 `Button`도 해당 모듈에 `'use client'` 지시어가 포함되어 있지 않더라도 클라이언트에서 평가됩니다. 하나의 모듈이 서버 코드에서 가져올 때는 서버에서, 클라이언트 코드에서 가져올 때는 클라이언트에서 평가될 수 있음을 유의해야 합니다. +`RichTextEditor`의 의존성으로 인하여, `formatDate`와 `Button`의 모듈에 `'use client'` 지시어가 포함되어 있지 않더라도 클라이언트에서 평가됩니다. 하나의 모듈이 서버 코드에서 가져올 때는 서버에서, 클라이언트 코드에서 가져올 때는 클라이언트에서 평가될 수 있음을 유의해야 합니다. #### 주의 사항 {/*caveats*/} -* `'use client'`는 파일의 맨 처음에 있어야 하며, 다른 코드나 import 문보다 위에 있어야 합니다(주석은 괜찮습니다). 작은따옴표나 큰따옴표로 작성해야 하며 백틱은 사용할 수 없습니다. +* `'use client'`는 파일의 맨 처음에 있어야 하며, 다른 코드나 import 문보다 위에 있어야 합니다. (주석은 괜찮습니다.) 작은따옴표나 큰따옴표로 작성해야 하며 백틱은 사용할 수 없습니다. * `'use client'` 모듈을 다른 클라이언트 렌더링 모듈에서 가져오면 지시어가 동작하지 않습니다. * 컴포넌트 모듈에 `'use client'` 지시어가 포함된 경우 해당 컴포넌트의 사용은 클라이언트 컴포넌트임이 보장됩니다. 하지만 컴포넌트에 `'use client'` 지시어가 없더라도 클라이언트에서 평가될 수 있습니다. * 컴포넌트 사용은 `'use client'` 지시어가 포함된 모듈에 정의되어 있거나 `'use client'` 지시어를 포함한 모듈의 전이적 의존성일 경우 클라이언트 컴포넌트로 간주합니다. 그렇지 않으면 서버 컴포넌트로 간주합니다. @@ -68,7 +58,7 @@ export default function RichTextEditor({ timestamp, text }) { React 앱에서 컴포넌트는 종종 별도의 파일 또는 [모듈](/learn/importing-and-exporting-components#exporting-and-importing-a-component)로 분리됩니다. -React 서버 컴포넌트를 사용하는 앱의 경우, 기본적으로 앱은 서버에서 렌더링 됩니다. `'use client'`는 [모듈 의존성 트리](/learn/understanding-your-ui-as-a-tree#the-module-dependency-tree)에 서버-클라이언트 경계를 도입하여 효과적으로 클라이언트 모듈의 하위 트리를 만듭니다. +React 서버 컴포넌트를 사용하는 앱의 경우, 기본적으로 앱은 서버에서 렌더링됩니다. `'use client'`는 [모듈 의존성 트리](/learn/understanding-your-ui-as-a-tree#the-module-dependency-tree)에 서버-클라이언트 경계를 도입하여 효과적으로 클라이언트 모듈의 하위 트리를 만듭니다. 이를 더 잘 설명하기 위해 다음과 같은 React 서버 컴포넌트 앱을 고려해 보세요. @@ -174,7 +164,7 @@ React 서버 컴포넌트 앱을 위한 렌더 트리에서 `InspirationGenerato * **클라이언트 컴포넌트**는 클라이언트에서 렌더링되는 렌더 트리의 컴포넌트입니다. * **서버 컴포넌트**는 서버에서 렌더링 되는 렌더 트리의 컴포넌트입니다. -예시 앱이 실행되는 동안 `App`, `FancyText` 및 `Copyright`는 모두 서버에서 렌더링 되며 서버 컴포넌트로 간주합니다. `InspirationGenerator.js`와 그 전이적 의존성이 클라이언트 코드로 표시되므로 컴포넌트 `InspirationGenerator`와 그 자식 컴포넌트 `FancyText`는 클라이언트 컴포넌트입니다. +예시 앱이 실행되는 동안 `App`, `FancyText` 및 `Copyright`는 모두 서버에서 렌더링되며 서버 컴포넌트로 간주합니다. `InspirationGenerator.js`와 그 전이적 의존성이 클라이언트 코드로 표시되므로 컴포넌트 `InspirationGenerator`와 그 자식 컴포넌트 `FancyText`는 클라이언트 컴포넌트입니다. <DeepDive> #### 어떻게 `FancyText`는 서버 컴포넌트이면서 클라이언트 컴포넌트인가요? {/*how-is-fancytext-both-a-server-and-a-client-component*/} @@ -204,10 +194,10 @@ function App() { 개념을 설명할 때 종종 부정확성은 중요하지 않지만, 이 경우에는 중요합니다. -서버 또는 클라이언트 컴포넌트에 관해 이야기할 때, 컴포넌트 사용을 언급하고 있습니다. +서버 또는 클라이언트 컴포넌트에 대해 이야기할 때, 컴포넌트 사용을 언급하고 있습니다. -* 컴포넌트가 `'use client'` 지시어가 있는 모듈에서 정의되었거나 컴포넌트가 클라이언트에서 가져와 호출된다면 그 컴포넌트 사용은 클라이언트 컴포넌트입니다. -* 그렇지 않은 경우 컴포넌트 사용은 서버 컴포넌트입니다. +* 컴포넌트가 `'use client'` 지시어가 있는 모듈에서 정의되었거나, 컴포넌트가 클라이언트 컴포넌트 내부에서 가져와<sup>Imported</sup> 호출된다면 해당 컴포넌트는 클라이언트 컴포넌트입니다. +* 그렇지 않은 경우, 컴포넌트는 서버 컴포넌트입니다. <Diagram name="use_client_render_tree" height={150} width={450} alt="A tree graph where each node represents a component and its children as child components. The top-level node is labelled 'App' and it has two child components 'InspirationGenerator' and 'FancyText'. 'InspirationGenerator' has two child components, 'FancyText' and 'Copyright'. Both 'InspirationGenerator' and its child component 'FancyText' are marked to be client-rendered.">렌더 트리는 컴포넌트 사용을 보여줍니다.</Diagram> @@ -216,7 +206,7 @@ function App() { `FancyText`를 `App`의 자식으로 사용하면 서버 컴포넌트로 사용할 수 있습니다. `FancyText`를 가져와서 `InspirationGenerator`에서 호출할 때 `InspirationGenerator`에 `'use client'` 지시어가 포함되어 있으므로 `FancyText`의 사용은 클라이언트 컴포넌트입니다. -이는 `FancyText`에 대한 컴포넌트 정의가 서버에서 평가되고 클라이언트 컴포넌트 사용을 렌더링하기 위해 클라이언트에서 내려받게 된다는 것을 의미합니다. +이는 `FancyText`의 컴포넌트 정의가 서버에서 평가될 뿐만 아니라, 클라이언트 컴포넌트로 사용되기 위해 클라이언트에 다운로드된다는 것을 의미합니다. </DeepDive> @@ -224,15 +214,15 @@ function App() { #### 왜 `Copyright`가 서버 컴포넌트인가요? {/*why-is-copyright-a-server-component*/} -`Copyright` 컴포넌트가 클라이언트 컴포넌트 `InspirationGenerator`의 자식으로 렌더링 되지만 이것이 서버 컴포넌트라는 사실에 놀랄 수 있습니다. +`Copyright` 컴포넌트가 클라이언트 컴포넌트 `InspirationGenerator`의 자식으로 렌더링되기 때문에, 이것이 서버 컴포넌트라는 점이 놀랍게 느껴질 수 있습니다. -`'use client'` 지시어는 _모듈 의존성 트리_(렌더 트리가 아닌)에서 서버와 클라이언트 코드 간의 경계를 정의한다는 점을 기억하세요. +`'use client'` 지시어는 (렌더 트리가 아닌) <em>모듈 의존성 트리</em>에서 서버와 클라이언트 코드 간의 경계를 정의한다는 점을 기억하세요. <Diagram name="use_client_module_dependency" height={200} width={500} alt="A tree graph with the top node representing the module 'App.js'. 'App.js' has three children: 'Copyright.js', 'FancyText.js', and 'InspirationGenerator.js'. 'InspirationGenerator.js' has two children: 'FancyText.js' and 'inspirations.js'. The nodes under and including 'InspirationGenerator.js' have a yellow background color to signify that this sub-graph is client-rendered due to the 'use client' directive in 'InspirationGenerator.js'."> `'use client'` 지시어는 모듈 의존성 트리에서 서버와 클라이언트 코드의 경계를 정의합니다. </Diagram> -모듈 의존성 트리에서 `App.js`는 `Copyright.js` 모듈로부터 `Copyright`를 가져와 호출합니다. `Copyright.js`에는 `'use client'` 지시어가 없기 때문에 컴포넌트 사용이 서버에서 렌더링 됩니다. `App`은 루트 컴포넌트로 서버에서 렌더링 됩니다. +모듈 의존성 트리에서 `App.js`는 `Copyright.js` 모듈로부터 `Copyright`를 가져와 호출합니다. `Copyright.js`에는 `'use client'` 지시어가 없기 때문에 컴포넌트를 서버에서 렌더링합니다. `App`은 루트 컴포넌트로 서버에서 렌더링합니다. 클라이언트 컴포넌트는 JSX를 props로 전달할 수 있기 때문에 서버 컴포넌트를 렌더링할 수 있습니다. 이 경우 `InspirationGenerator`는 `Copyright`를 [자식](/learn/passing-props-to-a-component#passing-jsx-as-children)으로 받습니다. 그러나 `InspirationGenerator` 모듈은 `Copyright` 모듈을 직접 가져오거나 컴포넌트를 호출하지 않으며 이 모든 작업은 `App`에 의해 실행됩니다. 실제로 `InspirationGenerator`가 렌더링을 시작하기 전에 `Copyright` 컴포넌트는 완전히 실행됩니다. @@ -242,28 +232,27 @@ function App() { ### `'use client'`의 사용 시기 {/*when-to-use-use-client*/} -`'use client'`를 사용하면 컴포넌트가 클라이언트 컴포넌트인지 확인할 수 있습니다. 서버 컴포넌트가 기본값이므로 클라이언트에서 렌더링할 것을 표시해야 하는 시기를 결정하기 위해 서버 컴포넌트의 장단점을 간단히 살펴보겠습니다. +`'use client'`를 사용하면 컴포넌트가 클라이언트 컴포넌트인지 확인할 수 있습니다. 서버 컴포넌트가 기본값이므로, 클라이언트에서 렌더링할 것을 표시해야 하는 시기를 결정하기 위해 서버 컴포넌트의 장단점을 간단히 살펴보겠습니다. -간략화를 위해 서버 컴포넌트에 관해 이야기하지만, 서버에서 실행되는 앱의 모든 코드에는 동일한 원칙이 적용됩니다. +간단히 설명하기 위해 서버 컴포넌트에 대해 이야기하지만, 서버에서 실행되는 앱의 모든 코드에는 동일한 원칙이 적용됩니다. #### 서버 컴포넌트의 장점 {/*advantages*/} -* 서버 컴포넌트는 클라이언트가 전송하고 실행하는 코드양을 줄일 수 있습니다. 클라이언트 모듈만 번들링 되고 클라이언트에서 평가됩니다. +* 서버 컴포넌트는 클라이언트에 전송되고 실행되는 코드의 양을 줄일 수 있습니다. 클라이언트 모듈만 클라이언트에서 번들링되고 평가됩니다. * 서버 컴포넌트는 서버에서 실행할 때 이점이 있습니다. 로컬 파일 시스템에 접근할 수 있으며 데이터 가져오기 및 네트워크 요청에 대한 짧은 지연 시간을 경험할 수 있습니다. #### 서버 컴포넌트의 한계 {/*limitations*/} * 클라이언트에서 이벤트 핸들러를 등록하고 트리거해야 하므로 서버 컴포넌트는 상호작용을 지원할 수 없습니다. * 예를 들어 `onClick`과 같은 이벤트 핸들러는 클라이언트 컴포넌트에서만 정의할 수 있습니다. * 서버 컴포넌트는 대부분의 Hook을 사용할 수 없습니다. - * 서버 컴포넌트가 렌더링 되면 그 출력은 기본적으로 클라이언트가 렌더링할 컴포넌트 목록입니다. 서버 컴포넌트는 렌더링 후 메모리에 유지되지 않으며 자체 상태를 가질 수 없습니다. + * 서버 컴포넌트가 렌더링될 때, 그 출력은 기본적으로 클라이언트가 렌더링할 컴포넌트 목록입니다. 서버 컴포넌트는 렌더링 후 메모리에 유지되지 않으며 자체적인 State를 가질 수 없습니다. -### 서버 컴포넌트에서 반환되는 직렬화 가능한 유형 {/*serializable-types*/} +### 서버 컴포넌트에서 반환하는 직렬화 가능한 유형 {/*serializable-types*/} -React 앱에서와 같이 부모 컴포넌트는 자식 컴포넌트에 데이터를 전달합니다. 서로 다른 환경에서 렌더링 되므로 서버 컴포넌트에서 클라이언트 컴포넌트로 데이터를 전달하는 것은 추가적인 고려 사항이 필요합니다. +React 앱에서와 같이 부모 컴포넌트는 자식 컴포넌트에 데이터를 전달합니다. 서로 다른 환경에서 렌더링되므로 서버 컴포넌트에서 클라이언트 컴포넌트로 데이터를 전달하는 것은 추가적인 고려 사항이 필요합니다. -서버 컴포넌트에서 클라이언트 컴포넌트로 전달되는 prop 값은 직렬화할 수 있어야 합니다. +서버 컴포넌트에서 클라이언트 컴포넌트로 전달하는 Prop 값은 직렬화할 수 있어야 합니다. -<<<<<<< HEAD -직렬화할 수 있는 props는 다음과 같습니다. +직렬화할 수 있는 Props는 다음과 같습니다. * 원시 자료형 * [string](https://developer.mozilla.org/ko/docs/Glossary/String) * [number](https://developer.mozilla.org/ko/docs/Glossary/Number) @@ -271,7 +260,7 @@ React 앱에서와 같이 부모 컴포넌트는 자식 컴포넌트에 데이 * [boolean](https://developer.mozilla.org/ko/docs/Glossary/Boolean) * [undefined](https://developer.mozilla.org/ko/docs/Glossary/Undefined) * [null](https://developer.mozilla.org/ko/docs/Glossary/Null) - * [symbol](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Symbol) ( [`Symbol.for`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for)을 통해 글로벌 심볼 레지스트리에 등록된 심볼만 해당 ) + * [symbol](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Symbol) ( [`Symbol.for`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for)을 통해 글로벌 심볼 레지스트리에 등록된 심볼만 해당) * 직렬화할 수 있는 값을 포함하는 이터러블 * [String](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/String) * [Array](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array) @@ -280,31 +269,9 @@ React 앱에서와 같이 부모 컴포넌트는 자식 컴포넌트에 데이 * [TypedArray](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) 및 [ArrayBuffer](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) * [Date](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Date) * 일반 [객체](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object) (직렬화할 수 있는 프로퍼티를 사용하여 [객체 이니셜라이저](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Object_initializer)로 생성된 객체) -* [서버 액션](/reference/react/use-server)으로서의 함수 +* [서버 함수](/reference/rsc/server-functions)로서의 함수 * 클라이언트 또는 서버 컴포넌트 요소(JSX) * [Promises](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise) -======= -Serializable props include: -* Primitives - * [string](https://developer.mozilla.org/en-US/docs/Glossary/String) - * [number](https://developer.mozilla.org/en-US/docs/Glossary/Number) - * [bigint](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) - * [boolean](https://developer.mozilla.org/en-US/docs/Glossary/Boolean) - * [undefined](https://developer.mozilla.org/en-US/docs/Glossary/Undefined) - * [null](https://developer.mozilla.org/en-US/docs/Glossary/Null) - * [symbol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol), only symbols registered in the global Symbol registry via [`Symbol.for`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for) -* Iterables containing serializable values - * [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) - * [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) - * [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) - * [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) - * [TypedArray](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) and [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) -* [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) -* Plain [objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object): those created with [object initializers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer), with serializable properties -* Functions that are [Server Functions](/reference/rsc/server-functions) -* Client or Server Component elements (JSX) -* [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc 단, 다음은 지원되지 않습니다. * 클라이언트로 표시된 모듈에서 내보내지 않았거나 [`'use server'`](/reference/rsc/use-server)로 표시된 [함수](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Function) @@ -315,7 +282,7 @@ Serializable props include: ## 사용법 {/*usage*/} -### 상호작용과 상태를 가진 컴포넌트 구축 {/*building-with-interactivity-and-state*/} +### 상호작용 및 State를 가진 컴포넌트 구축 {/*building-with-interactivity-and-state*/} <Sandpack> @@ -354,7 +321,7 @@ export default async function CounterContainer() { } ``` -예를 들어, `Counter`의 상위 컴포넌트인 `CounterContainer`는 상호작용이 없고 state를 사용하지 않기 때문에 `'use client'`가 사용할 필요가 없습니다. 또한 `CounterContainer`는 서버의 로컬 파일 시스템에서 읽어야 하므로 이가 가능한 서버 컴포넌트여야만 합니다. +예를 들어, `Counter`의 상위 컴포넌트인 `CounterContainer`는 상호작용이 없고 State를 사용하지 않기 때문에 `'use client'`를 사용할 필요가 없습니다. 또한 `CounterContainer`는 서버의 로컬 파일 시스템을 읽어야 하므로, 이것이 가능한 서버 컴포넌트여야만 합니다. 서버나 클라이언트 전용 기능을 사용하지 않고 렌더링 위치에 구애받지 않는 컴포넌트도 있습니다. 앞서 예로 든 `FancyText`가 그러한 컴포넌트 중 하나입니다. @@ -368,11 +335,11 @@ export default function FancyText({title, text}) { 이 경우 `'use client'` 지시어를 추가하지 않으면 `FancyText`의 _산출물_(소스 코드가 아닌)이 서버 컴포넌트에서 참조될 때 브라우저로 전송됩니다. 앞서 Inspirations 앱 예시에서 보여준 것처럼 `FancyText`는 가져오고 사용되는 위치에 따라 서버 또는 클라이언트 컴포넌트로 사용됩니다. -하지만 `FancyText`의 HTML 출력이 의존성을 포함한 소스 코드에 비해 크다면, 항상 클라이언트 컴포넌트로 강제하는 것이 더 효율적일 수 있습니다. 한 예로 긴 SVG 경로 문자열을 반환하는 컴포넌트를 클라이언트 컴포넌트로 강제하는 것이 더 효율적일 수 있는 것처럼 말입니다. +하지만 `FancyText`의 HTML 출력이 (의존성을 포함한) 소스 코드에 비해 크다면, 항상 클라이언트 컴포넌트로 강제하는 것이 더 효율적일 수 있습니다. 한 예로 긴 SVG 경로 문자열을 반환하는 컴포넌트를 클라이언트 컴포넌트로 강제하는 것이 더 효율적일 수 있는 것처럼 말입니다. ### 클라이언트 API 사용 {/*using-client-apis*/} -React 앱에서는 웹 스토리지, 오디오 및 비디오 조작, 하드웨어 장치 등과 같은 [브라우저의 API](https://developer.mozilla.org/ko/docs/Web/API)를 포함한 클라이언트 특정 API를 사용할 수 있습니다. +React 앱에서는 웹 스토리지, 오디오 및 비디오 조작, 하드웨어 장치 등과 같은 [브라우저의 API](https://developer.mozilla.org/ko/docs/Web/API)를 포함한 클라이언트 전용 API를 사용할 수 있습니다. 이 예시에서 컴포넌트는 [DOM API](https://developer.mozilla.org/ko/docs/Glossary/DOM)를 사용해 [`canvas`](https://developer.mozilla.org/ko/docs/Web/HTML/Element/canvas) 요소를 조작합니다. 이러한 API는 브라우저에서만 사용할 수 있으므로 클라이언트 컴포넌트로 표시되어야 합니다. @@ -400,13 +367,13 @@ export default function Circle() { React 앱에서는 서드파티 라이브러리를 활용하여 일반적인 UI 패턴이나 로직을 처리하는 경우가 많습니다. 이러한 라이브러리들은 컴포넌트 Hook이나 클라이언트 API에 의존할 수 있습니다. 다음 React API를 사용하는 서드파티 컴포넌트는 클라이언트에서 실행되어야 합니다. -* [createContext](/reference/react/createContext) +* [`createContext`](/reference/react/createContext) * [`use`](/reference/react/use) 및 [`useId`](/reference/react/useId)를 제외한 [`react`](/reference/react/hooks)와 [`react-dom`](/reference/react-dom/hooks)의 Hook -* [forwardRef](/reference/react/forwardRef) -* [memo](/reference/react/memo) -* [startTransition](/reference/react/startTransition) +* [`forwardRef`](/reference/react/forwardRef) +* [`memo`](/reference/react/memo) +* [`startTransition`](/reference/react/startTransition) * 클라이언트 API를 사용하는 경우(예: DOM 삽입 혹은 네이티브 플랫폼 뷰 등) -이 라이브러리들이 React 서버 컴포넌트와 호환되도록 업데이트되었다면 이미 `'use client'`를 포함하고 있어 서버 컴포넌트에서 직접 사용할 수 있습니다. 라이브러리가 업데이트되지 않았거나 컴포넌트가 클라이언트에서만 지정할 수 있는 이벤트 핸들러와 같은 props가 필요한 경우 사용할 서드파티 클라이언트 컴포넌트와 서버 컴포넌트 사이에 자체 클라이언트 컴포넌트 파일을 추가해야 할 수 있습니다. +이 라이브러리들이 React 서버 컴포넌트와 호환되도록 업데이트되었다면 이미 `'use client'`를 포함하고 있어 서버 컴포넌트에서 직접 사용할 수 있습니다. 라이브러리가 업데이트되지 않았거나 컴포넌트가 클라이언트에서만 사용할 수 있는 이벤트 핸들러와 같은 Props가 필요한 경우, 사용할 서드파티 클라이언트 컴포넌트와 서버 컴포넌트 사이에 자체 클라이언트 컴포넌트 파일을 추가해야 할 수 있습니다. [TODO]: <> (Troubleshooting - need use-cases) From 43674555e9f8de11748ca618a00bf4fe237eae8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Thu, 2 Jan 2025 23:44:05 +0900 Subject: [PATCH 0487/1164] docs: update `use-server.md` --- src/content/reference/rsc/use-client.md | 8 +- src/content/reference/rsc/use-server.md | 180 ++++++------------------ 2 files changed, 44 insertions(+), 144 deletions(-) diff --git a/src/content/reference/rsc/use-client.md b/src/content/reference/rsc/use-client.md index 448860414..252884f7a 100644 --- a/src/content/reference/rsc/use-client.md +++ b/src/content/reference/rsc/use-client.md @@ -12,7 +12,7 @@ titleForTitleTag: "'use client' 지시어" <Intro> -`'use client'`를 사용하면 클라이언트에서 실행되는 코드를 표시할 수 있습니다. +`'use client'`를 사용하여 클라이언트에서 실행되는 코드를 표시합니다. </Intro> @@ -260,7 +260,7 @@ React 앱에서와 같이 부모 컴포넌트는 자식 컴포넌트에 데이 * [boolean](https://developer.mozilla.org/ko/docs/Glossary/Boolean) * [undefined](https://developer.mozilla.org/ko/docs/Glossary/Undefined) * [null](https://developer.mozilla.org/ko/docs/Glossary/Null) - * [symbol](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Symbol) ( [`Symbol.for`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for)을 통해 글로벌 심볼 레지스트리에 등록된 심볼만 해당) + * [symbol](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Symbol) ( [`Symbol.for`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for)를 통해 전역 심볼 레지스트리에 등록된 심볼만 해당) * 직렬화할 수 있는 값을 포함하는 이터러블 * [String](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/String) * [Array](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array) @@ -271,13 +271,13 @@ React 앱에서와 같이 부모 컴포넌트는 자식 컴포넌트에 데이 * 일반 [객체](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object) (직렬화할 수 있는 프로퍼티를 사용하여 [객체 이니셜라이저](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Object_initializer)로 생성된 객체) * [서버 함수](/reference/rsc/server-functions)로서의 함수 * 클라이언트 또는 서버 컴포넌트 요소(JSX) -* [Promises](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise) +* [Promise](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise) 단, 다음은 지원되지 않습니다. * 클라이언트로 표시된 모듈에서 내보내지 않았거나 [`'use server'`](/reference/rsc/use-server)로 표시된 [함수](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Function) * [클래스](https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Classes_in_JavaScript) * 위에서 언급한 내장형 클래스의 인스턴스가 아닌 객체 혹은 [null 프로토타입](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object#null-prototype_objects)을 가진 객체 -* 글로벌하게 등록되지 않은 symbol (예: `Symbol('my new symbol')`) +* 전역에 등록되지 않은 Symbol (예: `Symbol('my new symbol')`) ## 사용법 {/*usage*/} diff --git a/src/content/reference/rsc/use-server.md b/src/content/reference/rsc/use-server.md index fa644d03e..edb8d917c 100644 --- a/src/content/reference/rsc/use-server.md +++ b/src/content/reference/rsc/use-server.md @@ -1,27 +1,18 @@ --- title: "'use server'" -<<<<<<< HEAD titleForTitleTag: "'use server' 지시어" -canary: true -======= -titleForTitleTag: "'use server' directive" ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc --- <RSC> -<<<<<<< HEAD -`'use server'`는 [React 서버 컴포넌트를 사용](/learn/start-a-new-react-project#bleeding-edge-react-frameworks)하거나 그와 호환되는 라이브러리를 만들 때만 필요합니다. -======= `'use server'` is for use with [using React Server Components](/learn/start-a-new-react-project#bleeding-edge-react-frameworks). ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc </RSC> <Intro> -`'use server'`는 클라이언트 측 코드에서 호출할 수 있는 서버 측 함수를 표시합니다. +`'use server'`를 사용하여 클라이언트 측 코드에서 호출할 수 있는 서버 측 함수를 표시합니다. </Intro> @@ -33,11 +24,7 @@ titleForTitleTag: "'use server' directive" ### `'use server'` {/*use-server*/} -<<<<<<< HEAD -함수가 클라이언트에서 실행될 수 있음을 표시하기 위해, 비동기 함수의 맨 위에 `'use server';`를 추가하세요. 우리는 이를 _Server Actions_ 이라고 부릅니다. -======= -Add `'use server'` at the top of an async function body to mark the function as callable by the client. We call these functions [_Server Functions_](/reference/rsc/server-functions). ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +함수를 클라이언트에서 호출할 수 있음을 표시하기 위해, 비동기 함수의 최상단에 `'use server';`를 추가하세요. 이를 [_서버 함수_](/reference/rsc/server-functions)라고 부릅니다. ```js {2} async function addToCart(data) { @@ -46,53 +33,28 @@ async function addToCart(data) { } ``` -<<<<<<< HEAD -Server Action을 클라이언트에서 호출하면, 직렬화된 인자의 사본을 포함하는 서버로의 네트워크 요청이 생성됩니다. Server Action이 값을 반환하면, 그 값은 직렬화되고 클라이언트에 반환됩니다. +클라이언트에서 서버 함수를 호출하면, 전달된 모든 인수의 직렬화된 사본을 포함한 네트워크 요청을 서버로 전송합니다. 서버 함수가 값을 반환하면, 그 값을 직렬화하여 클라이언트로 반환합니다. -함수 각각에 `'use server'`를 표기하는 대신, 파일의 맨 위에 지시어를 추가하여 파일의 모든 export를, 클라이언트를 포함한 모든 곳에서 사용할 수 있는 Server Action으로 표기할 수 있습니다. +함수 각각에 `'use server'`를 표기하는 대신, 파일의 최상단에 지시어를 추가하여 파일의 모든 내보내기<sup>Export</sup>를 클라이언트를 포함한 모든 곳에서 사용할 수 있는 서버 함수로 표기할 수 있습니다. #### 주의 사항 {/*caveats*/} -* `'use server'`는 함수 또는 모듈의 맨 처음에 있어야 합니다. import를 포함한 다른 코드보다 위에 있어야 합니다.(지시어 위의 주석은 괜찮습니다). 백틱이 아닌 단일 또는 이중 따옴표로 작성해야 합니다. -* `'use server'`는 서버 측 파일에서만 사용할 수 있습니다. 결과적인 Server Action은 props를 통해 클라이언트 컴포넌트로 전달할 수 있습니다. 제공되는 [직렬화 타입](#serializable-parameters-and-return-values)을 참고하세요. -* Server Action을 [클라이언트 코드](/reference/rsc/use-client)에서 import 하기 위해, 지시어는 모듈 수준에서 사용되어야 합니다. -* 기본 네트워크 호출이 항상 비동기이므로 `'use server'`는 비동기 함수에서만 사용할 수 있습니다. -* 항상 Server Action의 인자를 신뢰할 수 없는 입력으로 취급하고 모든 변경을 검토하세요. [보안 고려사항](#security)을 확인하세요. -* Server Action은 [transition](/reference/react/useTransition) 안에서 호출되어야합니다. [`<form action>`](/reference/react-dom/components/form#props) 또는 [`formAction`](/reference/react-dom/components/input#props)로 전달된 Server Action은 자동으로 transition 내에서 호출됩니다. -* Server Action은 서버 측 상태를 업데이트하는 mutation을 위해 설계되었으며 데이터 fetching에는 권장되지 않습니다. 따라서 서버 액션을 구현하는 프레임워크는 일반적으로 한 번에 하나의 액션을 처리하며 반환 값을 캐시할 방법이 없습니다. -======= -When calling a Server Function on the client, it will make a network request to the server that includes a serialized copy of any arguments passed. If the Server Function returns a value, that value will be serialized and returned to the client. - -Instead of individually marking functions with `'use server'`, you can add the directive to the top of a file to mark all exports within that file as Server Functions that can be used anywhere, including imported in client code. - -#### Caveats {/*caveats*/} -* `'use server'` must be at the very beginning of their function or module; above any other code including imports (comments above directives are OK). They must be written with single or double quotes, not backticks. -* `'use server'` can only be used in server-side files. The resulting Server Functions can be passed to Client Components through props. See supported [types for serialization](#serializable-parameters-and-return-values). -* To import a Server Functions from [client code](/reference/rsc/use-client), the directive must be used on a module level. -* Because the underlying network calls are always asynchronous, `'use server'` can only be used on async functions. -* Always treat arguments to Server Functions as untrusted input and authorize any mutations. See [security considerations](#security). -* Server Functions should be called in a [Transition](/reference/react/useTransition). Server Functions passed to [`<form action>`](/reference/react-dom/components/form#props) or [`formAction`](/reference/react-dom/components/input#props) will automatically be called in a transition. -* Server Functions are designed for mutations that update server-side state; they are not recommended for data fetching. Accordingly, frameworks implementing Server Functions typically process one action at a time and do not have a way to cache the return value. ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +* `'use server'`는 함수 또는 모듈의 최상단에 있어야 합니다. `import`를 포함한 다른 코드보다 위에 있어야 합니다. (지시어 위의 주석은 괜찮습니다.) 백틱이 아닌 단일 또는 이중 따옴표로 작성해야 합니다. +* `'use server'`는 서버 측 파일에서만 사용할 수 있습니다. 결과적으로 생성된 서버 함수는 Props를 통해 클라이언트 컴포넌트로 전달할 수 있습니다. 지원되는 [직렬화 타입](#serializable-parameters-and-return-values)을 참고하세요. +* 서버 함수를 [클라이언트 코드](/reference/rsc/use-client)에서 가져오기<sup>Import</sup> 위해, 지시어를 모듈 수준에서 사용해야 합니다. +* 기본 네트워크 호출이 항상 비동기적이므로, `'use server'`는 비동기 함수에서만 사용할 수 있습니다. +* 항상 서버 함수의 인수를 신뢰할 수 없는 입력으로 취급하고 모든 변경을 검토하세요. [보안 고려사항](#security)을 확인하세요. +* 서버 함수는 [Transition](/reference/react/useTransition) 안에서 호출되어야 합니다. [`<form action>`](/reference/react-dom/components/form#props) 또는 [`formAction`](/reference/react-dom/components/input#props)으로 전달된 서버 함수는 자동으로 Transition 내에서 호출됩니다. +* 서버 함수는 서버 측 상태를 업데이트하는 Mutation을 위해 설계되었으며, 데이터 가져오기<sup>Fetching</sup>에는 권장하지 않습니다. 따라서, 서버 함수를 구현하는 프레임워크는 일반적으로 한 번에 하나의 작업만 처리하며, 반환 값을 캐시하는 방법을 제공하지 않습니다. ### 보안 고려사항 {/*security*/} -<<<<<<< HEAD -Server Action에 대한 인수는 완전히 클라이언트에서 제어됩니다. 보안을 위해 항상 신뢰할 수 없는 입력으로 취급하여, 인자를 적절하게 검증하고 이스케이프 하는지 확인하세요. +서버 함수에 대한 인수는 클라이언트에서 완전히 제어됩니다. 보안을 위해 항상 신뢰할 수 없는 입력으로 취급하여, 인수를 적절하게 검증하고 이스케이프 하는지 확인하세요. -Server Action에서 로그인한 사용자가 해당 작업을 수행할 수 있는지 확인하세요. +모든 서버 함수에서 로그인한 사용자가 해당 작업을 수행할 수 있는지 확인하세요. <Wip> -Server Action에서 중요한 데이터를 전송하지 않도록 하기 위해, 고유한 값과 객체가 클라이언트 코드로 전달되는 것을 방지하기 위한 실험적인 테인트 API가 있습니다. -======= -Arguments to Server Functions are fully client-controlled. For security, always treat them as untrusted input, and make sure to validate and escape arguments as appropriate. - -In any Server Function, make sure to validate that the logged-in user is allowed to perform that action. - -<Wip> - -To prevent sending sensitive data from a Server Function, there are experimental taint APIs to prevent unique values and objects from being passed to client code. ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +서버 함수에서 중요한 데이터를 전송하지 않기 위해, 고유한 값과 객체를 클라이언트 코드로 전달하는 것을 방지하기 위한 실험적인 Taint API가 있습니다. [experimental_taintUniqueValue](/reference/react/experimental_taintUniqueValue)와 [experimental_taintObjectReference](/reference/react/experimental_taintObjectReference)를 참고하세요. @@ -100,20 +62,19 @@ To prevent sending sensitive data from a Server Function, there are experimental ### 직렬화 가능 인수와 반환값 {/*serializable-parameters-and-return-values*/} -<<<<<<< HEAD -클라이언트 코드가 네트워크를 통해 서버 작업을 호출할 때 전달된 인수는 모두 직렬화되어야 합니다. +클라이언트 코드가 네트워크를 통해 서버 함수를 호출하므로, 전달하는 모든 인수는 직렬화 가능해야 합니다. -다음은 지원되는 Server Action 인자의 타입입니다. +다음은 서버 함수의 인수로 지원되는 타입입니다. -* Primitives +* 원시 자료형 * [string](https://developer.mozilla.org/ko/docs/Glossary/String) * [number](https://developer.mozilla.org/ko/docs/Glossary/Number) * [bigint](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/BigInt) * [boolean](https://developer.mozilla.org/ko/docs/Glossary/Boolean) * [undefined](https://developer.mozilla.org/ko/docs/Glossary/Undefined) * [null](https://developer.mozilla.org/ko/docs/Glossary/Null) - * [symbol](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Symbol), [`Symbol.for`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for)를 통해 전역 Symbol로 등록된 Symbol 한정 -* 직렬화 가능한 값을 포함한 Iterables + * [symbol](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Symbol) ( [`Symbol.for`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for)를 통해 전역 심볼 레지스트리에 등록된 심볼만 해당) +* 직렬화할 수 있는 값을 포함하는 이터러블 * [String](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/String) * [Array](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array) * [Map](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Map) @@ -121,67 +82,27 @@ To prevent sending sensitive data from a Server Function, there are experimental * [TypedArray](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/TypedArray)와 [ArrayBuffer](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) * [Date](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Date) * [FormData](https://developer.mozilla.org/ko/docs/Web/API/FormData) 인스턴스 -* [object initializers](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Object_initializer)로 직렬화 가능한 속성과 함께 생성된 일반 [objects](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object) -* Server Action인 함수 -* [Promises](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise) +* 일반 [객체](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object) (직렬화할 수 있는 프로퍼티를 사용하여 [객체 이니셜라이저](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Object_initializer)로 생성된 객체) +* [서버 함수](/reference/rsc/server-functions)로서의 함수 +* [Promise](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise) -특히 다음은 지원되지 않습니다. +단, 다음은 지원되지 않습니다. * React 엘리먼트 또는 [JSX](/learn/writing-markup-with-jsx) -* 컴포넌트 함수 또는 Server Action이 아닌 다른 함수를 포함하는 함수 +* 컴포넌트 함수 또는 서버 함수가 아닌 다른 함수를 포함하는 함수 * [클래스](https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Classes_in_JavaScript) -* 클래스의 인스턴스인 객체(언급된 내장 객체 제외)또는 [null 프로토타입](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object#null-prototype_objects)이 있는 개체 -* 전역에 등록되지 않은 Symbol, 예. `Symbol('my new symbol')` -======= -Since client code calls the Server Function over the network, any arguments passed will need to be serializable. - -Here are supported types for Server Function arguments: - -* Primitives - * [string](https://developer.mozilla.org/en-US/docs/Glossary/String) - * [number](https://developer.mozilla.org/en-US/docs/Glossary/Number) - * [bigint](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) - * [boolean](https://developer.mozilla.org/en-US/docs/Glossary/Boolean) - * [undefined](https://developer.mozilla.org/en-US/docs/Glossary/Undefined) - * [null](https://developer.mozilla.org/en-US/docs/Glossary/Null) - * [symbol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol), only symbols registered in the global Symbol registry via [`Symbol.for`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for) -* Iterables containing serializable values - * [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) - * [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) - * [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) - * [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) - * [TypedArray](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) and [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) -* [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) -* [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) instances -* Plain [objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object): those created with [object initializers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer), with serializable properties -* Functions that are Server Functions -* [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) - -Notably, these are not supported: -* React elements, or [JSX](/learn/writing-markup-with-jsx) -* Functions, including component functions or any other function that is not a Server Function -* [Classes](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Classes_in_JavaScript) -* Objects that are instances of any class (other than the built-ins mentioned) or objects with [a null prototype](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object#null-prototype_objects) -* Symbols not registered globally, ex. `Symbol('my new symbol')` +* 클래스의 인스턴스인 객체(언급된 내장 객체 제외)또는 [null 프로토타입](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object#null-prototype_objects)이 있는 객체 +* 전역에 등록되지 않은 Symbol (예: `Symbol('my new symbol')`) * Events from event handlers ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc - -지원되는 직렬화 가능한 반환 값은 경계 클라이언트 컴포넌트의 [직렬화 가능한 props](/reference/react/use-client#passing-props-from-server-to-client-components)와 동일합니다. - -### Server Action 형식 {/*server-actions-in-forms*/} -Server Action의 가장 일반적인 사용 사례는, 데이터를 변경하는 서버 함수를 호출하는 것입니다. 브라우저에서 [HTML 폼 엘리먼트](https://developer.mozilla.org/ko/docs/Web/HTML/Element/form)는 사용자가 mutation을 제출하는 전통적인 접근 방식입니다. React 서버 컴포넌트로, React는 [forms](/reference/react-dom/components/form)에서 Server Action에 대한 최상의 지원을 제공합니다. +지원되는 직렬화 가능한 반환 값은 경계 클라이언트 컴포넌트의 [직렬화 가능한 Props](/reference/rsc/use-client#passing-props-from-server-to-client-components)와 동일합니다. -<<<<<<< HEAD -사용자가 사용자 이름을 요청할 수 있는 양식이 있습니다. -======= -## Usage {/*usage*/} +## 사용법 {/*usage*/} ### Server Functions in forms {/*server-functions-in-forms*/} -The most common use case of Server Functions will be calling functions that mutate data. On the browser, the [HTML form element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form) is the traditional approach for a user to submit a mutation. With React Server Components, React introduces first-class support for Server Functions as Actions in [forms](/reference/react-dom/components/form). +서버 함수의 가장 일반적인 사용 사례는, 데이터를 변경하는 서버 함수를 호출하는 것입니다. 브라우저의 [HTML 폼 엘리먼트](https://developer.mozilla.org/ko/docs/Web/HTML/Element/form)는 사용자가 Mutation을 제출하는 전통적인 접근 방식입니다. React 서버 컴포넌트를 통해, React는 [폼<sup>Form</sup>](/reference/react-dom/components/form)에서 액션으로 사용되는 서버 함수에 대한 최상의 지원을 제공합니다. -Here is a form that allows a user to request a username. ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +여기, 사용자가 사용자 이름을 요청할 수 있는 폼<sup>Form</sup>이 있습니다. ```js [[1, 3, "formData"]] // App.js @@ -202,24 +123,15 @@ export default function App() { } ``` -<<<<<<< HEAD -예시에서 `requestUsername`는 `<form>`을 통한 Server Action입니다. 사용자가 이 양식을 제출하면 서버 함수인 `requestUsername`에 네트워크 요청이 있습니다. 폼에서 Server Action을 호출할 때 React는 폼의 <CodeStep step={1}>[FormData](https://developer.mozilla.org/ko/docs/Web/API/FormData)</CodeStep>를 Server Action의 첫 번째 인자로 제공합니다. - -Server Action을 폼 `action`에 전달하여, React는 폼을 [점진적 향상](https://developer.mozilla.org/ko/docs/Glossary/Progressive_Enhancement)할 수 있습니다. 이것은 자바스크립트 번들이 로드되기 전에 양식을 제출할 수 있다는 것을 의미합니다. -======= -In this example `requestUsername` is a Server Function passed to a `<form>`. When a user submits this form, there is a network request to the server function `requestUsername`. When calling a Server Function in a form, React will supply the form's <CodeStep step={1}>[FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData)</CodeStep> as the first argument to the Server Function. - -By passing a Server Function to the form `action`, React can [progressively enhance](https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement) the form. This means that forms can be submitted before the JavaScript bundle is loaded. ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +예시에서 `requestUsername`은 `<form>`을 통한 서버 함수입니다. 사용자가 이 폼<sup>Form</sup>을 제출하면 서버 함수인 `requestUsername`에 네트워크 요청을 보냅니다. 폼<sup>Form</sup>에서 서버 함수를 호출할 때, React는 폼<sup>Form</sup>의 <CodeStep step={1}>[formData](https://developer.mozilla.org/ko/docs/Web/API/FormData)</CodeStep>를 서버 함수의 첫 번째 인자로 제공합니다. +서버 함수를 폼 `action`에 전달하여, React는 폼을 [점진적 향상](https://developer.mozilla.org/ko/docs/Glossary/Progressive_Enhancement)할 수 있습니다. 이것은 자바스크립트 번들을 로드하기 전에 양식을 제출할 수 있다는 것을 의미합니다. #### 폼에서 반환 값 처리 {/*handling-return-values*/} -<<<<<<< HEAD -점진적 향상을 지원하며 Server Action의 결과를 기반으로 UI를 업데이트하려면, [`useActionState`](/reference/react/useActionState)를 사용하세요. -======= -To update the UI based on the result of a Server Function while supporting progressive enhancement, use [`useActionState`](/reference/react/useActionState). ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +In the username request form, there might be the chance that a username is not available. `requestUsername` should tell us if it fails or not. + +점진적 향상을 지원하며 서버 함수의 결과를 기반으로 UI를 업데이트하려면, [`useActionState`](/reference/react/useActionState)를 사용하세요. ```js // requestUsername.js @@ -257,21 +169,13 @@ function UsernameForm() { } ``` -대부분의 Hook과 마찬가지로 `useActionState`는 <CodeStep step={1}>[client code](/reference/rsc/use-client)</CodeStep>에서만 호출할 수 있습니다. - -<<<<<<< HEAD -### `<form>`외부에서 Server Action 호출하기 {/*calling-a-server-action-outside-of-form*/} - -Server Action은 노출된 서버 엔드포인트이며 클라이언트 코드 어디에서나 호출할 수 있습니다. +대부분의 Hook과 마찬가지로 `useActionState`는 <CodeStep step={2}>[클라이언트 코드](/reference/rsc/use-client)</CodeStep>에서만 호출할 수 있습니다. -[form](/reference/react-dom/components/form) 외부에서 Server Action을 사용할 때, [Transition](/reference/react/useTransition)에서 서버 액션을 호출하면 로딩 인디케이터를 표시하고, [낙관적 상태 업데이트](/reference/react/useOptimistic)를 표시하며 예기치 않은 오류를 처리할 수 있습니다. 폼은 transition의 Server Action을 자동으로 래핑합니다. -======= -### Calling a Server Function outside of `<form>` {/*calling-a-server-function-outside-of-form*/} +### `<form>`외부에서 서버 함수 호출하기 {/*calling-a-server-function-outside-of-form*/} -Server Functions are exposed server endpoints and can be called anywhere in client code. +서버 함수는 노출된 서버 엔드포인트이며 클라이언트 코드 어디에서나 호출할 수 있습니다. -When using a Server Function outside a [form](/reference/react-dom/components/form), call the Server Function in a [Transition](/reference/react/useTransition), which allows you to display a loading indicator, show [optimistic state updates](/reference/react/useOptimistic), and handle unexpected errors. Forms will automatically wrap Server Functions in transitions. ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +[폼<sup>Form</sup>](/reference/react-dom/components/form) 외부에서 서버 함수를 사용할 때, [Transition](/reference/react/useTransition)에서 서버 함수를 호출하면 로딩 인디케이터<sup>Loading Indicator</sup>를 표시하고, [낙관적 상태 업데이트](/reference/react/useOptimistic)를 표시하며 예기치 않은 오류를 처리할 수 있습니다. 폼은 Transition의 서버 함수를 자동으로 래핑합니다. ```js {9-12} import incrementLike from './actions'; @@ -308,8 +212,4 @@ export default async function incrementLike() { } ``` -<<<<<<< HEAD -Server Action 반환 값을 읽으려면 반환된 promise를 `await` 해야합니다. -======= -To read a Server Function return value, you'll need to `await` the promise returned. ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +서버 함수의 반환 값을 읽으려면 반환된 Promise를 `await` 해야합니다. From 9137ecc96c7b3ef1c592b0d0bb5d366c008fd3f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Thu, 2 Jan 2025 23:59:27 +0900 Subject: [PATCH 0488/1164] docs: update `rules/index.md` --- src/content/reference/rules/index.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/content/reference/rules/index.md b/src/content/reference/rules/index.md index 586abda2b..4c28026ba 100644 --- a/src/content/reference/rules/index.md +++ b/src/content/reference/rules/index.md @@ -3,7 +3,7 @@ title: React의 규칙 --- <Intro> -각 프로그래밍 언어마다 개념을 표현하는 고유한 방식이 있듯이, React도 이해하기 쉽고 고품질 애플리케이션을 생성하는 패턴을 표현하기 위한 고유한 관용구와 규칙을 가지고 있습니다. +각 프로그래밍 언어마다 개념을 표현하는 고유한 방식이 있듯이, React에도 패턴 이해를 쉽게 하며 고품질의 애플리케이션을 만들 수 있게 하는 일종의 규칙 혹은 모범적인 방식이 있습니다. </Intro> <InlineToc /> @@ -14,22 +14,22 @@ title: React의 규칙 React를 사용하여 UI를 표현하는 방법에 대해 더 알고 싶다면 [React로 사고하기](/learn/thinking-in-react)를 읽어보는 것을 추천합니다. </Note> -이 섹션에서는 관용적인 React 코드를 작성하기 위한 규칙을 설명합니다. 관용적인 React 코드를 작성하면 애플리케이션을 체계적으로 조직하고 안전하며 쉽게 구성할 수 있습니다. 이러한 특성은 애플리케이션이 변화에 더 잘 대처할 수 있게 하고 다른 개발자나 라이브러리, 도구와의 협업을 더 원활하게 합니다. +이 섹션에서는 모범적인 React 코드를 작성하기 위한 규칙을 설명합니다. 모범적인 React 코드를 작성하면 애플리케이션을 체계적으로 조직하고 안전하며 쉽게 구성할 수 있습니다. 이러한 특성은 애플리케이션이 변화에 더 잘 대처할 수 있게 하고 다른 개발자나 라이브러리, 도구와의 협업을 더 원활하게 합니다. -이러한 규칙을 **React의 규칙** 이라고 합니다. 이는 단순한 지침이 아니라 규칙으로, 이를 어길 경우 애플리케이션에 버그가 생길 가능성이 높으며 코드가 일반적이지 않게 변해 이해하기 어렵고 논리적으로 설명하기 힘들어집니다. +이러한 규칙을 **React의 규칙**이라고 합니다. 이는 단순한 지침이 아니라 규칙으로, 이를 어길 경우 애플리케이션에 버그가 생길 가능성이 높으며 코드가 일반적이지 않게 변해 이해하기 어렵고 논리적으로 설명하기 힘들어집니다. -코드베이스가 React의 규칙을 따르도록 돕기 위해 React의 [ESLint](https://www.npmjs.com/package/eslint-plugin-react-hooks) 플러그인과 함께 [Strict Mode](/reference/react/StrictMode)를 사용하는 것을 강력히 권장합니다. React의 규칙을 따르면 버그를 찾아 해결할 수 있으며 애플리케이션의 유지 보수성을 높일 수 있습니다. +코드베이스가 React의 규칙을 따르도록 하기 위해 React의 [ESLint](https://www.npmjs.com/package/eslint-plugin-react-hooks) 플러그인과 함께 [Strict Mode](/reference/react/StrictMode)를 사용하는 것을 강력히 권장합니다. React의 규칙을 따르면 버그를 찾아 해결할 수 있으며 애플리케이션의 유지 보수성을 높일 수 있습니다. --- ## 컴포넌트와 Hook은 순수해야 합니다 {/*components-and-hooks-must-be-pure*/} -[컴포넌트와 Hook의 순수성](/reference/rules/components-and-hooks-must-be-pure)은 React의 주요 규칙으로 이를 통해 앱의 예측 가능하고 디버깅이 쉬워지며 React가 코드를 자동으로 최적화할 수 있습니다. +[컴포넌트와 Hook의 순수성](/reference/rules/components-and-hooks-must-be-pure)은 React의 주요 규칙으로, 이를 통해 앱이 예측 가능하고 디버깅이 쉬워지며 React가 코드를 자동으로 최적화할 수 있습니다. -* [컴포넌트는 멱등해야 합니다](/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent) – React 컴포넌트는 항상 입력 값(props, state, context)에 따라 동일한 출력을 반환한다고 가정합니다. +* [컴포넌트는 멱등해야 합니다](/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent) – React 컴포넌트는 항상 입력 값(Props, State, Context)에 따라 동일한 출력을 반환한다고 가정합니다. * [사이드 이펙트는 렌더링 외부에서 실행되어야 합니다](/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render) – [사이드 이펙트](/learn/keeping-components-pure#side-effects-unintended-consequences)는 React가 최상의 사용자 경험을 제공하기 위해 컴포넌트를 여러 번 렌더링할 수 있기 때문에 렌더링 중에 실행되어서는 안 됩니다. -* [Props와 state는 불변입니다](/reference/rules/components-and-hooks-must-be-pure#props-and-state-are-immutable) – 컴포넌트의 props와 state는 단일 렌더링에 대해 불변의 [스냅샷](/learn/state-as-a-snapshot)입니다. 절대 이를 직접 변경하지 마세요. -* [Hook의 반환값과 인수는 불변입니다](/reference/rules/components-and-hooks-must-be-pure#return-values-and-arguments-to-hooks-are-immutable) – 값이 Hook에 전달되면 이를 수정해서는 안 됩니다. JSX의 props와 마찬가지로 Hook에 전달된 값도 불변입니다. +* [Props와 State는 불변입니다](/reference/rules/components-and-hooks-must-be-pure#props-and-state-are-immutable) – 컴포넌트의 Props와 State는 단일 렌더링에 대한 불변의 [스냅샷](/learn/state-as-a-snapshot)입니다. 절대 이를 직접 변경하지 마세요. +* [Hook의 반환값과 인수는 불변입니다](/reference/rules/components-and-hooks-must-be-pure#return-values-and-arguments-to-hooks-are-immutable) – 값이 Hook에 전달되면 이를 수정해서는 안 됩니다. JSX의 Props와 마찬가지로 Hook에 전달된 값도 불변입니다. * [JSX로 전달된 값은 불변입니다](/reference/rules/components-and-hooks-must-be-pure#values-are-immutable-after-being-passed-to-jsx) – JSX에 사용된 후에는 값을 변경하지 마세요. JSX가 생성되기 전에 변경을 수행하세요. --- @@ -45,8 +45,8 @@ React를 사용하여 UI를 표현하는 방법에 대해 더 알고 싶다면 [ ## Hook의 규칙 {/*rules-of-hooks*/} -Hook은 JavaScript 함수로 정의되지만 호출 위치에 제약이 있는 특별한 유형의 재사용 가능한 UI 로직입니다. Hook을 사용할 때는 [Hook의 규칙](/reference/rules/rules-of-hooks) 을 따라야 합니다. +Hook은 자바스크립트 함수로 정의하지만, 호출 위치에 제약이 있는 특별한 유형의 재사용 가능한 UI 로직입니다. Hook을 사용할 때는 [Hook의 규칙](/reference/rules/rules-of-hooks)을 따라야 합니다. * [Hook을 최상위 레벨에서만 호출하세요](/reference/rules/rules-of-hooks#only-call-hooks-at-the-top-level) – Hook을 반복문, 조건문, 또는 중첩된 함수 내부에서 호출하지 마세요. 대신 Hook을 항상 React 함수 최상위 레벨에서 호출하고, early return 이전에 사용해야 합니다. -* [Hook을 React 함수에서만 호출하세요 ](/reference/rules/rules-of-hooks#only-call-hooks-from-react-functions) – 일반 JavaScript 함수에서 Hook을 호출하지 마세요. +* [Hook을 React 함수에서만 호출하세요 ](/reference/rules/rules-of-hooks#only-call-hooks-from-react-functions) – 일반 자바스크립트 함수에서 Hook을 호출하지 마세요. From 8310e7dd0f44962b1f467df3e98d76cd9464cd5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Fri, 3 Jan 2025 17:20:57 +0900 Subject: [PATCH 0489/1164] docs: update `components-and-hooks-must-be-pure` --- .../components-and-hooks-must-be-pure.md | 88 +++++++++---------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/src/content/reference/rules/components-and-hooks-must-be-pure.md b/src/content/reference/rules/components-and-hooks-must-be-pure.md index cc1bf4fe7..9044d4f5a 100644 --- a/src/content/reference/rules/components-and-hooks-must-be-pure.md +++ b/src/content/reference/rules/components-and-hooks-must-be-pure.md @@ -16,19 +16,19 @@ title: 컴포넌트와 Hook은 순수해야 합니다 React를 만드는 핵심 개념 중 하나는 _순수성_ 입니다. 순수한 컴포넌트나 Hook은 다음과 같습니다. -* **멱등성** – 컴포넌트의 props, state, context 혹은 Hook의 인수에 대한 동일한 입력으로 실행할 때마다 [항상 같은 결과](/learn/keeping-components-pure#purity-components-as-formulas)를 얻습니다. -* **렌더링 시 사이드 이펙트가 없어야 합니다** – 사이드 이펙트가 있는 코드는 [**렌더링과 별도로 실행**](#how-does-react-run-your-code)되어야 합니다. 예를 들어 [이벤트 핸들러](/learn/responding-to-events)에서는 사용자가 UI와 상호작용을 하여 업데이트가 발생하거나 [Effect](/reference/react/useEffect)에서는 렌더링 후에 실행됩니다. +* **멱등성** – 컴포넌트의 Props, State, Context 혹은 Hook의 인수에 대한 동일한 입력으로 실행할 때마다 [항상 같은 결과](/learn/keeping-components-pure#purity-components-as-formulas)를 얻습니다. +* **렌더링 시 사이드 이펙트가 없어야 합니다** – 사이드 이펙트가 있는 코드는 [**렌더링과 별도로 실행**](#how-does-react-run-your-code)해야 합니다. 예를 들어, [이벤트 핸들러](/learn/responding-to-events)를 통해 사용자가 UI와 상호작용하여 UI를 업데이트하는 경우나, 렌더링 후에 실행되는 [Effect](/reference/react/useEffect)를 사용할 수 있습니다. * **지역 변수가 아닌 값을 변경하지 마세요** – 컴포넌트와 Hook은 렌더링 시 [지역에서 생성되지 않은 값을 수정하지 않아야](#mutation) 합니다. -렌더링이 순수하게 유지되면, React는 어떤 업데이트가 사용자에게 먼저 보이는 것이 중요한지를 이해할 수 있습니다. 이는 렌더링의 순수성 덕분에 가능합니다. 컴포넌트가 [렌더링하는 동안](#how-does-react-run-your-code) 사이드 이펙트가 없기 때문에 React는 중요하지 않은 컴포넌트의 렌더링을 일시 중지하고 나중에 필요할 때 다시 돌아올 수 있습니다. +렌더링을 순수하게 유지하면, React는 어떤 업데이트가 사용자에게 먼저 보이는 것이 중요한지를 이해할 수 있습니다. 이는 렌더링의 순수성 덕분에 가능합니다. 컴포넌트가 [렌더링하는 동안](#how-does-react-run-your-code) 사이드 이펙트가 없기 때문에 React는 중요하지 않은 컴포넌트의 렌더링을 일시 중지하고 나중에 필요할 때 다시 돌아올 수 있습니다. 구체적으로, 이는 렌더링 로직을 여러 번 실행할 수 있어 React가 사용자에게 쾌적한 사용자 경험을 제공할 수 있음을 의미합니다. 그러나 [렌더링 중](#how-does-react-run-your-code)에 전역 변수 값을 수정하는 것처럼 컴포넌트에 추적되지 않은 사이드 이펙트가 있는 경우, React가 렌더링 코드를 다시 실행할 때 사이드 이펙트가 원하지 않는 방식으로 트리거될 수 있습니다. 이는 종종 예상치 못한 버그로 이어져 사용자의 앱 경험을 저하할 수 있습니다. [컴포넌트를 순수하게 유지하기](/learn/keeping-components-pure#side-effects-unintended-consequences)에서 이 예시를 볼 수 있습니다. #### React가 코드를 실행하는 방식 {/*how-does-react-run-your-code*/} -React는 선언적입니다. React에 _무엇을_ 렌더링할지 말해주면, React는 사용자에게 _어떻게_ 최적으로 표시할지 알아냅니다. 이를 위해 React는 코드를 실행하는 몇 가지 단계를 거칩니다. React를 잘 사용하기 위해 이 모든 단계를 알 필요는 없습니다. 하지만 높은 수준에서 _렌더링_ 중에 실행되는 코드와 그 외부에서 실행되는 코드에 대해 알아야 합니다. +React는 선언적입니다. React에 _무엇을_ 렌더링할지 말해주면, React는 사용자에게 _어떻게_ 최적으로 표시할지 알아냅니다. 이를 위해 React는 코드를 실행하는 몇 가지 단계를 거칩니다. React를 잘 사용하기 위해 이 모든 단계를 알 필요는 없습니다. 하지만 고수준에서 _렌더링_ 중에 실행되는 코드와 그 외부에서 실행되는 코드에 대해 알아야 합니다. -_렌더링_ 은 UI의 다음 버전이 어떻게 보일지 계산하는 것을 의미합니다. 렌더링 후에 [Effect](/reference/react/useEffect)가 _flushed_ 됩니다(더 이상 남아 있지 않을 때까지 실행됨). 그리고 Effect가 레이아웃에 영향을 미치는 경우 계산을 업데이트할 수 있습니다. React는 새로운 계산을 이전 UI 버전을 만드는 데 사용된 계산과 비교한 다음, 최신 버전과 일치시키기 위해 [DOM](https://developer.mozilla.org/ko/docs/Web/API/Document_Object_Model)(사용자가 실제로 보는 것)에 필요한 최소한의 변경만을 _커밋_ 합니다. +<em>렌더링</em>은 UI의 다음 버전이 어떻게 보일지 계산하는 것을 의미합니다. 렌더링 후에 [Effect](/reference/react/useEffect)가 _flushed_ 됩니다. (더 이상 남아 있지 않을 때까지 실행됨.) 그리고 Effect가 레이아웃에 영향을 미치는 경우, 계산을 업데이트할 수 있습니다. React는 새로운 계산을 이전 UI 버전을 만드는 데 사용된 계산과 비교한 다음, 최신 버전과 일치시키기 위해 [DOM](https://developer.mozilla.org/ko/docs/Web/API/Document_Object_Model)(사용자가 실제로 보는 것)에 필요한 최소한의 변경만을 _커밋_ 합니다. <DeepDive> @@ -38,7 +38,7 @@ _렌더링_ 은 UI의 다음 버전이 어떻게 보일지 계산하는 것을 ```js {2} function Dropdown() { - const selectedItems = new Set(); // 렌더링 중에 생성됩니다 + const selectedItems = new Set(); // 렌더링 중에 생성됩니다. // ... } ``` @@ -49,7 +49,7 @@ function Dropdown() { function Dropdown() { const selectedItems = new Set(); const onSelect = (item) => { - // 이벤트 핸들러 안에 있으므로 사용자가 트리거할 때만 실행됩니다 + // 이벤트 핸들러 안에 있으므로 사용자가 트리거할 때만 실행됩니다. selectedItems.add(item); } } @@ -59,7 +59,7 @@ function Dropdown() { function Dropdown() { const selectedItems = new Set(); useEffect(() => { - // Effect 안에 있으므로 렌더링 후에만 실행됩니다 + // Effect 안에 있으므로 렌더링 후에만 실행됩니다. logForAnalytics(selectedItems); }, [selectedItems]); } @@ -70,9 +70,9 @@ function Dropdown() { ## 컴포넌트와 Hook은 멱등해야 합니다 {/*components-and-hooks-must-be-idempotent*/} -컴포넌트는 항상 props, state, context와 같은 입력에 대해 동일한 출력을 반환해야 합니다. 이를 _멱등성_ 이라고 합니다. [멱등성](https://ko.wikipedia.org/wiki/%EB%A9%B1%EB%93%B1%EB%B2%95%EC%B9%99)은 함수형 프로그래밍에서 널리 사용되는 용어입니다. 이는 동일한 입력으로 해당 코드를 실행할 때마다 [항상 동일한 결과를 얻는 것](learn/keeping-components-pure)을 의미합니다. +컴포넌트는 항상 Props, State, Context와 같은 입력에 대해 동일한 출력을 반환해야 합니다. 이를 <em>멱등성</em>이라고 합니다. [멱등성](https://ko.wikipedia.org/wiki/%EB%A9%B1%EB%93%B1%EB%B2%95%EC%B9%99)은 함수형 프로그래밍에서 널리 사용되는 용어입니다. 이는 동일한 입력으로 해당 코드를 실행할 때마다 [항상 동일한 결과를 얻는 것](learn/keeping-components-pure)을 의미합니다. -이는 _모든_ 코드가 [렌더링 중](#how-does-react-run-your-code)에도 멱등성을 유지해야 한다는 것을 의미합니다. 예를 들어 이 코드 라인은 멱등하지 않습니다(따라서 컴포넌트도 멱등하지 않습니다). +이는 _모든_ 코드가 [렌더링 중](#how-does-react-run-your-code)에도 멱등성을 유지해야 한다는 것을 의미합니다. 예를 들어 다음 코드 라인은 멱등하지 않습니다. (따라서 컴포넌트도 멱등하지 않습니다.) ```js {2} function Clock() { @@ -83,7 +83,7 @@ function Clock() { `new Date()` 함수는 항상 현재 날짜를 반환하고 호출할 때마다 결과가 변경되기 때문에 멱등하지 않습니다. 위 컴포넌트를 렌더링하면 화면에 표시되는 시간이 컴포넌트가 렌더링된 시간에 고정됩니다. 마찬가지로 `Math.random()`과 같은 함수도 멱등하지 않습니다. 입력이 동일해도 호출할 때마다 다른 결과를 반환하기 때문입니다. -이는 `new Date()`와 같은 비멱등 함수를 _전혀_ 사용하지 말아야 한다는 뜻이 아닙니다. 단지 이를 [렌더링 중](#how-does-react-run-your-code)에 사용하지 않아야 한다는 것입니다. 이 경우 [Effect](/reference/react/useEffect)를 사용하여 최신 날짜를 이 컴포넌트에 _동기화_ 할 수 있습니다. +이는 `new Date()`와 같은 비멱등 함수를 _전혀_ 사용하지 말아야 한다는 뜻이 아닙니다. 단지 이를 [렌더링 중](#how-does-react-run-your-code)에 사용하지 않아야 한다는 것입니다. 이 경우 [Effect](/reference/react/useEffect)를 사용하여 최신 날짜를 컴포넌트에 _동기화_ 할 수 있습니다. <Sandpack> @@ -91,7 +91,7 @@ function Clock() { import { useState, useEffect } from 'react'; function useTime() { - // 1. 현재 날짜의 state를 추적합니다. `useState`는 초기 state로 초기화 함수를 받습니다. + // 1. 현재 날짜의 State를 추적합니다. `useState`는 초기 State로 초기화 함수를 받습니다. // 이 함수는 Hook이 호출될 때 한 번만 실행되므로, Hook이 호출되는 시점의 현재 날짜가 // 처음으로 설정됩니다. const [time, setTime] = useState(() => new Date()); @@ -99,9 +99,9 @@ function useTime() { useEffect(() => { // 2. `setInterval`을 사용하여 현재 날짜를 매초마다 업데이트합니다. const id = setInterval(() => { - setTime(new Date()); // ✅ Good: 렌더링에서 비멱등 코드가 더 이상 실행되지 않음 + setTime(new Date()); // ✅ Good: 렌더링에서 비멱등 코드가 더 이상 실행되지 않음. }, 1000); - // 3. `setInterval` 타이머가 누수되지 않도록 cleanup 함수를 반환합니다. + // 3. `setInterval` 타이머가 누수되지 않도록 Cleanup 함수를 반환합니다. return () => clearInterval(id); }, []); @@ -124,29 +124,29 @@ React와 외부 상태를 동기화할 필요가 없다면, 사용자 상호작 ## 사이드 이펙트는 렌더링 외부에서 실행되어야 합니다 {/*side-effects-must-run-outside-of-render*/} -[사이드 이펙트](/learn/keeping-components-pure#side-effects-unintended-consequences)는 React가 최상의 사용자 경험을 제공하기 위해 컴포넌트를 여러 번 렌더링할 수 있기 때문에 [렌더링 중에](#how-does-react-run-your-code) 실행되어서는 안 됩니다. +[사이드 이펙트](/learn/keeping-components-pure#side-effects-unintended-consequences)는 [렌더링 중에](#how-does-react-run-your-code) 실행되어서는 안 됩니다. 이는, React가 최상의 사용자 경험을 제공하기 위해 컴포넌트를 여러 번 렌더링할 수 있기 때문입니다! <Note> -사이드 이펙트는 Effects보다 더 넓은 개념입니다. Effects는 특히 `useEffect` 안에 감싸진 코드를 지칭하는 반면, 사이드 이펙트는 호출자에게 값을 반환하는 것 외에도 어떤 관찰 가능한 효과를 가진 코드를 일반적으로 가리킵니다. +사이드 이펙트는 Effect보다 더 넓은 개념입니다. Effect는 특히 `useEffect` 안에 감싸진 코드를 지칭하는 반면, 사이드 이펙트는 호출자에게 값을 반환하는 기본 결과 외에도 어떤 관찰 가능한 영향을 미치는 코드를 지칭하는 일반적인 용어입니다. -사이드 이펙트는 전형적으로 [이벤트 핸들러](/learn/responding-to-events)나 Effects 안에서 작성됩니다. 하지만 렌더링 중에는 절대로 작성되어서는 안 됩니다. +사이드 이펙트는 일반적으로 [이벤트 핸들러](/learn/responding-to-events)나 Effect 안에서 작성합니다. 하지만 렌더링 중에는 절대로 작성해서는 안 됩니다. </Note> -렌더링은 순수하게 유지되어야 하지만, 화면에 무언가를 보여주는 것처럼 앱이 흥미로운 동작을 하려면 어느 시점에서는 사이드 이펙트가 필요합니다! 이 규칙의 핵심은 사이드 이펙트가 [렌더링 중에](#how-does-react-run-your-code) 실행되어서는 안 된다는 것입니다, React가 컴포넌트를 여러 번 렌더링할 수 있기 때문입니다. 대부분의 경우 [이벤트 핸들러](learn/responding-to-events)를 사용하여 사이드 이펙트를 처리합니다. 이벤트 핸들러를 사용하면 이 코드가 렌더링 중에 실행될 필요가 없다는 것을 React에 명시적으로 알려주어 렌더링을 순수하게 유지합니다. 모든 옵션을 다 시도해 보고 나서도 해결되지 않는 경우, 그리고 정말 최후의 수단으로만, `useEffect`를 사용하여 사이드 이펙트를 처리할 수도 있습니다. +렌더링은 순수하게 유지되어야 하지만, 화면에 무언가를 보여주는 것처럼 앱이 흥미로운 동작을 하려면 어느 시점에서는 사이드 이펙트가 필요합니다! 이 규칙의 핵심은 React가 컴포넌트를 여러 번 렌더링할 수 있기 때문에, 사이드 이펙트가 [렌더링 중에](#how-does-react-run-your-code) 실행되어서는 안 된다는 것입니다. 대부분의 경우 [이벤트 핸들러](learn/responding-to-events)를 사용하여 사이드 이펙트를 처리합니다. 이벤트 핸들러를 사용하면 이 코드가 렌더링 중에 실행될 필요가 없다는 것을 React에 명시적으로 알려주어 렌더링을 순수하게 유지합니다. 모든 옵션을 다 시도해 보고 나서도 해결되지 않는 경우, 정말 최후의 수단으로 `useEffect`를 사용하여 사이드 이펙트를 처리할 수도 있습니다. ### 변경이 허용되는 경우 {/*mutation*/} #### 지역 변경 {/*local-mutation*/} -사이드 이펙트의 일반적인 예로 변경(mutation)이 있습니다. 자바스크립트에서 변경은 [원시 값](https://developer.mozilla.org/ko/docs/Glossary/Primitive)이 아닌 값을 변경하는 것을 의미합니다. 흔히 변경은 React에서 권장하지 않지만, _지역_ 변경은 전혀 문제가 되지 않습니다. +사이드 이펙트의 일반적인 예로 변경<sup>Mutation</sup>이 있습니다. 자바스크립트에서 변경은 [원시 값](https://developer.mozilla.org/ko/docs/Glossary/Primitive)이 아닌 값을 변경하는 것을 의미합니다. 흔히 React에서는 변경을 권장하지 않지만, _지역_ 변경은 전혀 문제가 되지 않습니다. ```js {2,7} function FriendList({ friends }) { - const items = []; // ✅ Good: 지역 변수로 생성됨 + const items = []; // ✅ Good: 지역 변수로 생성됨. for (let i = 0; i < friends.length; i++) { const friend = friends[i]; items.push( <Friend key={friend.id} friend={friend} /> - ); // ✅ Good: 지역 변경은 괜찮습니다 + ); // ✅ Good: 지역 변경은 괜찮습니다. } return <section>{items}</section>; } @@ -154,18 +154,18 @@ function FriendList({ friends }) { 지역 변경을 피하고자 코드를 비틀 필요는 없습니다. [`Array.map`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/map)을 사용하여 간결하게 만들 수도 있지만, 지역 배열을 생성한 다음 [렌더링 중](#how-does-react-run-your-code)에 항목을 추가하는 것은 전혀 문제가 되지 않습니다. -비록 `items`를 변경시키는 것처럼 보이지만, 이 코드가 _지역에서만_ 변경한다는 점이 중요합니다. 즉 이 변경은 컴포넌트가 다시 렌더링될 때 "기억되지" 않습니다. `items`는 컴포넌트가 존재하는 동안에만 유지됩니다. `<FriendList />`가 렌더링 될 때마다 `items`는 항상 _재생성_ 되므로, 컴포넌트는 항상 동일한 결과를 반환합니다. +비록 `items`를 변경시키는 것처럼 보이지만, 이 코드를 _지역에서만_ 변경한다는 점이 중요합니다. 즉 이 변경은 컴포넌트가 다시 렌더링될 때 "기억되지" 않습니다. `items`는 컴포넌트가 존재하는 동안에만 유지됩니다. `<FriendList />`가 렌더링 될 때마다 `items`는 항상 _재생성_ 되므로, 컴포넌트는 항상 동일한 결과를 반환합니다. 반면 `items`가 컴포넌트 외부에서 생성되면 이전 값을 유지하고 변경 사항을 기억합니다. ```js {1,7} -const items = []; // 🔴 Bad: 컴포넌트 외부에서 생성됨 +const items = []; // 🔴 Bad: 컴포넌트 외부에서 생성됨. function FriendList({ friends }) { for (let i = 0; i < friends.length; i++) { const friend = friends[i]; items.push( <Friend key={friend.id} friend={friend} /> - ); // 🔴 Bad: 렌더링 외부에서 생성된 값을 변경합니다 + ); // 🔴 Bad: 렌더링 외부에서 생성된 값을 변경합니다. } return <section>{items}</section>; } @@ -186,7 +186,7 @@ function ExpenseForm() { #### DOM 변경 {/*changing-the-dom*/} -사용자에게 직접적으로 보이는 사이드 이펙트는 React 컴포넌트의 렌더링 로직에서 허용되지 않습니다. 즉 단순히 컴포넌트 함수를 호출하는 것만으로 화면에 변화를 일으켜서는 안 됩니다. +사용자에게 직접적으로 보이는 사이드 이펙트는 React 컴포넌트의 렌더링 로직에서 허용되지 않습니다. 즉, 단순히 컴포넌트 함수를 호출하는 것만으로 화면에 변화를 일으켜서는 안 됩니다. ```js {2} function ProductDetailPage({ product }) { @@ -202,42 +202,42 @@ function ProductDetailPage({ product }) { ## Props와 State는 불변입니다 {/*props-and-state-are-immutable*/} -컴포넌트의 props와 state는 불변의 [스냅샷](learn/state-as-a-snapshot)입니다. 직접적으로 변경하면 안 됩니다. 대신 새로운 props를 전달하거나 `useState`에서 제공하는 setter 함수를 사용하세요. +컴포넌트의 Props와 State는 불변의 [스냅샷](learn/state-as-a-snapshot)입니다. 직접적으로 변경하면 안 됩니다. 대신 새로운 Props를 전달하거나 `useState`에서 제공하는 Setter 함수를 사용하세요. -props와 state 값을 렌더링 후에 업데이트되는 스냅샷으로 생각할 수 있습니다. 이러한 이유로 props나 state 변수를 직접 수정하지 않아야 합니다. 새로운 props를 전달하거나 제공된 setter 함수를 사용하여 컴포넌트가 다음 번에 렌더링 될 때 state가 업데이트되어야 함을 React에 알려줍니다. +Props와 State 값을 렌더링 후에 업데이트되는 스냅샷으로 생각할 수 있습니다. 이러한 이유로 Props나 State 변수를 직접 수정하지 않아야 합니다. 새로운 Props를 전달하거나 제공된 Setter 함수를 사용하여 컴포넌트가 다음 번에 렌더링 될 때 State가 업데이트되어야 함을 React에 알려줍니다. ### Props를 변경하지 마세요 {/*props*/} -props는 불변입니다. props를 변경한다면 애플리케이션이 일관성 없는 출력을 생성하게 되며, 상황에 따라 작동할 수도 있고 안 할 수도 있기 때문에 디버깅이 어려워질 수 있습니다. +Props는 불변입니다. Props를 변경한다면 애플리케이션이 일관성 없는 출력을 생성하게 되며, 상황에 따라 작동할 수도 있고 안 할 수도 있기 때문에 디버깅이 어려워질 수 있습니다. ```js {2} function Post({ item }) { - item.url = new Url(item.url, base); // 🔴 Bad: 절대 props를 직접 변경하지 마세요 + item.url = new Url(item.url, base); // 🔴 Bad: 절대 Props를 직접 변경하지 마세요. return <Link url={item.url}>{item.title}</Link>; } ``` ```js {2} function Post({ item }) { - const url = new Url(item.url, base); // ✅ Good: 대신 복사본을 만드세요 + const url = new Url(item.url, base); // ✅ Good: 대신, 복사본을 만드세요. return <Link url={url}>{item.title}</Link>; } ``` ### State를 변경하지 마세요 {/*state*/} -`useState`는 state 변수와 그 state를 변경하기 위한 setter를 반환합니다. +`useState`는 State 변수와 그 State를 변경하기 위한 Setter 함수를 반환합니다. ```js const [stateVariable, setter] = useState(0); ``` -state 변수를 직접 변경하는 대신, `useState`에 의해 반환된 setter 함수를 사용하여 변경해야 합니다. state 변수의 값을 변경하면 컴포넌트가 변경되지 않아 사용자는 이전 UI를 보게 됩니다. setter 함수를 사용하면 React에 state가 변경되었으며 UI를 변경하기 위해 리렌더링을 대기열에 추가해야 한다는 것을 알립니다. +State 변수를 직접 변경하는 대신, `useState`에 의해 반환된 Setter 함수를 사용하여 변경해야 합니다. State 변수의 값을 변경하면 컴포넌트가 변경되지 않아 사용자는 이전 UI를 보게 됩니다. Setter 함수를 사용하면 React에 State가 변경되었으며 UI를 변경하기 위해 리렌더링을 대기열에 추가해야 한다는 것을 알립니다. ```js {5} function Counter() { const [count, setCount] = useState(0); function handleClick() { - count = count + 1; // 🔴 Bad: 절대 state를 직접 변경하지 마세요 + count = count + 1; // 🔴 Bad: 절대 State를 직접 변경하지 마세요. } return ( @@ -268,13 +268,13 @@ function Counter() { ## Hook의 반환값과 인수는 불변입니다 {/*return-values-and-arguments-to-hooks-are-immutable*/} -값이 Hook에 전달되면, 이를 수정해서는 안 됩니다. JSX의 props와 마찬가지로 Hook에 전달된 값은 불변이 됩니다. +값이 Hook에 전달되면, 이를 수정해서는 안 됩니다. JSX의 Props와 마찬가지로 Hook에 전달된 값은 불변입니다. ```js {4} function useIconStyle(icon) { const theme = useContext(ThemeContext); if (icon.enabled) { - icon.className = computeStyle(icon, theme); // 🔴 Bad: 절대 Hook 인수를 직접 변경하지 마세요 + icon.className = computeStyle(icon, theme); // 🔴 Bad: 절대 Hook 인수를 직접 변경하지 마세요. } return icon; } @@ -283,7 +283,7 @@ function useIconStyle(icon) { ```js {3} function useIconStyle(icon) { const theme = useContext(ThemeContext); - const newIcon = { ...icon }; // ✅ Good: 대신 복사본을 만드세요 + const newIcon = { ...icon }; // ✅ Good: 대신 복사본을 만드세요. if (icon.enabled) { newIcon.className = computeStyle(icon, theme); } @@ -310,15 +310,15 @@ function useIconStyle(icon) { Hook 인수를 변경하면 커스텀 Hook의 메모이제이션이 잘못되므로, 이를 피하는 것이 중요합니다. ```js {4} -style = useIconStyle(icon); // `style`은 `icon`을 기준으로 메모이제이션됨 -icon.enabled = false; // Bad: 🔴 절대 Hook 인수를 직접 변경하지 마세요 -style = useIconStyle(icon); // 이전에 메모이제이션된 결과가 반환됨 +style = useIconStyle(icon); // `style`은 `icon`을 기준으로 메모이제이션됨. +icon.enabled = false; // Bad: 🔴 절대 Hook 인수를 직접 변경하지 마세요. +style = useIconStyle(icon); // 이전에 메모이제이션된 결과가 반환됨. ``` ```js {4} -style = useIconStyle(icon); // `style`은 `icon`을 기준으로 메모이제이션됨 -icon = { ...icon, enabled: false }; // Good: ✅ 대신 복사본을 만드세요 -style = useIconStyle(icon); // `style`의 새로운 값이 계산됨 +style = useIconStyle(icon); // `style`은 `icon`을 기준으로 메모이제이션됨. +icon = { ...icon, enabled: false }; // Good: ✅ 대신 복사본을 만드세요. +style = useIconStyle(icon); // `style`의 새로운 값이 계산됨. ``` 마찬가지로 Hook의 반환 값을 수정하지 않는 것이 중요합니다. 반환 값이 메모이제이션되어 있을 수 있기 때문입니다. @@ -335,7 +335,7 @@ JSX를 표현식에서 사용할 때, React는 컴포넌트의 렌더링이 끝 function Page({ colour }) { const styles = { colour, size: "large" }; const header = <Header styles={styles} />; - styles.size = "small"; // 🔴 Bad: styles는 이미 위의 JSX에서 사용되었습니다 + styles.size = "small"; // 🔴 Bad: `styles`는 이미 위의 JSX에서 사용되었습니다. const footer = <Footer styles={styles} />; return ( <> @@ -351,7 +351,7 @@ function Page({ colour }) { function Page({ colour }) { const headerStyles = { colour, size: "large" }; const header = <Header styles={headerStyles} />; - const footerStyles = { colour, size: "small" }; // ✅ Good: 새로운 값을 생성했습니다 + const footerStyles = { colour, size: "small" }; // ✅ Good: 새로운 값을 생성했습니다. const footer = <Footer styles={footerStyles} />; return ( <> From f39068a13ba3fa8cd16a1264257b4bec7b3a7c47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Fri, 3 Jan 2025 17:44:10 +0900 Subject: [PATCH 0490/1164] docs: update `react-calls-components-and-hooks` --- .../rules/react-calls-components-and-hooks.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/content/reference/rules/react-calls-components-and-hooks.md b/src/content/reference/rules/react-calls-components-and-hooks.md index 708cd91f8..58a8a8a51 100644 --- a/src/content/reference/rules/react-calls-components-and-hooks.md +++ b/src/content/reference/rules/react-calls-components-and-hooks.md @@ -13,17 +13,17 @@ React는 사용자 경험을 최적화하기 위해 필요할 때마다 컴포 ## 컴포넌트 함수를 직접 호출하지 마세요 {/*never-call-component-functions-directly*/} 컴포넌트는 JSX에서만 사용해야 합니다. 일반 함수처럼 호출하지 마세요. React가 호출해야 합니다. -React는 [렌더링하는 동안](/reference/rules/components-and-hooks-must-be-pure#how-does-react-run-your-code) 컴포넌트 함수가 언제 호출될지 결정해야 합니다. React에서는 이를 JSX로 수행합니다. +React는 [렌더링하는 동안](/reference/rules/components-and-hooks-must-be-pure#how-does-react-run-your-code) 컴포넌트 함수가 언제 호출될지 결정해야 합니다. React는 이를 JSX로 수행합니다. ```js {2} function BlogPost() { - return <Layout><Article /></Layout>; // ✅ 컴포넌트를 JSX에서만 사용합니다 + return <Layout><Article /></Layout>; // ✅ Good: 컴포넌트를 JSX에서만 사용합니다. } ``` ```js {2} function BlogPost() { - return <Layout>{Article()}</Layout>; // 🔴 컴포넌트 함수를 직접 호출하지 마세요 + return <Layout>{Article()}</Layout>; // 🔴 Bad: 컴포넌트 함수를 직접 호출하지 마세요. } ``` @@ -31,7 +31,7 @@ function BlogPost() { React가 렌더링을 조정하도록 하면 여러 이점이 있습니다. -* **컴포넌트가 함수 이상의 역할을 하게 됩니다.** React는 Hook을 사용해 컴포넌트에 _로컬 상태_ 와 같은 기능을 추가하여, 컴포넌트가 트리 내에서 고유한 정체성을 갖도록 할 수 있습니다. +* **컴포넌트가 함수 이상의 역할을 하게 됩니다.** React는 Hook을 사용해 컴포넌트에 <em>지역 State</em>와 같은 기능을 추가하여, 컴포넌트가 트리 내에서 고유한 정체성을 갖도록 할 수 있습니다. * **컴포넌트 타입이 재조정 과정에 참여합니다.** React가 컴포넌트를 호출하도록 하면 트리의 개념적 구조에 대해 더 많은 정보를 제공하게 됩니다. 예를 들어 `<Feed>`에서 `<Profile>` 페이지로 전환될 때 React는 이를 재사용하려고 하지 않습니다. * **React가 사용자 경험을 향상할 수 있습니다.** 예를 들어 React는 컴포넌트를 호출하는 사이에 브라우저가 일부 작업을 수행할 수 있도록 하여, 큰 컴포넌트 트리를 다시 렌더링하는 것이 메인 스레드를 차단하지 않도록 할 수 있습니다. * **더 나은 디버깅 경험을 제공합니다.** 컴포넌트가 라이브러리에서 일급 객체로 취급되면, 개발 중에 분석할 수 있는 풍부한 개발 도구를 제공할 수 있습니다. @@ -39,11 +39,11 @@ React가 렌더링을 조정하도록 하면 여러 이점이 있습니다. --- -## Hook을 일반 값으로 전달하지 마세요 {/*never-pass-around-hooks-as-regular-values*/} +## Hook을 일반 값처럼 전달하지 마세요 {/*never-pass-around-hooks-as-regular-values*/} Hook은 컴포넌트나 Hook 내부에서만 호출되어야 합니다. Hook을 일반 값처럼 전달하지 마세요. -Hook은 컴포넌트에 React 기능을 추가할 수 있게 합니다. Hook은 항상 함수로 호출되어야 하며 일반 값처럼 전달하면 안 됩니다. Hook을 함수로 호출해야, 개발자가 컴포넌트를 독립적으로 이해할 수 있는 _로컬 추론_ 이 가능합니다. +Hook은 컴포넌트에 React 기능을 추가할 수 있게 합니다. Hook은 항상 함수로 호출되어야 하며 일반 값처럼 전달하면 안 됩니다. Hook을 함수로 호출해야, 개발자가 컴포넌트를 독립적으로 이해할 수 있는 _지역 추론_ 이 가능합니다. 이 규칙을 어기면 React가 컴포넌트를 자동으로 최적화하지 못합니다. @@ -53,7 +53,7 @@ Hook은 가능한 한 "정적"으로 유지되어야 합니다. 이는 Hook을 ```js {2} function ChatInput() { - const useDataWithLogging = withLogging(useData); // 🔴 고차 Hook을 작성하지 마세요 + const useDataWithLogging = withLogging(useData); // 🔴 Bad: 고차 Hook을 작성하지 마세요. const data = useDataWithLogging(); } ``` @@ -62,7 +62,7 @@ Hook은 변경 불가능해야 하며 수정되지 않아야 합니다. Hook을 ```js {2,6} function ChatInput() { - const data = useDataWithLogging(); // ✅ Hook을 새로 작성하세요 + const data = useDataWithLogging(); // ✅ Good: Hook을 새로 작성하세요. } function useDataWithLogging() { @@ -76,7 +76,7 @@ Hook은 동적으로 사용해서도 안 됩니다. 예를 들어 Hook을 값으 ```js {2} function ChatInput() { - return <Button useData={useDataWithLogging} /> // 🔴 Hook을 props로 전달하지 마세요 + return <Button useData={useDataWithLogging} /> // 🔴 Bad: Hook을 Props로 전달하지 마세요. } ``` @@ -88,7 +88,7 @@ function ChatInput() { } function Button() { - const data = useDataWithLogging(); // ✅ Hook을 직접 사용하세요 + const data = useDataWithLogging(); // ✅ Good: Hook을 직접 사용하세요. } function useDataWithLogging() { @@ -96,4 +96,4 @@ function useDataWithLogging() { } ``` -이렇게 하면 `<Button />` 컴포넌트가 훨씬 이해하기 쉽고 디버깅하기도 쉬워집니다. Hook을 동적으로 사용하면 앱의 복잡성이 크게 증가하고, 로컬 추론을 방해하여 장기적으로 팀의 생산성을 저하시킵니다. 또한 Hook을 조건부로 호출하면 안된다는 [Hook의 규칙](/reference/rules/rules-of-hooks)을 실수로 어기기 쉽습니다. 테스트를 위해 컴포넌트를 모킹해야 한다면, 대신 서버를 모킹하여 미리 준비된 데이터에 응답하도록 하는 것이 낫습니다. 가능하다면 앱을 end-to-end 테스트하는 것이 더 효과적입니다. +이렇게 하면 `<Button />` 컴포넌트가 훨씬 이해하기 쉽고 디버깅하기도 쉬워집니다. Hook을 동적으로 사용하면 앱의 복잡성이 크게 증가하고, 지역 추론을 방해하여 장기적으로 팀의 생산성을 저하시킵니다. 또한 Hook을 조건부로 호출하면 안된다는 [Hook의 규칙](/reference/rules/rules-of-hooks)을 실수로 어기기 쉽습니다. 테스트를 위해 컴포넌트를 모킹<sup>Mocking</sup>해야 한다면, 대신 서버를 모킹<sup>Mocking</sup>하여 미리 준비된 데이터에 응답하도록 하는 것이 낫습니다. 가능하다면 앱을 end-to-end 테스트하는 것이 더 효과적입니다. From 0da537ecf0ed0a3913c6722fe76f6d4460f7cb32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Fri, 3 Jan 2025 18:17:24 +0900 Subject: [PATCH 0491/1164] docs: update `rules-of-hooks.md` --- src/content/reference/rules/rules-of-hooks.md | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/content/reference/rules/rules-of-hooks.md b/src/content/reference/rules/rules-of-hooks.md index 26cf1ff14..9ae43ffa6 100644 --- a/src/content/reference/rules/rules-of-hooks.md +++ b/src/content/reference/rules/rules-of-hooks.md @@ -3,7 +3,7 @@ title: Hook의 규칙 --- <Intro> -Hook은 JavaScript 함수로 정의되지만 호출 위치에 제약이 있는 특별한 유형의 재사용 가능한 UI 로직입니다. +Hook은 자바스크립트 함수로 정의되지만 호출 위치에 제약이 있는 특별한 유형의 재사용 가능한 UI 로직입니다. </Intro> <InlineToc /> @@ -12,7 +12,7 @@ Hook은 JavaScript 함수로 정의되지만 호출 위치에 제약이 있는 ## Hook을 최상위 레벨에서만 호출하세요 {/*only-call-hooks-at-the-top-level*/} -React에서는 `use`로 시작하는 함수를 [*Hook*](/reference/react) 이라고 부릅니다. +React에서는 `use`로 시작하는 함수를 [*Hook*](/reference/react)이라고 부릅니다. **Hook을 반복문, 조건문, 중첩 함수, 또는 `try`/`catch`/`finally` 블록 내부에서 호출하지 마세요.** 대신 Hook을 항상 React 함수의 최상위 레벨에서 호출하고, early return 이전에 사용해야 합니다. Hook은 React가 함수 컴포넌트를 렌더링하는 동안에만 호출할 수 있습니다. @@ -21,13 +21,13 @@ React에서는 `use`로 시작하는 함수를 [*Hook*](/reference/react) 이라 ```js{2-3,8-9} function Counter() { - // ✅ 함수 컴포넌트의 최상위 레벨에서 사용합니다 + // ✅ Good: 함수 컴포넌트의 최상위 레벨에서 사용합니다. const [count, setCount] = useState(0); // ... } function useWindowWidth() { - // ✅ 커스텀 Hook의 최상위 레벨에서 사용합니다 + // ✅ Good: 커스텀 Hook의 최상위 레벨에서 사용합니다. const [width, setWidth] = useState(window.innerWidth); // ... } @@ -47,7 +47,7 @@ function useWindowWidth() { ```js{3-4,11-12,20-21} function Bad({ cond }) { if (cond) { - // 🔴 조건부 내부 (수정하려면 외부로 이동하세요!) + // 🔴 Bad: 조건부 내부 (수정하려면 외부로 이동하세요!) const theme = useContext(ThemeContext); } // ... @@ -55,7 +55,7 @@ function Bad({ cond }) { function Bad() { for (let i = 0; i < 10; i++) { - // 🔴 반복문 내부 (수정하려면 외부로 이동하세요!) + // 🔴 Bad: 반복문 내부 (수정하려면 외부로 이동하세요!) const theme = useContext(ThemeContext); } // ... @@ -65,14 +65,14 @@ function Bad({ cond }) { if (cond) { return; } - // 🔴 조건부 return문 이후 (수정하려면 return문 이전으로 이동하세요!) + // 🔴 Bad: 조건부 `return`문 이후 (수정하려면 `return`문 이전으로 이동하세요!) const theme = useContext(ThemeContext); // ... } function Bad() { function handleClick() { - // 🔴 이벤트 핸들러 내부 (수정하려면 외부로 이동하세요!) + // 🔴 Bad: 이벤트 핸들러 내부 (수정하려면 외부로 이동하세요!) const theme = useContext(ThemeContext); } // ... @@ -80,7 +80,7 @@ function Bad() { function Bad() { const style = useMemo(() => { - // 🔴 useMemo 내부 (수정하려면 외부로 이동하세요!) + // 🔴 Bad: `useMemo` 내부 (수정하려면 외부로 이동하세요!) const theme = useContext(ThemeContext); return createStyle(theme); }); @@ -89,7 +89,7 @@ function Bad() { class Bad extends React.Component { render() { - // 🔴 클래스 컴포넌트 내부 (수정하려면 클래스 컴포넌트 대신 함수 컴포넌트를 사용하세요!) + // 🔴 Bad: 클래스 컴포넌트 내부 (수정하려면 클래스 컴포넌트 대신 함수 컴포넌트를 사용하세요!) useEffect(() => {}) // ... } @@ -97,7 +97,7 @@ class Bad extends React.Component { function Bad() { try { - // 🔴 try/catch/finally 블록 내부 (수정하려면 외부로 이동하세요!) + // 🔴 Bad: `try`/`catch`/`finally` 블록 내부 (수정하려면 외부로 이동하세요!) const [x, setX] = useState(0); } catch { const [x, setX] = useState(1); @@ -109,7 +109,7 @@ function Bad() { <Note> -[커스텀 Hook](/learn/reusing-logic-with-custom-hooks)은 다른 Hook을 *호출할 수 있습니다* (그것이 커스텀 Hook의 주된 목적입니다). 커스텀 Hook도 함수 컴포넌트가 렌더링되는 동안에만 호출될 수 있기 때문입니다. +[커스텀 Hook](/learn/reusing-logic-with-custom-hooks)은 다른 Hook을 *호출할 수 있습니다*. (이것이 바로 커스텀 Hook의 주된 목적입니다.) 커스텀 Hook도 함수 컴포넌트가 렌더링되는 동안에만 호출될 수 있기 때문입니다. </Note> @@ -117,7 +117,7 @@ function Bad() { ## Hook을 React 함수에서만 호출하세요 {/*only-call-hooks-from-react-functions*/} -일반 JavaScript 함수에서 Hook을 호출하지 마세요. 대신 다음과 같이 사용할 수 있습니다. +일반 자바스크립트 함수에서 Hook을 호출하지 마세요. 대신 다음과 같이 사용할 수 있습니다. ✅ Hook을 React 함수 컴포넌트에서 호출하세요. ✅ Hook을 [커스텀 Hook](/learn/reusing-logic-with-custom-hooks#extracting-your-own-custom-hook-from-a-component)에서 호출하세요. From d7f4ab7665403a56670859d2bcb1d1064cd3f669 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Fri, 3 Jan 2025 18:30:41 +0900 Subject: [PATCH 0492/1164] docs: update `prerender.md` --- src/content/reference/react-dom/static/prerender.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/content/reference/react-dom/static/prerender.md b/src/content/reference/react-dom/static/prerender.md index 198faea64..bb726683f 100644 --- a/src/content/reference/react-dom/static/prerender.md +++ b/src/content/reference/react-dom/static/prerender.md @@ -73,7 +73,7 @@ On the client, call [`hydrateRoot`](/reference/react-dom/client/hydrateRoot) to ### When should I use `prerender`? {/*when-to-use-prerender*/} -The static `prerender` API is used for static server-side generation (SSG). Unlike `renderToString`, `prerender` waits for all data to load before resolving. This makes it suitable for generating static HTML for a full page, including data that needs to be fetched using Suspense. To stream content as it loads, use a streaming server-side render (SSR) API like [renderToReadableStream](/reference/react-dom/server/renderToReadableStream). +The static `prerender` API is used for static server-side generation (SSG). Unlike `renderToString`, `prerender` waits for all data to load before resolving. This makes it suitable for generating static HTML for a full page, including data that needs to be fetched using Suspense. To stream content as it loads, use a streaming server-side render (SSR) API like [`renderToReadableStream`](/reference/react-dom/server/renderToReadableStream). </Note> @@ -83,7 +83,7 @@ The static `prerender` API is used for static server-side generation (SSG). Unli ### Rendering a React tree to a stream of static HTML {/*rendering-a-react-tree-to-a-stream-of-static-html*/} -Call `prerender` to render your React tree to static HTML into a [Readable Web Stream:](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream): +Call `prerender` to render your React tree to static HTML into a [Readable Web Stream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream): ```js [[1, 4, "<App />"], [2, 5, "['/main.js']"]] import { prerender } from 'react-dom/static'; @@ -229,7 +229,7 @@ async function renderToString() { const {prelude} = await prerender(<App />, { bootstrapScripts: ['/main.js'] }); - + const reader = stream.getReader(); let content = ''; while (true) { @@ -291,7 +291,6 @@ Suspense-enabled data fetching without the use of an opinionated framework is no ### My stream doesn't start until the entire app is rendered {/*my-stream-doesnt-start-until-the-entire-app-is-rendered*/} -The `prerender` response waits for the entire app to finish rendering, including waiting for all suspense boundaries to resolve, before resolving. It is designed for static site generation (SSG) ahead of time and does not support streaming more content as it loads. +The `prerender` response waits for the entire app to finish rendering, including waiting for all suspense boundaries to resolve, before resolving. It is designed for static site generation (SSG) ahead of time and does not support streaming more content as it loads. -To stream content as it loads, use a streaming server render API like [renderToReadableStream](/reference/react-dom/server/renderToReadableStream). - \ No newline at end of file +To stream content as it loads, use a streaming server render API like [`renderToReadableStream`](/reference/react-dom/server/renderToReadableStream). From 9ebd94c856ae01669c5442b3adfa46faf49449ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Fri, 3 Jan 2025 18:39:03 +0900 Subject: [PATCH 0493/1164] docs: update `prerenderToNodeStream.md` --- .../react-dom/static/prerenderToNodeStream.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/content/reference/react-dom/static/prerenderToNodeStream.md b/src/content/reference/react-dom/static/prerenderToNodeStream.md index 039987497..a90ca86b3 100644 --- a/src/content/reference/react-dom/static/prerenderToNodeStream.md +++ b/src/content/reference/react-dom/static/prerenderToNodeStream.md @@ -4,7 +4,7 @@ title: prerenderToNodeStream <Intro> -`prerenderToNodeStream` renders a React tree to a static HTML string using a [Node.js Stream.](https://nodejs.org/api/stream.html). +`prerenderToNodeStream` renders a React tree to a static HTML string using a [Node.js Stream](https://nodejs.org/api/stream.html). ```js const {prelude} = await prerenderToNodeStream(reactNode, options?) @@ -63,7 +63,7 @@ On the client, call [`hydrateRoot`](/reference/react-dom/client/hydrateRoot) to #### Returns {/*returns*/} `prerenderToNodeStream` returns a Promise: -- If rendering the is successful, the Promise will resolve to an object containing: +- If rendering is successful, the Promise will resolve to an object containing: - `prelude`: a [Node.js Stream.](https://nodejs.org/api/stream.html) of HTML. You can use this stream to send a response in chunks, or you can read the entire stream into a string. - If rendering fails, the Promise will be rejected. [Use this to output a fallback shell.](#recovering-from-errors-inside-the-shell) @@ -71,7 +71,7 @@ On the client, call [`hydrateRoot`](/reference/react-dom/client/hydrateRoot) to ### When should I use `prerenderToNodeStream`? {/*when-to-use-prerender*/} -The static `prerenderToNodeStream` API is used for static server-side generation (SSG). Unlike `renderToString`, `prerenderToNodeStream` waits for all data to load before resolving. This makes it suitable for generating static HTML for a full page, including data that needs to be fetched using Suspense. To stream content as it loads, use a streaming server-side render (SSR) API like [renderToReadableStream](/reference/react-dom/server/renderToReadableStream). +The static `prerenderToNodeStream` API is used for static server-side generation (SSG). Unlike `renderToString`, `prerenderToNodeStream` waits for all data to load before resolving. This makes it suitable for generating static HTML for a full page, including data that needs to be fetched using Suspense. To stream content as it loads, use a streaming server-side render (SSR) API like [`renderToReadableStream`](/reference/react-dom/server/renderToReadableStream). </Note> @@ -81,7 +81,7 @@ The static `prerenderToNodeStream` API is used for static server-side generation ### Rendering a React tree to a stream of static HTML {/*rendering-a-react-tree-to-a-stream-of-static-html*/} -Call `prerenderToNodeStream` to render your React tree to static HTML into a [Node.js Stream.](https://nodejs.org/api/stream.html): +Call `prerenderToNodeStream` to render your React tree to static HTML into a [Node.js Stream](https://nodejs.org/api/stream.html): ```js [[1, 5, "<App />"], [2, 6, "['/main.js']"]] import { prerenderToNodeStream } from 'react-dom/static'; @@ -91,7 +91,7 @@ app.use('/', async (request, response) => { const { prelude } = await prerenderToNodeStream(<App />, { bootstrapScripts: ['/main.js'], }); - + response.setHeader('Content-Type', 'text/plain'); prelude.pipe(response); }); @@ -228,7 +228,7 @@ async function renderToString() { const {prelude} = await prerenderToNodeStream(<App />, { bootstrapScripts: ['/main.js'] }); - + return new Promise((resolve, reject) => { let data = ''; prelude.on('data', chunk => { @@ -291,5 +291,5 @@ Suspense-enabled data fetching without the use of an opinionated framework is no The `prerenderToNodeStream` response waits for the entire app to finish rendering, including waiting for all suspense boundaries to resolve, before resolving. It is designed for static site generation (SSG) ahead of time and does not support streaming more content as it loads. -To stream content as it loads, use a streaming server render API like [renderToPipeableStream](/reference/react-dom/server/renderToPipeableStream). - +To stream content as it loads, use a streaming server render API like [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream). + From f222c5d4e7f55de4c23a13b18afd28efdee099ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Fri, 3 Jan 2025 18:51:24 +0900 Subject: [PATCH 0494/1164] docs: update `server/index.md` --- .../reference/react-dom/server/index.md | 37 +++---------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/src/content/reference/react-dom/server/index.md b/src/content/reference/react-dom/server/index.md index c294b6386..1ef5474df 100644 --- a/src/content/reference/react-dom/server/index.md +++ b/src/content/reference/react-dom/server/index.md @@ -4,11 +4,7 @@ title: Server React DOM APIs <Intro> -<<<<<<< HEAD -`react-dom/server` API를 사용하면 React 컴포넌트를 서버에서 HTML로 렌더링할 수 있습니다. 이 API는 앱의 최상위 레벨에 있는 서버에서만 초기 HTML을 생성하는 데 사용됩니다. [프레임워크](/learn/start-a-new-react-project#production-grade-react-frameworks)가 대신 호출할 수도 있습니다. 대부분의 컴포넌트는 이를 가져오거나 사용할 필요가 없습니다. -======= -The `react-dom/server` APIs let you server-side render React components to HTML. These APIs are only used on the server at the top level of your app to generate the initial HTML. A [framework](/learn/start-a-new-react-project#production-grade-react-frameworks) may call them for you. Most of your components don't need to import or use them. ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +`react-dom/server` API를 사용하면 React 컴포넌트를 서버 측에서 HTML로 렌더링할 수 있습니다. 이 API는 앱의 최상위 레벨에 있는 서버에서만 초기 HTML을 생성하는 데 사용됩니다. [프레임워크](/learn/start-a-new-react-project#production-grade-react-frameworks)가 대신 호출할 수도 있습니다. 대부분의 컴포넌트는 이를 가져오거나 사용할 필요가 없습니다. </Intro> @@ -16,20 +12,15 @@ The `react-dom/server` APIs let you server-side render React components to HTML. ## Server APIs for Node.js Streams {/*server-apis-for-nodejs-streams*/} -다음 메서드들은 [Node.js Streams](https://nodejs.org/api/stream.html)이 있는 환경에서만 사용할 수 있습니다: +다음 메서드들은 [Node.js Stream](https://nodejs.org/api/stream.html)이 있는 환경에서만 사용할 수 있습니다. -<<<<<<< HEAD -* [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream)은 React 트리를 pipeable [Node.js Stream.](https://nodejs.org/api/stream.html)로 렌더링합니다. -* [`renderToStaticNodeStream`](/reference/react-dom/server/renderToStaticNodeStream)은 상호작용하지 않는 React 트리를 [Node.js Readable Stream.](https://nodejs.org/api/stream.html#readable-streams)로 렌더링합니다. -======= -* [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream) renders a React tree to a pipeable [Node.js Stream.](https://nodejs.org/api/stream.html) ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +* [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream)은 React 트리를 [Pipeable Node.js Stream](https://nodejs.org/api/stream.html)으로 렌더링합니다. --- ## Server APIs for Web Streams {/*server-apis-for-web-streams*/} -다음 메서드들은 브라우저, Deno 및 일부 최신 엣지 런타임을 포함하는 [Web Streams](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API)이 있는 환경에서만 사용할 수 있습니다: +다음 메서드들은 브라우저, Deno 및 일부 최신 엣지 런타임을 포함하는 [Web Stream](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API)이 있는 환경에서만 사용할 수 있습니다. * [`renderToReadableStream`](/reference/react-dom/server/renderToReadableStream)은 React 트리를 [Readable Web Stream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)으로 렌더링합니다. @@ -37,25 +28,9 @@ The `react-dom/server` APIs let you server-side render React components to HTML. ## Legacy Server APIs for non-streaming environments {/*legacy-server-apis-for-non-streaming-environments*/} -다음 메서드들은 스트림을 지원하지 않는 환경에서 사용할 수 있습니다: +다음 메서드들은 Stream을 지원하지 않는 환경에서 사용할 수 있습니다. * [`renderToString`](/reference/react-dom/server/renderToString)은 React 트리를 문자열로 렌더링합니다. -* [`renderToStaticMarkup`](/reference/react-dom/server/renderToStaticMarkup)은 상호작용하지 않는 React 트리를 HTML 문자열로 렌더링합니다. +* [`renderToStaticMarkup`](/reference/react-dom/server/renderToStaticMarkup)은 상호작용하지 않는 React 트리를 문자열로 렌더링합니다. -<<<<<<< HEAD 위 메서드들은 스트리밍 API와 비교하여 기능이 제한적입니다. - ---- - -## Deprecated server APIs {/*deprecated-server-apis*/} - -<Deprecated> - -이 API는 추후 React major 버전에서 제거될 예정입니다. - -</Deprecated> - -* [`renderToNodeStream`](/reference/react-dom/server/renderToNodeStream)은 React 트리를 [Node.js Readable Stream](https://nodejs.org/api/stream.html#readable-streams)으로 렌더링합니다. (Deprecated.) -======= -They have limited functionality compared to the streaming APIs. ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc From 8ffa5290775dfb4d534e8231588284dc2a29ebe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Fri, 3 Jan 2025 19:27:34 +0900 Subject: [PATCH 0495/1164] docs: update `renderToPipeableStream.md` --- .../server/renderToPipeableStream.md | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/content/reference/react-dom/server/renderToPipeableStream.md b/src/content/reference/react-dom/server/renderToPipeableStream.md index 0f3a78da4..684130fe0 100644 --- a/src/content/reference/react-dom/server/renderToPipeableStream.md +++ b/src/content/reference/react-dom/server/renderToPipeableStream.md @@ -94,7 +94,7 @@ app.use('/', (request, response) => { <CodeStep step={1}>루트 컴포넌트</CodeStep>와 함께 <CodeStep step={2}>부트스트랩 `<script>` 경로 목록</CodeStep>을 제공해야 합니다. 루트 컴포넌트는 **루트 `<html>` 태그를 포함한 전체 문서를 반환해야 합니다.** -예를 들어 다음과 같이 표시될 수 있습니다. +예를 들어 다음과 같이 표시할 수 있습니다. ```js [[1, 1, "App"]] export default function App() { @@ -200,7 +200,7 @@ app.use('/', (request, response) => { }); ``` -위 예시에서 `bootstrapScriptContent` 옵션은 클라이언트에서 전역 `window.assetMap` 변수를 설정하는 추가 인라인 `<script>` 태그를 추가합니다. 이렇게 하면 클라이언트 코드가 동일한 `assetMap`을 읽을 수 있습니다: +위 예시에서 `bootstrapScriptContent` 옵션은 클라이언트에서 전역 `window.assetMap` 변수를 설정하는 추가 인라인 `<script>` 태그를 추가합니다. 이렇게 하면 클라이언트 코드가 동일한 `assetMap`을 읽을 수 있습니다. ```js {4} import { hydrateRoot } from 'react-dom/client'; @@ -276,7 +276,7 @@ function ProfilePage() { } ``` -이 예시에서 React는 페이지 스트리밍을 더 일찍 시작할 수 있습니다. `ProfileLayout`과 `ProfileCover`만 `<Suspense>` 경계로 둘러싸여 있지 않기 때문에 먼저 렌더링을 완료해야 합니다. 하지만 `Sidebar`, `Friends`, `Photos`이 일부 데이터를 로드해야 하는 경우 React는 대신 `BigSpinner` 폴백을 위한 HTML을 전송합니다. 그러면 더 많은 데이터를 사용할 수 있게 되면 모든 데이터가 표시될 때까지 더 많은 콘텐츠가 계속 표시됩니다. +이 예시에서 React는 페이지 스트리밍을 더 일찍 시작할 수 있습니다. `ProfileLayout`과 `ProfileCover`만 `<Suspense>` 경계로 둘러싸여 있지 않기 때문에 먼저 렌더링을 완료해야 합니다. 하지만 `Sidebar`, `Friends`, `Photos`가 일부 데이터를 로드해야 하는 경우, React는 대신 `BigSpinner` 폴백을 위한 HTML을 전송합니다. 그러면 더 많은 데이터를 사용할 수 있게 되면 모든 데이터가 표시될 때까지 더 많은 콘텐츠가 계속 표시됩니다. 스트리밍은 브라우저에서 React 자체가 로드되거나 앱이 상호작용 가능해질 때까지 기다릴 필요가 없습니다. 서버의 HTML 콘텐츠는 `<script>` 태그가 로드되기 전에 점진적으로 표시됩니다. @@ -284,17 +284,17 @@ function ProfilePage() { <Note> -**Suspense 가 활성화된 데이터 소스만 Suspense 컴포넌트를 활성화합니다.** 여기에는 다음이 포함됩니다. +**Suspense가 활성화된 데이터 소스만 Suspense 컴포넌트를 활성화합니다.** 여기에는 다음이 포함됩니다. -- [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/)와 [Next.js](https://nextjs.org/docs/getting-started/react-essentials) 같이 Suspense가 가능한 프레임워크를 사용한 데이터 가져오기 -- [`lazy`](/reference/react/lazy)를 활용한 지연 로딩 컴포넌트 -- [`use`](/reference/react/use)를 사용해서 Promise 값 읽기 +- [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/)와 [Next.js](https://nextjs.org/docs/getting-started/react-essentials) 같은 Suspense가 가능한 프레임워크를 사용한 데이터 가져오기. +- [`lazy`](/reference/react/lazy)를 활용한 지연 로딩 컴포넌트. +- [`use`](/reference/react/use)를 사용해서 Promise 값 읽기. -Suspense 는 이펙트 또는 이벤트 핸들러 내부에서 데이터를 가져올 때를 감지하지 **않습니다.** +Suspense는 이펙트 또는 이벤트 핸들러 내부에서 데이터를 가져올 때를 감지하지 **않습니다.** 위의 `Posts` 컴포넌트에서 데이터를 로드하는 정확한 방법은 프레임워크에 따라 다릅니다. Suspense 지원 프레임워크를 사용하는 경우 해당 데이터 가져오기 문서에서 자세한 내용을 확인할 수 있습니다. -독자적인 프레임워크를 사용하지 않는 Suspense 가능한 데이터 가져오기는 아직 지원되지 않습니다. Suspense 가능한 데이터 소스를 구현하기 위한 요구 사항은 불안정하고 문서화되지 않았습니다. 데이터 소스를 Suspense 와 통합하기 위한 공식 API는 향후 React 버전에서 출시될 예정입니다. +독자적인 프레임워크를 사용하지 않는 Suspense 가능한 데이터 가져오기는 아직 지원되지 않습니다. Suspense 가능한 데이터 소스를 구현하기 위한 요구 사항은 불안정하고 문서화되지 않았습니다. 데이터 소스를 Suspense와 통합하기 위한 공식 API는 향후 React 버전에서 출시될 예정입니다. </Note> @@ -502,8 +502,7 @@ const { pipe } = renderToPipeableStream(<App />, { ### 다양한 오류를 서로 다른 방식으로 처리하기 {/*handling-different-errors-in-different-ways*/} -[자신만의 `Error` 서브 클래스를 생성](https://ko.javascript.info/custom-errors)하고 [`instanceof`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/instanceof) 연산자를 사용해 어떤 에러가 발생하는지 확인할 수 있습니다. -예를 들어 사용자 정의 `NotFoundError`를 정의하고 컴포넌트에서 이를 던질 수 있습니다. 그러면 오류 유형에 따라 `onError`, `onShellReady`, `onShellError` 콜백이 다른 작업을 수행할 수 있습니다. +[자신만의 `Error` 서브 클래스를 생성](https://ko.javascript.info/custom-errors)하고 [`instanceof`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/instanceof) 연산자를 사용해 어떤 에러가 발생하는지 확인할 수 있습니다. 예를 들어, 사용자 정의 `NotFoundError`를 정의하고 컴포넌트에서 이를 던질 수 있습니다. 그러면 오류 유형에 따라 `onError`, `onShellReady`, `onShellError` 콜백이 다른 작업을 수행할 수 있습니다. ```js {2,4-14,19,24,30} let didError = false; From 2a8198670a5805ad58ba5bfff0e885e23f29ea70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Fri, 3 Jan 2025 19:59:25 +0900 Subject: [PATCH 0496/1164] docs: update `renderToReadableStream.md` --- .../server/renderToPipeableStream.md | 20 ++-- .../server/renderToReadableStream.md | 94 +++++++++---------- 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/src/content/reference/react-dom/server/renderToPipeableStream.md b/src/content/reference/react-dom/server/renderToPipeableStream.md index 684130fe0..5890c48a3 100644 --- a/src/content/reference/react-dom/server/renderToPipeableStream.md +++ b/src/content/reference/react-dom/server/renderToPipeableStream.md @@ -16,7 +16,7 @@ const { pipe, abort } = renderToPipeableStream(reactNode, options?) <Note> -이 API는 Node.js 전용입니다. Deno 및 최신 엣지 런타임과 같은 [Web 스트림](https://developer.mozilla.org/ko/docs/Web/API/Streams_API)이 있는 환경에서는 대신 [`renderToReadableStream`](/reference/react-dom/server/renderToReadableStream)을 사용해야 합니다. +이 API는 Node.js 전용입니다. Deno 및 최신 엣지 런타임과 같은 [Web 스트림](https://developer.mozilla.org/ko/docs/Web/API/Streams_API)이 있는 환경에서는 [`renderToReadableStream`](/reference/react-dom/server/renderToReadableStream)을 대신 사용하세요. </Note> @@ -284,17 +284,17 @@ function ProfilePage() { <Note> -**Suspense가 활성화된 데이터 소스만 Suspense 컴포넌트를 활성화합니다.** 여기에는 다음이 포함됩니다. +**Suspense를 지원하는 데이터 소스만 Suspense 컴포넌트를 활성화합니다.** 이는 다음과 같습니다. - [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/)와 [Next.js](https://nextjs.org/docs/getting-started/react-essentials) 같은 Suspense가 가능한 프레임워크를 사용한 데이터 가져오기. - [`lazy`](/reference/react/lazy)를 활용한 지연 로딩 컴포넌트. - [`use`](/reference/react/use)를 사용해서 Promise 값 읽기. -Suspense는 이펙트 또는 이벤트 핸들러 내부에서 데이터를 가져올 때를 감지하지 **않습니다.** +Suspense는 Effect 또는 이벤트 핸들러 내부에서 데이터를 가져올 경우, **이를 감지하지 못합니다.** -위의 `Posts` 컴포넌트에서 데이터를 로드하는 정확한 방법은 프레임워크에 따라 다릅니다. Suspense 지원 프레임워크를 사용하는 경우 해당 데이터 가져오기 문서에서 자세한 내용을 확인할 수 있습니다. +`Posts` 컴포넌트에서 데이터를 불러오는 정확한 방법은 앞서 설명한 프레임워크에 따라 다릅니다. Suspense를 지원하는 프레임워크를 사용하는 경우, 데이터를 가져오는 자세한 방법은 해당 프레임워크 문서에서 찾을 수 있습니다. -독자적인 프레임워크를 사용하지 않는 Suspense 가능한 데이터 가져오기는 아직 지원되지 않습니다. Suspense 가능한 데이터 소스를 구현하기 위한 요구 사항은 불안정하고 문서화되지 않았습니다. 데이터 소스를 Suspense와 통합하기 위한 공식 API는 향후 React 버전에서 출시될 예정입니다. +독자적인 프레임워크를 사용하지 않는 Suspense 지원 데이터 가져오기는 아직 지원하지 않습니다. Suspense를 지원하는 데이터 소스를 구현하기 위한 요구 사항은 불안정하고 문서화되지 않았습니다. 데이터 소스를 Suspense와 통합하기 위한 공식 API는 React의 향후 버전에서 출시할 예정입니다. </Note> @@ -350,9 +350,9 @@ const { pipe } = renderToPipeableStream(<App />, { --- -### 서버에서 크래시 로깅하기 {/*logging-crashes-on-the-server*/} +### 서버에서의 충돌을 기록하기 {/*logging-crashes-on-the-server*/} -기본적으로 서버의 모든 오류는 콘솔에 기록됩니다. 이 동작을 재정의하여 크래시 보고서를 기록할 수 있습니다. +기본적으로 서버의 모든 오류는 콘솔에 기록<sup>Logging</sup>됩니다. 이 동작을 재정의하여 충돌<sup>Crash</sup> 보고서를 기록할 수 있습니다. ```js {7-10} const { pipe } = renderToPipeableStream(<App />, { @@ -437,7 +437,7 @@ function ProfilePage() { 2. 더 이상 서버에서 `Posts` 콘텐츠를 렌더링하는 것을 "포기"합니다. 3. 자바스크립트 코드가 클라이언트에서 로드되면 React는 클라이언트에서 `Posts` 렌더링을 *재시도*합니다. -클라이언트에서 `Posts` 렌더링을 *다시 시도해도* 실패하면 React는 클라이언트에서 에러를 던집니다. 렌더링 중에 발생하는 모든 에러와 마찬가지로, [가장 가까운 부모 에러 경계](/reference/react/Component#static-getderivedstatefromerror)에 따라 사용자에게 에러를 표시하는 방법이 결정됩니다. 실제로는 오류를 복구할 수 없다는 것이 확실해질 때까지 사용자에게 로딩 표시기가 표시된다는 의미입니다. +클라이언트에서 `Posts` 렌더링을 *다시 시도해도* 실패하면 React는 클라이언트에서 오류를 던집니다. 렌더링 중에 발생하는 모든 오류와 마찬가지로, [가장 가까운 부모 오류 경계](/reference/react/Component#static-getderivedstatefromerror)에 따라 사용자에게 오류를 표시하는 방법이 결정됩니다. 실제로는 오류를 복구할 수 없다는 것이 확실해질 때까지 사용자에게 로딩 표시기가 표시된다는 의미입니다. 클라이언트에서 `Posts` 렌더링을 다시 시도하여 성공하면 서버의 로딩 폴백이 클라이언트 렌더링 출력으로 대체됩니다. 사용자는 서버 오류가 발생했다는 사실을 알 수 없습니다. 그러나 서버 `onError` 콜백 및 클라이언트 [`onRecoverableError`](/reference/react-dom/client/hydrateRoot#hydrateroot) 콜백이 실행되어 오류에 대한 알림을 받을 수 있습니다. @@ -469,7 +469,7 @@ const { pipe } = renderToPipeableStream(<App />, { }); ``` -셸 *외부*(즉, `<Suspense>` 경계 안쪽)에 있는 컴포넌트가 에러를 던져도 React는 렌더링을 멈추지 않습니다. 즉, `onError` 콜백이 실행되지만 `onShellError` 대신 `onShellReady`가 반환됩니다. 이는 [위에서 설명한 것처럼](#recovering-from-errors-outside-the-shell) React가 클라이언트에서 해당 오류를 복구하려고 시도하기 때문입니다. +셸 *외부*(즉, `<Suspense>` 경계 안쪽)에 있는 컴포넌트가 오류를 던져도 React는 렌더링을 멈추지 않습니다. 즉, `onError` 콜백이 실행되지만 `onShellError` 대신 `onShellReady`가 반환됩니다. 이는 [위에서 설명한 것처럼](#recovering-from-errors-outside-the-shell) React가 클라이언트에서 해당 오류를 복구하려고 시도하기 때문입니다. 그러나 원하는 경우 오류가 발생했다는 사실을 사용하여 상태 코드를 설정할 수 있습니다. @@ -502,7 +502,7 @@ const { pipe } = renderToPipeableStream(<App />, { ### 다양한 오류를 서로 다른 방식으로 처리하기 {/*handling-different-errors-in-different-ways*/} -[자신만의 `Error` 서브 클래스를 생성](https://ko.javascript.info/custom-errors)하고 [`instanceof`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/instanceof) 연산자를 사용해 어떤 에러가 발생하는지 확인할 수 있습니다. 예를 들어, 사용자 정의 `NotFoundError`를 정의하고 컴포넌트에서 이를 던질 수 있습니다. 그러면 오류 유형에 따라 `onError`, `onShellReady`, `onShellError` 콜백이 다른 작업을 수행할 수 있습니다. +[자신만의 `Error` 서브 클래스를 생성](https://ko.javascript.info/custom-errors)하고 [`instanceof`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/instanceof) 연산자를 사용해 어떤 오류가 발생하는지 확인할 수 있습니다. 예를 들어, 사용자 정의 `NotFoundError`를 정의하고 컴포넌트에서 이를 던질 수 있습니다. 그러면 오류 유형에 따라 `onError`, `onShellReady`, `onShellError` 콜백이 다른 작업을 수행할 수 있습니다. ```js {2,4-14,19,24,30} let didError = false; diff --git a/src/content/reference/react-dom/server/renderToReadableStream.md b/src/content/reference/react-dom/server/renderToReadableStream.md index 24563d4c1..03db97a2b 100644 --- a/src/content/reference/react-dom/server/renderToReadableStream.md +++ b/src/content/reference/react-dom/server/renderToReadableStream.md @@ -4,7 +4,7 @@ title: renderToReadableStream <Intro> -`renderToReadableStream`는 [Readable Web Stream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)을 이용해 React tree를 그립니다. +`renderToReadableStream`는 [Readable Web Stream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)을 이용해 React 트리를 그립니다. ```js const stream = await renderToReadableStream(reactNode, options?) @@ -16,7 +16,7 @@ const stream = await renderToReadableStream(reactNode, options?) <Note> -이 API는 [Web Streams.](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API)에 의존합니다. Node.js의 경우, [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream)를 대신 사용합니다. +이 API는 [Web Stream](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API)에 의존합니다. Node.js의 경우, [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream)을 대신 사용하세요. </Note> @@ -26,7 +26,7 @@ const stream = await renderToReadableStream(reactNode, options?) ### `renderToReadableStream(reactNode, options?)` {/*rendertoreadablestream*/} -`renderToReadableStream`를 호출해 [Readable Web Stream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)으로 사용자가 작성한 React tree를 HTML처럼 렌더링합니다. +`renderToReadableStream`을 호출하여 React 트리를 HTML로 [Readable Web Stream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)에 렌더링합니다. ```js import { renderToReadableStream } from 'react-dom/server'; @@ -43,7 +43,7 @@ async function handler(request) { 클라이언트에서, [`hydrateRoot`](/reference/react-dom/client/hydrateRoot)를 호출해 서버에서 생성된 HTML을 상호작용 가능하도록 만듭니다. -[아래에서 더 많은 예시를 참고하세요.](#usage) +[아래에서 더 많은 예시를 확인하세요.](#usage) #### 매개변수 {/*parameters*/} @@ -56,7 +56,7 @@ async function handler(request) { * **optional** `identifierPrefix`: React가 ID로서 사용할 문자열 앞머리로 [`useId`](/reference/react/useId)로 생성된 문자열입니다. 같은 페이지에서 여러 root를 사용할 때, 각 root간의 충돌을 방지하기 위해 유용합니다. [`hydrateRoot`](/reference/react-dom/client/hydrateRoot#parameters)에 전달한 앞머리와 반드시 동일해야합니다. * **optional** `namespaceURI`: 문자열로 스트림을 위한 기준 [namespace URI](https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS#important_namespace_uris)입니다. 일반 HTML에 해당하는 기본값이 설정되어있습니다. SVG를 위해 `'http://www.w3.org/2000/svg'`를 설정하거나 MathML을 위해 `'http://www.w3.org/1998/Math/MathML'`을 설정할 수 있습니다. * **optional** `nonce`: [`script-src` Content-Security-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src)를 허용하기 위한 [`nonce`](http://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#nonce) (한번만 사용되는) 문자열입니다. - * **optional** `onError`: [회복할 수 있든](#recovering-from-errors-outside-the-shell) 있든 [없든] 상관없이, 서버에서 에러가 발생할 때마다 호출되는 콜백입니다. 기본적으로, 이 콜백은 `console.error`만 호출합니다. [크래시 리포트를 로그하기](#logging-crashes-on-the-server) 위해 오버라이드하거나, [상태 코드를 조정하기](#setting-the-status-code) 위해 오버라이드할 수 있습니다. + * **optional** `onError`: [회복할 수 있든](#recovering-from-errors-outside-the-shell) 있든 [없든] 상관없이, 서버에서 오류가 발생할 때마다 호출되는 콜백입니다. 기본적으로, 이 콜백은 `console.error`만 호출합니다. [크래시 리포트를 로그하기](#logging-crashes-on-the-server) 위해 오버라이드하거나, [상태 코드를 조정하기](#setting-the-status-code) 위해 오버라이드할 수 있습니다. * **optional** `progressiveChunkSize`: 청크의 바이트 수를 설정합니다. [기본 휴리스틱에 대해 더 읽어보기.](https://github.com/facebook/react/blob/14c2be8dac2d5482fda8a0906a31d239df8551fc/packages/react-server/src/ReactFizzServer.js#L210-L225) * **optional** `signal`: [서버 렌더링을 취소](#aborting-server-rendering)하고, 그 나머지를 클라이언트에 렌더링하기 위한 [거절 신호(abort signal)](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)를 설정합니다. @@ -64,8 +64,8 @@ async function handler(request) { `renderToReadableStream`는 [Promise](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise)를 반환합니다. -- [shell](#specifying-what-goes-into-the-shell)렌더링에 성공했다면, 반환된 Promise는 [Readable Web Stream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)으로 해결됩니다. -- [shell](#specifying-what-goes-into-the-shell)렌더링에 실패하면, 반환된 Promise는 취소됩니다. [shell 렌더링에 실패시, 이것을 이용해 실패 결과를 출력하세요.](#recovering-from-errors-inside-the-shell) +- [shell](#specifying-what-goes-into-the-shell) 렌더링에 성공했다면, 반환된 Promise는 [Readable Web Stream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)으로 해결됩니다. +- [shell](#specifying-what-goes-into-the-shell) 렌더링에 실패하면, 반환된 Promise는 취소됩니다. [shell 렌더링에 실패시, 이것을 이용해 실패 결과를 출력하세요.](#recovering-from-errors-inside-the-shell) 반환된 스트림은 다음과 같은 추가적인 프로퍼티를 가지고 있습니다. @@ -75,9 +75,9 @@ async function handler(request) { ## 사용 예시 {/*usage*/} -### Readable Web Stream을 이용해 React tree를 HTML처럼 렌더링하기 {/*rendering-a-react-tree-as-html-to-a-readable-web-stream*/} +### Readable Web Stream을 이용해 React 트리를 HTML처럼 렌더링하기 {/*rendering-a-react-tree-as-html-to-a-readable-web-stream*/} -`renderToReadableStream`를 호출해 [Readable Web Stream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)을 통해 React tree를 HTML처럼 렌더링합니다. +`renderToReadableStream`을 호출해 [Readable Web Stream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)을 통해 React 트리를 HTML로 렌더링합니다. ```js [[1, 4, "<App />"], [2, 5, "['/main.js']"]] import { renderToReadableStream } from 'react-dom/server'; @@ -94,7 +94,7 @@ async function handler(request) { <CodeStep step={1}>root 컴포넌트</CodeStep>와 함께, <CodeStep step={2}>bootstrap `<script>` 경로</CodeStep> 리스트를 제공해야합니다. 제공된 root 컴포넌트는 **최상위 `<html>` 태그를 포함한 모든 문서를 포함해서** 반환되어야 합니다. -예를 들어, 다음과 같은 형태가 되어야 합니다: +예를 들어, 다음과 같은 형태가 되어야 합니다. ```js [[1, 1, "App"]] export default function App() { @@ -114,7 +114,7 @@ export default function App() { } ``` -React는 [doctype](https://developer.mozilla.org/en-US/docs/Glossary/Doctype)와 <CodeStep step={2}>bootstrap `<script>` 태그들</CodeStep>을 결과 HTML 스트림에 주입합니다: +React는 [doctype](https://developer.mozilla.org/en-US/docs/Glossary/Doctype)과 <CodeStep step={2}>bootstrap `<script>` 태그들</CodeStep>을 결과 HTML 스트림에 주입합니다. ```html [[2, 5, "/main.js"]] <!DOCTYPE html> @@ -124,7 +124,7 @@ React는 [doctype](https://developer.mozilla.org/en-US/docs/Glossary/Doctype)와 <script src="/main.js" async=""></script> ``` -클라이언트에선, 추가된 bootstrap 스크립트는 [`hydrateRoot`를 호출해 `document` 전체를 hydrate 해야합니다:](/reference/react-dom/client/hydrateRoot#hydrating-an-entire-document) +클라이언트에선, 추가된 bootstrap 스크립트는 [`hydrateRoot`를 호출해 `document` 전체를 hydrate 해야합니다](/reference/react-dom/client/hydrateRoot#hydrating-an-entire-document). ```js [[1, 4, "<App />"]] import { hydrateRoot } from 'react-dom/client'; @@ -139,9 +139,9 @@ hydrateRoot(document, <App />); #### 빌드 결과물에서 CSS와 JS의 경로 읽어오기 {/*reading-css-and-js-asset-paths-from-the-build-output*/} -JS와 CSS같은 최종 에셋들에 대한 URL들은 종종 빌드 후에 해시됩니다. 예를 들어, `styles.css` 대신 `styles.123456.css`와 같은 형태로 끝날 수 있습니다. 에셋들의 파일명을 해시하는 것은 모든 빌드의 결과물이 각각 다른 파일명을 가지도록 보장합니다. 이는 정적 에셋들에 대한 장기 캐싱을 안전하게 활성화할 수 있도록 해줍니다: 즉, 특정 이름의 파일 내용은 절대 바뀌지 않는 다는 것을 보장합니다. +JS와 CSS같은 최종 에셋들에 대한 URL들은 종종 빌드 후에 해시됩니다. 예를 들어, `styles.css` 대신 `styles.123456.css`와 같은 형태로 끝날 수 있습니다. 에셋들의 파일명을 해시하는 것은 모든 빌드의 결과물이 각각 다른 파일명을 가지도록 보장합니다. 이는 정적 에셋들에 대한 장기 캐싱을 안전하게 활성화할 수 있도록 해줍니다. 즉, 특정 이름의 파일 내용은 절대 바뀌지 않는 다는 것을 보장합니다. -하지만, 빌드 후에 에셋들의 URL을 알 수 없다면, 소스 코드에 URL을 넣을 수 없습니다. 예를 들어, JSX에 `"/styles.css"`를 하드코딩하는 것은 작동하지 않습니다. 소스 코드에 URL을 넣지 않으려면, 루트 컴포넌트는 props로 전달된 맵에서 실제 파일명을 읽어야합니다: +하지만, 빌드 후에 에셋들의 URL을 알 수 없다면, 소스 코드에 URL을 넣을 수 없습니다. 예를 들어, JSX에 `"/styles.css"`를 하드코딩하는 것은 작동하지 않습니다. 소스 코드에 URL을 넣지 않으려면, 루트 컴포넌트는 props로 전달된 맵에서 실제 파일명을 읽어야합니다. ```js {1,6} export default function App({ assetMap }) { @@ -157,7 +157,7 @@ export default function App({ assetMap }) { } ``` -서버에선 `<App assetMap={assetMap} />`을 렌더링하고, 에셋 URL들과 함께 `assetMap`을 전달합니다: +서버에선 `<App assetMap={assetMap} />`을 렌더링하고, 에셋 URL들과 함께 `assetMap`을 전달합니다. ```js {1-5,8,9} // 빌드 도구로부터 이 JSON을 얻어야합니다. 예를 들어, 빌드 결과물에서 읽어올 수 있습니다. @@ -176,7 +176,7 @@ async function handler(request) { } ``` -서버가 `<App assetMap={assetMap} />`를 렌더링한 이후엔, 클라이언트에서도 hydration 에러를 피하기 위해 `assetMap`과 함께 렌더링해야합니다. `assetMap`을 직렬화하고 클라이언트에 전달하기 위해 다음과 같이 할 수 있습니다: +서버가 `<App assetMap={assetMap} />`를 렌더링한 이후엔, 클라이언트에서도 hydration 오류를 피하기 위해 `assetMap`과 함께 렌더링해야합니다. `assetMap`을 직렬화하고 클라이언트에 전달하기 위해 다음과 같이 할 수 있습니다. ```js {9-10} // 빌드 도구로부터 이 JSON을 얻어야합니다. @@ -197,7 +197,7 @@ async function handler(request) { } ``` -위의 예시에서, `bootstrapScriptContent` 옵션은 클라이언트에서 `window.assetMap` 전역 변수를 설정하는 인라인 `<script>` 태그를 추가합니다. 이는 클라이언트 코드가 동일한 `assetMap`을 읽을 수 있게 해줍니다: +위의 예시에서, `bootstrapScriptContent` 옵션은 클라이언트에서 `window.assetMap` 전역 변수를 설정하는 인라인 `<script>` 태그를 추가합니다. 이는 클라이언트 코드가 동일한 `assetMap`을 읽을 수 있게 해줍니다. ```js {4} import { hydrateRoot } from 'react-dom/client'; @@ -206,7 +206,7 @@ import App from './App.js'; hydrateRoot(document, <App assetMap={window.assetMap} />); ``` -클라이언트와 서버는 모두 같은 `assetMap` prop을 이용해 `App`을 렌더링하므로, hydration 에러가 일어나지 않습니다. +클라이언트와 서버는 모두 같은 `assetMap` prop을 이용해 `App`을 렌더링하므로, hydration 오류가 일어나지 않습니다. </DeepDive> @@ -231,7 +231,7 @@ function ProfilePage() { } ``` -`<Posts />`의 데이터를 불러오는데 약간의 시간이 필요하다고 가정해봅시다. 이 경우, 사용자가 포스트 목록을 기다리지 않고도 프로필 페이지의 나머지 컨텐츠를 볼 수 있도록 하고 싶을 것입니다. 이를 위해, [`<Suspense>`를 사용해 `Posts`를 감싸주세요:](/reference/react/Suspense#displaying-a-fallback-while-content-is-loading) +`<Posts />`의 데이터를 불러오는데 약간의 시간이 필요하다고 가정해봅시다. 이 경우, 사용자가 포스트 목록을 기다리지 않고도 프로필 페이지의 나머지 컨텐츠를 볼 수 있도록 하고 싶을 것입니다. 이를 위해, [`<Suspense>`를 사용해 `Posts`를 감싸주세요](/reference/react/Suspense#displaying-a-fallback-while-content-is-loading). ```js {9,11} function ProfilePage() { @@ -252,7 +252,7 @@ function ProfilePage() { 이렇게 하면 React는 `Posts`가 모든 데이터를 불러오기 전까지, HTML 스트리밍을 시작합니다. React는 먼저 로딩 대체 컨텐츠인 `<PostsGlimmer />`를 HTML로 보내고, `Posts`의 데이터 로딩이 완료되면, `<PostsGlimmer />`를 `<Posts />`로 교체할 HTML과 인라인 `<script>` 태그를 함께 보냅니다. 사용자 입장에선, 먼저 `<PostsGlimmer />`를 보고, 후에 `<Posts />`를 보게 됩니다. -더 정밀한 로딩 순서를 만들기 위해 [`<Suspense>` 경계를 중첩](/reference/react/Suspense#revealing-nested-content-as-it-loads) 할 수 있습니다: +더 정밀한 로딩 순서를 만들기 위해 [`<Suspense>` 경계를 중첩](/reference/react/Suspense#revealing-nested-content-as-it-loads)할 수 있습니다. ```js {5,13} function ProfilePage() { @@ -282,17 +282,17 @@ function ProfilePage() { <Note> -Suspense-가능한 데이터 소스만이 Suspense 컴포넌트를 활성화합니다. 이는 다음과 같습니다: +**Suspense를 지원하는 데이터 소스만 Suspense 컴포넌트를 활성화합니다.** 이는 다음과 같습니다. -- [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/)와 [Next.js](https://nextjs.org/docs/getting-started/react-essentials) 같이 Suspense가 가능한 프레임워크를 사용한 데이터 가져오기 -- [`lazy`](/reference/react/lazy)를 활용한 지연 로딩 컴포넌트 -- [`use`](/reference/react/use)를 사용해서 Promise 값 읽기 +- [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/)와 [Next.js](https://nextjs.org/docs/getting-started/react-essentials) 같은 Suspense가 가능한 프레임워크를 사용한 데이터 가져오기. +- [`lazy`](/reference/react/lazy)를 활용한 지연 로딩 컴포넌트. +- [`use`](/reference/react/use)를 사용해서 Promise 값 읽기. -Suspense는 Effect나 이벤트 핸들러 내부에서 데이터를 불러올 경우, **이를, 감지하지 못합니다.** +Suspense는 Effect 또는 이벤트 핸들러 내부에서 데이터를 가져올 경우, **이를 감지하지 못합니다.** -`Posts` 컴포넌트에서 데이터를 불러오는 정확한 방법은, 위에 설명된 프레임워크에 따라 달라집니다. Suspense-가능한 프레임워크를 이용하는 경우, 데이터를 불러오는 방법과 그 자세한 사항은 해당 프레임워크 문서에서 찾으실 수 있습니다. +`Posts` 컴포넌트에서 데이터를 불러오는 정확한 방법은 앞서 설명한 프레임워크에 따라 다릅니다. Suspense를 지원하는 프레임워크를 이용하는 경우, 데이터를 가져오는 자세한 방법은 해당 프레임워크 문서에서 찾을 수 있습니다. -주관적으로 제시된 프레임워크 없이 Suspense-가능한 데이터 불러오기 방법은 아직 지원하지 않습니다. 프레임워크 없이 Suspense-가능한 데이터를 만들고 불러오는 방법은 아직 불안정하고 문서화되지 않았습니다. 데이터 소스를 Suspense와 함께 융합하는 방법은 공식적인 API는 React의 향후 버전에서 지원될 예정입니다. +독자적인 프레임워크를 사용하지 않는 Suspense 지원 데이터 가져오기는 아직 지원하지 않습니다. Suspense를 지원하는 데이터 소스를 구현하기 위한 요구 사항은 불안정하고 문서화되지 않았습니다. 데이터 소스를 Suspense와 통합하기 위한 공식 API는 React의 향후 버전에서 출시할 예정입니다. </Note> @@ -300,7 +300,7 @@ Suspense는 Effect나 이벤트 핸들러 내부에서 데이터를 불러올 ### Specifying what goes into the shell {/*specifying-what-goes-into-the-shell*/} -앱에서 `<Suspense>` 경계 밖에 있는 부분을 *shell*이라고 합니다: +앱에서 `<Suspense>` 경계 밖에 있는 부분을 *shell*이라고 합니다. ```js {3-5,13,14} @@ -322,7 +322,7 @@ function ProfilePage() { } ``` -이는 사용자가 보는 최초의 로딩 상태를 정해줍니다: +이는 사용자가 보는 최초의 로딩 상태를 정해줍니다. ```js {3-5,13} <ProfileLayout> @@ -331,7 +331,7 @@ function ProfilePage() { </ProfileLayout> ``` -만약, `<Suspense>` 경계를 root에 걸어 앱 전체를 감쌌다면, shell은 spinner만을 보여줄 것입니다. 하지만, 이는 사용자 경험에 있어서 좋지 않습니다. 큰 spinner를 보는 것은 비록 더 기다리게 될 지 언정, 실제 레이아웃이 나타나는 것보다 더 느리고 더 짜증나는 경험을 줄 수 있습니다. 이런 이유로 개발자들은 `<Suspense>` 경계를 통해 shell을 전체 페이지 레이아웃의 뼈대처럼 *최소한으로 완성된* 상태이다라는 느낌을 줄 수 있도록 하고 싶을 것입니다. +만약, `<Suspense>` 경계를 root에 걸어 앱 전체를 감쌌다면, shell은 spinner만을 보여줄 것입니다. 하지만, 이는 사용자 경험에 있어서 좋지 않습니다. 큰 spinner를 보는 것은 비록 더 기다리게 될 지 언정, 실제 레이아웃이 나타나는 것보다 더 느리고 더 짜증나는 경험을 줄 수 있습니다. 이런 이유로 개발자들은 `<Suspense>` 경계를 통해 shell을 전체 페이지 레이아웃의 뼈대처럼 *최소한으로 완성된* 상태라는 느낌을 줄 수 있도록 하고 싶을 것입니다. `renderToReadableStream`를 비동기 호출하여 모든 shell이 렌더링될 때까지 `stream`으로 위 문제를 해결합니다. 보통, `stream`을 가진 응답을 생성하고 반환함으로서 스트리밍을 시작합니다. @@ -350,9 +350,9 @@ async function handler(request) { --- -### 서버의 충돌을 로깅하기 {/*logging-crashes-on-the-server*/} +### 서버에서의 충돌을 기록하기 {/*logging-crashes-on-the-server*/} -기본적으로, 서버의 모든 에러는 콘솔에 로깅됩니다. 이 기본 동작을 오버라이드하여 크래시 리포트를 로깅할 수 있습니다: +기본적으로 서버의 모든 오류는 콘솔에 기록<sup>Logging</sup>됩니다. 이 동작을 재정의하여 충돌<sup>Crash</sup> 보고서를 기록할 수 있습니다. ```js {4-7} async function handler(request) { @@ -373,7 +373,7 @@ async function handler(request) { --- -### shell 내부의 에러로부터 회복하기 {/*recovering-from-errors-inside-the-shell*/} +### shell 내부의 오류로부터 회복하기 {/*recovering-from-errors-inside-the-shell*/} 이번 예시에서, shell은 `ProfileLayout`, `ProfileCover` 그리고 `PostsGlimmer`를 포함하고 있습니다. @@ -390,7 +390,7 @@ function ProfilePage() { } ``` -만약, 위의 컴포넌트들을 렌더링하다가 에러가 발생했다면, React는 클라이언트로 보낼 의미있는 HTML을 가지고 있지 않을 것 입니다. 이런 때를 대비해 `renderToReadableStream`을 `try...catch`로 감싸 서버 렌더링에 의존하지 않는 대체 HTML을 보낼 수 있도록 하세요. +만약, 위의 컴포넌트들을 렌더링하다가 오류가 발생했다면, React는 클라이언트로 보낼 의미있는 HTML을 가지고 있지 않을 것 입니다. 이런 때를 대비해 `renderToReadableStream`을 `try...catch`로 감싸 서버 렌더링에 의존하지 않는 대체 HTML을 보낼 수 있도록 하세요. ```js {2,13-18} async function handler(request) { @@ -414,11 +414,11 @@ async function handler(request) { } ``` -shell을 렌더링하면서 에러가 발생한다면, `onError`와 `catch` 블록이 동시에 실행됩니다. `onError`는 에러를 보고하기 위해 사용하고, `catch` 블록은 대체 HTML 문서를 보내기 위해 사용하세요. 대체 HTML은 반드시 에러 페이지일 필요는 없습니다. 대신, 클라이언트에서만 렌더링되는 대체 shell을 포함할 수 있습니다. +shell을 렌더링하면서 오류가 발생한다면, `onError`와 `catch` 블록이 동시에 실행됩니다. `onError`는 오류를 보고하기 위해 사용하고, `catch` 블록은 대체 HTML 문서를 보내기 위해 사용하세요. 대체 HTML은 반드시 오류 페이지일 필요는 없습니다. 대신, 클라이언트에서만 렌더링되는 대체 shell을 포함할 수 있습니다. --- -### shell 외부의 에러로부터 회복하기 {/*recovering-from-errors-outside-the-shell*/} +### shell 외부의 오류로부터 회복하기 {/*recovering-from-errors-outside-the-shell*/} 이번 예시에서, `<Posts />` 컴포넌트는 `<Suspense>`에 감싸져있기 때문에, shell의 일부가 *아닙니다.* @@ -435,15 +435,15 @@ function ProfilePage() { } ``` -`Posts` 컴포넌트 혹은 그 내부 어딘가에서 에러가 발생했을 경우, React는 [에러로 부터 회복하려고 할 것입니다:](/reference/react/Suspense#providing-a-fallback-for-server-errors-and-client-only-content) +`Posts` 컴포넌트 혹은 그 내부 어딘가에서 오류가 발생했을 경우, React는 [오류로 부터 회복하려고 할 것입니다](/reference/react/Suspense#providing-a-fallback-for-server-errors-and-client-only-content). 1. 가장 가까운 `<Suspense>` 경계의 로딩 대체인 (`PostsGlimmer`)를 HTML로 보냅니다. 2. 서버에서 더이상의 `Posts`와 그 내부를 렌더링하는 것을 "포기"합니다. 3. 클라이언트에서 자바스크립트 코드가 로딩되었을 때, React는 `Posts`를 다시 렌더링하려고 시도할 것입니다. -만약 클라이언트에서도 `Posts` 렌더링 재시도가 실패한다면, React는 클라이언트에서 에러를 던지게 됩니다. 렌더링 중에 일어난 모든 에러과 함께, [가장 가까운 부모 에러 경계](/reference/react/Component#static-getderivedstatefromerror)로 사용자에게 어떤 에러를 보여줘야할 지를 결정하게 됩니다. 실제로는, 사용자가 에러가 복구될 수 없다는 것이 확실시 될 때까지 로딩 표시기를 보고있어야 한 다는 것을 의미합니다. +만약 클라이언트에서도 `Posts` 렌더링 재시도가 실패한다면, React는 클라이언트에서 오류를 던지게 됩니다. 렌더링 중에 일어난 모든 오류과 함께, [가장 가까운 부모 오류 경계](/reference/react/Component#static-getderivedstatefromerror)로 사용자에게 어떤 오류를 보여줘야할 지를 결정하게 됩니다. 실제로는, 사용자가 오류가 복구될 수 없다는 것이 확실시 될 때까지 로딩 표시기를 보고있어야 한 다는 것을 의미합니다. -클라이언트에서 `Posts` 렌더링 재시도가 성공하면, 서버에서 온 로딩 대체 HTML이 클라이언트에서 렌더링된 결과로 교체됩니다. 사용자는 서버에서 에러가 있었는지 모를 것입니다. 하지만, 서버의 `onError` 콜백과 클라이언트의 [`onRecoverableError`](/reference/react-dom/client/hydrateRoot#hydrateroot) 콜백은 그대로 실행됩니다. 이를 통해 에러 내용을 받아서 로깅할 수 있습니다. +클라이언트에서 `Posts` 렌더링 재시도가 성공하면, 서버에서 온 로딩 대체 HTML이 클라이언트에서 렌더링된 결과로 교체됩니다. 사용자는 서버에서 오류가 있었는지 모를 것입니다. 하지만, 서버의 `onError` 콜백과 클라이언트의 [`onRecoverableError`](/reference/react-dom/client/hydrateRoot#hydrateroot) 콜백은 그대로 실행됩니다. 이를 통해 오류 내용을 받아서 로깅할 수 있습니다. --- @@ -451,7 +451,7 @@ function ProfilePage() { 스트리밍은 트레이드오프를 동반합니다. 사용자가 컨텐츠를 더 빨리 볼 수 있도록 페이지를 스트리밍하겠지만, 한번 스트리밍을 시작하면, 응답 상태 코드를 설정할 수 없습니다. -앱을 shell(`<Suspense>` 경계 바깥의 모든 것)과 나머지 컨텐츠들로 [나누는 것](#specifying-what-goes-into-the-shell)으로, 이 문제는 이미 해결된 것입니다. 만약 shell에 에러가 있다면, `catch` 블록이 실행되기 때문에, 상태 코드를 설정할 수 있습니다. 혹은, 클라이언트에서 에러가 복구된 다는 것을 알고 있다면, 그냥 "OK"를 보낼 수도 있습니다. +앱을 shell(`<Suspense>` 경계 바깥의 모든 것)과 나머지 컨텐츠들로 [나누는 것](#specifying-what-goes-into-the-shell)으로, 이 문제는 이미 해결된 것입니다. 만약 shell에 오류가 있다면, `catch` 블록이 실행되기 때문에, 상태 코드를 설정할 수 있습니다. 혹은, 클라이언트에서 오류가 복구된 다는 것을 알고 있다면, 그냥 "OK"를 보낼 수도 있습니다. ```js {11} async function handler(request) { @@ -476,9 +476,9 @@ async function handler(request) { } ``` -만약 shell 바깥 (`<Suspense>` 경계의 안쪽)에서 에러가 발생했다면, React는 렌더링을 멈추지 않을 것입니다. 즉, `onError` 콜백은 실행되지만, `catch` 블록은 실행되지 않은 채로 코드가 계속해서 실행된다는 의미입니다. 그 이유는, [위에서 설명했던 것 처럼](#recovering-from-errors-outside-the-shell), React가 클라이언트에서 해당 에러를 복구하려고 하기 때문입니다. +만약 shell 바깥 (`<Suspense>` 경계의 안쪽)에서 오류가 발생했다면, React는 렌더링을 멈추지 않을 것입니다. 즉, `onError` 콜백은 실행되지만, `catch` 블록은 실행되지 않은 채로 코드가 계속해서 실행된다는 의미입니다. 그 이유는, [위에서 설명했던 것 처럼](#recovering-from-errors-outside-the-shell), React가 클라이언트에서 해당 오류를 복구하려고 하기 때문입니다. -하지만, 그래도 상태 코드를 설정하고 싶다면, 오류가 발생했다는 사실을 이용하여 상태 코드를 설정할 수 있습니다: +하지만, 그래도 상태 코드를 설정하고 싶다면, 오류가 발생했다는 사실을 이용하여 상태 코드를 설정할 수 있습니다. ```js {3,7,13} async function handler(request) { @@ -505,13 +505,13 @@ async function handler(request) { } ``` -이는, 초기 shell 콘텐츠를 생성하는 동안 발생한 shell 외부에서 일어난 에러만 잡을 것이므로, 완전한 방법은 아닙니다. 만약, 어떤 컨텐츠가 정말 중요해서 해당 컨텐츠에 발생한 에러를 알고 싶다면, 그것을 shell 안으로 옮겨 에러를 알아낼 수 있습니다. +이는, 초기 shell 콘텐츠를 생성하는 동안 발생한 shell 외부에서 일어난 오류만 잡을 것이므로, 완전한 방법은 아닙니다. 만약, 어떤 컨텐츠가 정말 중요해서 해당 컨텐츠에 발생한 오류를 알고 싶다면, 그것을 shell 안으로 옮겨 오류를 알아낼 수 있습니다. --- -### 각기 다른 방식으로 다른 종류의 에러를 처리하기 {/*handling-different-errors-in-different-ways*/} +### 각기 다른 방식으로 다른 종류의 오류를 처리하기 {/*handling-different-errors-in-different-ways*/} -[`Error` 서브클래스를 직접 만들 수 있고](https://javascript.info/custom-errors), [`instanceof`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof) 연산자를 이용해 어떤 에러가 발생했는지 구별할 수 있습니다. 예를 들어, `NotFoundError`라는 서브클래스를 정의했고 이를 컴포넌트에서 발생시켰다고 한다면, `onError`에서 에러를 저장하고 응답을 반환하기 전에 에러 타입에 따라 다른 동작을 할 수 있습니다: +[`Error` 서브클래스를 직접 만들 수 있고](https://javascript.info/custom-errors), [`instanceof`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof) 연산자를 이용해 어떤 오류가 발생했는지 구별할 수 있습니다. 예를 들어, `NotFoundError`라는 서브클래스를 정의했고 이를 컴포넌트에서 발생시켰다고 한다면, `onError`에서 오류를 저장하고 응답을 반환하기 전에 오류 타입에 따라 다른 동작을 할 수 있습니다. ```js {2-3,5-15,22,28,33} async function handler(request) { @@ -563,7 +563,7 @@ async function handler(request) { 하지만, 크롤러가 이 페이지를 방문했을 때, 혹은 페이지를 빌드했을 때 정적으로 생성한 경우엔 컨텐츠가 점진적으로 드러나는 것이 아니라 모든 컨텐츠가 처음부터 모두 불러와진 다음 최종 HTML 출력물을 생성하는 것을 원할 것입니다. -`stream.allReady` Promise를 기다림으로써 모든 컨텐츠가 로드될 때까지 기다릴 수 있습니다: +`stream.allReady` Promise를 기다림으로써 모든 컨텐츠가 로드될 때까지 기다릴 수 있습니다. ```js {12-15} async function handler(request) { @@ -594,7 +594,7 @@ async function handler(request) { } ``` -일반적인 방문자라면 컨텐츠를 점진적으로 받게 될 것입니다. 크롤러라면, 모든 컨텐츠가 로드될 때까지 기다린 후에 최종 HTML을 받게 될 것입니다. 하지만, 이는 크롤러가 모든 데이터를 받을 때까지 기다려야 한다는 것으로, 그 중에 어떤 데이터가 로드되는데 느리거나 에러가 발생할 수 있는 상황까지 기다려야 한다는 것을 의미합니다. 따라서 앱의 특성에 따라 크롤러에게 shell을 보내는 것이 더 좋을 수도 있습니다. +일반적인 방문자라면 컨텐츠를 점진적으로 받게 될 것입니다. 크롤러라면, 모든 컨텐츠가 로드될 때까지 기다린 후에 최종 HTML을 받게 될 것입니다. 하지만, 이는 크롤러가 모든 데이터를 받을 때까지 기다려야 한다는 것으로, 그 중에 어떤 데이터가 로드되는데 느리거나 오류가 발생할 수 있는 상황까지 기다려야 한다는 것을 의미합니다. 따라서 앱의 특성에 따라 크롤러에게 shell을 보내는 것이 더 좋을 수도 있습니다. --- From d2fd63f505c6dc18f3bb944bb35e58eb819edcbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Fri, 3 Jan 2025 20:16:34 +0900 Subject: [PATCH 0497/1164] docs: update `renderToStaticMarkup.md` --- .../react-dom/server/renderToStaticMarkup.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/content/reference/react-dom/server/renderToStaticMarkup.md b/src/content/reference/react-dom/server/renderToStaticMarkup.md index af49f806a..9345b501a 100644 --- a/src/content/reference/react-dom/server/renderToStaticMarkup.md +++ b/src/content/reference/react-dom/server/renderToStaticMarkup.md @@ -4,7 +4,7 @@ title: renderToStaticMarkup <Intro> -`renderToStaticMarkup` 상호작용하지 않는 React 트리를 HTML 문자열로 렌더링합니다. +`renderToStaticMarkup`은 상호작용하지 않는 React 트리를 HTML 문자열로 렌더링합니다. ```js const html = renderToStaticMarkup(reactNode, options?) @@ -28,7 +28,7 @@ import { renderToStaticMarkup } from 'react-dom/server'; const html = renderToStaticMarkup(<Page />); ``` -상호작용하지 않는 React 컴포넌트의 HTML 출력을 생성합니다. +이는 React 컴포넌트의 상호작용하지 않는 HTML 출력을 생성합니다. [아래 예시를 참고하세요.](#usage) @@ -36,7 +36,7 @@ const html = renderToStaticMarkup(<Page />); * `reactNode`: HTML로 렌더링할 React 노드입니다. 예를 들어, `<Page />`와 같은 JSX 노드입니다. * **optional** `options`: 서버 렌더링을 위한 객체입니다. - * **optional** `identifierPrefix`: [`useId`.](/reference/react/useId)에 의해 생성된 ID에 대해 React가 사용하는 문자열 접두사입니다. 같은 페이지에서 여러 루트를 사용할 때 충돌을 피하기 위해 유용합니다. + * **optional** `identifierPrefix`: [`useId`](/reference/react/useId)에 의해 생성된 ID에 대해 React가 사용하는 문자열 접두사입니다. 같은 페이지에서 여러 루트를 사용할 때 충돌을 피하기 위해 유용합니다. #### 반환값 {/*returns*/} @@ -44,11 +44,11 @@ HTML 문자열을 반환합니다. #### 주의 사항 {/*caveats*/} -* `renderToStaticMarkup`의 출력값은 hydrate 될 수 없습니다. +* `renderToStaticMarkup`의 출력값은 Hydrate 될 수 없습니다. -* `renderToStaticMarkup`은 Suspense를 제한적으로 지원합니다. 만약 suspense 컴포넌트라면, `renderToStaticMarkup`은 즉시 HTML을 fallback으로 보냅니다. +* `renderToStaticMarkup`은 Suspense를 제한적으로 지원합니다. 만약 Suspense 컴포넌트라면, `renderToStaticMarkup`은 즉시 HTML을 Fallback으로 보냅니다. -* `renderToStaticMarkup`은 브라우저에서 동작하지만, 클라이언트 코드에서 사용되는 건 권장하지 않습니다. 브라우저에서 컴포넌트를 HTML로 렌더링해야 하는 경우, [HTML 을 DOM 노드로 렌더링해서 가져오세요.](/reference/react-dom/server/renderToString#removing-rendertostring-from-the-client-code) +* `renderToStaticMarkup`은 브라우저에서 동작하지만, 클라이언트 코드에서 사용하는 것은 권장하지 않습니다. 브라우저에서 컴포넌트를 HTML로 렌더링해야 하는 경우, [HTML을 DOM 노드로 렌더링해서 가져오세요.](/reference/react-dom/server/renderToString#removing-rendertostring-from-the-client-code) --- @@ -56,7 +56,7 @@ HTML 문자열을 반환합니다. ### 상호작용하지 않는 React 트리를 HTML 문자열로 렌더링하기 {/*rendering-a-non-interactive-react-tree-as-html-to-a-string*/} -`renderToStaticMarkup`을 서버 응답과 함께 보낼 수 있는 HTML 문자열로 앱에 렌더링하기 위해 호출하세요: +`renderToStaticMarkup`을 서버 응답과 함께 보낼 수 있는 HTML 문자열로 앱에 렌더링하기 위해 호출하세요. ```js {5-6} import { renderToStaticMarkup } from 'react-dom/server'; @@ -68,12 +68,12 @@ app.use('/', (request, response) => { }); ``` -이것은 React 컴포넌트의 상호작용하지 않는 초기 HTML 결과가 생성됩니다. +이것은 React 컴포넌트의 상호작용하지 않는 초기 HTML 출력을 생성합니다. <Pitfall> -이 메서드는 **hydrate 될 수 없고 상호작용하지 않는 HTML** 을 렌더링합니다. 이 메서드는 React를 간단한 정적 페이지 생성기로 사용하거나 이메일과 같은 완전히 정적인 콘텐츠를 렌더링할 때 유용합니다. +이 메서드는 **Hydrate 될 수 없는 상호작용하지 않는 HTML**을 렌더링합니다. 이 메서드는 React를 간단한 정적 페이지 생성기로 사용하거나, 이메일과 같은 완전히 정적인 콘텐츠를 렌더링할 때 유용합니다. -상호작용을 위한 앱은 서버에서 [`renderToString`](/reference/react-dom/server/renderToString)을, 클라이언트에서 [`hydrateRoot`](/reference/react-dom/client/hydrateRoot)를 사용해야 합니다. +상호작용을 위한 앱은 서버에서 [`renderToString`](/reference/react-dom/server/renderToString), 클라이언트에서는 [`hydrateRoot`](/reference/react-dom/client/hydrateRoot)를 사용해야 합니다. </Pitfall> From f8ae01ad98d020f118784d5d41a6e2de772fe9ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Fri, 3 Jan 2025 20:38:58 +0900 Subject: [PATCH 0498/1164] docs: update `renderToString.md` --- .../react-dom/server/renderToString.md | 48 +++++++------------ 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/src/content/reference/react-dom/server/renderToString.md b/src/content/reference/react-dom/server/renderToString.md index 0bb71bbe3..522fe407c 100644 --- a/src/content/reference/react-dom/server/renderToString.md +++ b/src/content/reference/react-dom/server/renderToString.md @@ -34,15 +34,15 @@ import { renderToString } from 'react-dom/server'; const html = renderToString(<App />); ``` -클라이언트에서 [`hydrateRoot`](/reference/react-dom/client/hydrateRoot)을 호출하면 서버에서 생성된 HTML을 상호작용하게 만듭니다. +클라이언트에서 [`hydrateRoot`](/reference/react-dom/client/hydrateRoot)를 호출하면 서버에서 생성된 HTML을 상호작용하게 만듭니다. -[아래에서 더 많은 예시를 참고하세요.](#usage) +[아래 예시를 참고하세요.](#usage) #### 매개변수 {/*parameters*/} * `reactNode`: HTML로 렌더링할 React 노드입니다. 예를 들어 `<App />`과 같은 JSX 노드입니다. * **optional** `options`: 서버 렌더링을 위한 객체입니다. - * **optional** `identifierPrefix`: [`useId`.](/reference/react/useId)에 의해 생성된 ID에 대해 React가 사용하는 문자열 접두사입니다. 같은 페이지에서 여러 루트를 사용할 때 충돌을 피하기 위해 유용합니다. [`hydrateRoot`.](/reference/react-dom/client/hydrateRoot#parameters)에 전달된 접두사와 동일해야 합니다. + * **optional** `identifierPrefix`: [`useId`](/reference/react/useId)에 의해 생성된 ID에 대해 React가 사용하는 문자열 접두사입니다. 같은 페이지에서 여러 루트를 사용할 때 충돌을 피하기 위해 유용합니다. [`hydrateRoot`.](/reference/react-dom/client/hydrateRoot#parameters)에 전달된 접두사와 동일해야 합니다. #### 반환값 {/*returns*/} @@ -60,7 +60,7 @@ HTML 문자열. ### React 트리를 HTML 문자열로 렌더링하기 {/*rendering-a-react-tree-as-html-to-a-string*/} -서버 응답과 함께 보낼 수 있는 HTML 문자열로 앱을 렌더링하려면 `renderToString`을 호출하세요: +서버 응답과 함께 보낼 수 있는 HTML 문자열로 앱을 렌더링하려면 `renderToString`을 호출하세요. ```js {5-6} import { renderToString } from 'react-dom/server'; @@ -72,7 +72,7 @@ app.use('/', (request, response) => { }); ``` -이렇게 하면 React 컴포넌트의 초기 비대화형 HTML 출력이 생성됩니다. 클라이언트에서 서버에서 생성된 HTML을 *hydrate*하여 상호작용할 수 있도록 [`hydrateRoot`](/reference/react-dom/client/hydrateRoot) 를 실행해야 합니다. +이는 React 컴포넌트의 초기 상호작용하지 않는 HTML 출력을 생성합니다. 클라이언트에서 서버에서 생성된 HTML을 *Hydrate*하여 상호작용할 수 있도록 [`hydrateRoot`](/reference/react-dom/client/hydrateRoot)를 실행해야 합니다. <Pitfall> @@ -85,43 +85,33 @@ app.use('/', (request, response) => { ## 대안 {/*alternatives*/} -<<<<<<< HEAD -### 서버에서 `renderToString`을 스트리밍 함수로 마이그레이션 {/*migrating-from-rendertostring-to-a-streaming-method-on-the-server*/} +### 서버에서 `renderToString`을 스트리밍 렌더링으로 마이그레이션 {/*migrating-from-rendertostring-to-a-streaming-method-on-the-server*/} -`renderToString`은 문자열을 즉시 반환하므로 스트리밍이나 데이터 대기를 지원하지 않습니다. -======= -### Migrating from `renderToString` to a streaming render on the server {/*migrating-from-rendertostring-to-a-streaming-method-on-the-server*/} +`renderToString`은 문자열을 즉시 반환하므로, 로딩 중인 콘텐츠를 스트리밍하는 것을 지원하지 않습니다. -`renderToString` returns a string immediately, so it does not support streaming content as it loads. ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +가능하면 다음과 같은 완전한 기능을 갖춘 대안을 사용하는 것을 권장합니다. -가능하면 다음과 같은 완전한 기능을 갖춘 대안을 사용하는 것을 권장합니다: - -* Node.js를 사용하는 경우 [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream) 을 사용하세요. -* Deno와 최신 엣지 런타임에서 [Web Streams](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API)을 사용하는 경우 [`renderToReadableStream`](/reference/react-dom/server/renderToReadableStream) 을 사용하세요 +* Node.js를 사용하는 경우 [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream)을 사용하세요. +* Deno와 최신 엣지 런타임에서 [Web Stream](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API)을 사용하는 경우 [`renderToReadableStream`](/reference/react-dom/server/renderToReadableStream)을 사용하세요. 서버 환경에서 스트림을 지원하지 않는 경우에도 `renderToString`을 계속 사용할 수 있습니다. --- -<<<<<<< HEAD -### 클라이언트 코드에서 `renderToString` 제거하기 {/*removing-rendertostring-from-the-client-code*/} -======= ### Migrating from `renderToString` to a static prerender on the server {/*migrating-from-rendertostring-to-a-static-prerender-on-the-server*/} `renderToString` returns a string immediately, so it does not support waiting for data to load for static HTML generation. We recommend using these fully-featured alternatives: -* If you use Node.js, use [`prerenderToNodeStream`.](/reference/react-dom/static/prerenderToNodeStream) -* If you use Deno or a modern edge runtime with [Web Streams](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API), use [`prerender`.](/reference/react-dom/static/prerender) +* If you use Node.js, use [`prerenderToNodeStream`](/reference/react-dom/static/prerenderToNodeStream). +* If you use Deno or a modern edge runtime with [Web Streams](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API), use [`prerender`](/reference/react-dom/static/prerender). You can continue using `renderToString` if your static site generation environment does not support streams. --- -### Removing `renderToString` from the client code {/*removing-rendertostring-from-the-client-code*/} ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +### 클라이언트 코드에서 `renderToString` 제거하기 {/*removing-rendertostring-from-the-client-code*/} 클라이언트에서 일부 컴포넌트를 HTML로 변환하기 위해 `renderToString`을 사용하기도 합니다. @@ -133,7 +123,7 @@ const html = renderToString(<MyIcon />); console.log(html); // 예를 들어, "<svg>...</svg>" ``` -**클라이언트에서** `react-dom/server`를 가져오면 불필요하게 번들 크기가 커지므로 피해야 합니다. 브라우저에서 일부 컴포넌트를 HTML로 렌더링해야 할 경우 [`createRoot`](/reference/react-dom/client/createRoot)을 사용하고 DOM에서 HTML을 읽으세요: +**클라이언트에서** `react-dom/server`를 가져오면 불필요하게 번들 크기가 커지므로 피해야 합니다. 브라우저에서 일부 컴포넌트를 HTML로 렌더링해야 할 경우 [`createRoot`](/reference/react-dom/client/createRoot)를 사용하고 DOM에서 HTML을 읽으세요. ```js import { createRoot } from 'react-dom/client'; @@ -157,12 +147,6 @@ console.log(div.innerHTML); // 예를 들어, "<svg>...</svg>" `renderToString`은 Suspense를 완벽하게 지원하지 않습니다. -<<<<<<< HEAD -일부 컴포넌트가 일시 중단되거나 (예를 들어, [`lazy`](/reference/react/lazy)와 함께 정의되거나 데이터를 가져올 때) `renderToString`은 콘텐츠가 해결될 때까지 기다리지 않습니다. `renderToString`는 그 위에 가장 가까운 [`<Suspense>`](/reference/react/Suspense) 경계를 찾아 `fallback` 프로퍼티를 HTML에 렌더링합니다. 내용은 클라이언트 코드가 로드될 때까지 나타나지 않습니다. -======= -If some component suspends (for example, because it's defined with [`lazy`](/reference/react/lazy) or fetches data), `renderToString` will not wait for its content to resolve. Instead, `renderToString` will find the closest [`<Suspense>`](/reference/react/Suspense) boundary above it and render its `fallback` prop in the HTML. The content will not appear until the client code loads. - -To solve this, use one of the [recommended streaming solutions.](#alternatives) For server side rendering, they can stream content in chunks as it resolves on the server so that the user sees the page being progressively filled in before the client code loads. For static site generation, they can wait for all the content to resolve before generating the static HTML. ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +일부 컴포넌트가 일시 중단<sup>Suspend</sup>되거나 (예를 들어, [`lazy`](/reference/react/lazy)와 함께 정의되거나 데이터를 가져올 때) `renderToString`은 콘텐츠가 해결될 때까지 기다리지 않습니다. `renderToString`는 그 위에 가장 가까운 [`<Suspense>`](/reference/react/Suspense) 경계를 찾아 `fallback` 프로퍼티를 HTML에 렌더링합니다. 내용<sup>Content</sup>은 클라이언트 코드가 로드될 때까지 나타나지 않습니다. -이를 해결하기 위해 [권장하는 스트리밍 솔루션](#migrating-from-rendertostring-to-a-streaming-method-on-the-server) 중 하나를 사용하세요. 사용자가 클라이언트 코드가 로드되기 전에 페이지가 점진적으로 채워지는 것을 볼 수 있도록 서버에서 해결할 때 컨텐츠를 청크로 스트리밍할 수 있습니다. +To solve this, use one of the [recommended streaming solutions](#alternatives). For server side rendering, they can stream content in chunks as it resolves on the server so that the user sees the page being progressively filled in before the client code loads. For static site generation, they can wait for all the content to resolve before generating the static HTML. From 4c2a77b8cd10c71703f698fae960eee3e40ae886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Fri, 3 Jan 2025 20:42:08 +0900 Subject: [PATCH 0499/1164] docs: remove `renderToNodeStream.md` and `renderToStaticNodeStream.md` --- .../react-dom/server/renderToNodeStream.md | 78 ------------------ .../server/renderToStaticNodeStream.md | 82 ------------------- 2 files changed, 160 deletions(-) delete mode 100644 src/content/reference/react-dom/server/renderToNodeStream.md delete mode 100644 src/content/reference/react-dom/server/renderToStaticNodeStream.md diff --git a/src/content/reference/react-dom/server/renderToNodeStream.md b/src/content/reference/react-dom/server/renderToNodeStream.md deleted file mode 100644 index d4daf1a4b..000000000 --- a/src/content/reference/react-dom/server/renderToNodeStream.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: renderToNodeStream ---- - -<Deprecated> - -이 API는 향후 React의 주요 버전에서 제거될 예정입니다. 대신 [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream)을 사용하세요. - -</Deprecated> - -<Intro> - -`renderToNodeStream`은 React 트리를 [Node.js Readable Stream.](https://nodejs.org/api/stream.html#readable-streams)으로 렌더링합니다. - -```js -const stream = renderToNodeStream(reactNode, options?) -``` - -</Intro> - -<InlineToc /> - ---- - -## 레퍼런스 {/*reference*/} - -### `renderToNodeStream(reactNode, options?)` {/*rendertonodestream*/} - -서버에서 `renderToNodeStream`을 호출하여 응답으로 연결할 수 있는 [Node.js Readable Stream](https://nodejs.org/api/stream.html#readable-streams)을 가져옵니다. - -```js -import { renderToNodeStream } from 'react-dom/server'; - -const stream = renderToNodeStream(<App />) -stream.pipe(response); -``` - -클라이언트에서 [`hydrateRoot`](/reference/react-dom/client/hydrateRoot)를 호출하여 서버에서 생성된 HTML을 상호작용 가능하도록 만드세요. - -[아래 예시를 참고하세요.](#usage) - -#### 매개변수 {/*parameters*/} - -* `reactNode`: HTML로 렌더링하려는 React 노드입니다. 예를 들어, `<App />`과 같은 JSX 엘리먼트입니다. -* **optional** `options`: 서버 렌더링을 위한 객체입니다. - * **optional** `identifierPrefix`: [`useId`.](/reference/react/useId)에 의해 생성된 ID에 대해 React가 사용하는 문자열 접두사입니다. 같은 페이지에서 여러 루트를 사용할 때 충돌을 피하기 위해 유용합니다. [`hydrateRoot`.](/reference/react-dom/client/hydrateRoot#parameters)에 전달된 접두사와 동일해야 합니다. - -#### 반환값 {/*returns*/} - -HTML 문자열을 출력하는 [Node.js Readable Stream](https://nodejs.org/api/stream.html#readable-streams)를 반환합니다. - -#### 주의 사항 {/*caveats*/} - -* 이 메서드는 출력물을 반환하기 전에 모든 [Suspense boundaries](/reference/react/Suspense))가 완료될 때까지 대기합니다. - -* React 18부터 이 메서드는 모든 출력값을 버퍼링하므로 실제로 스트리밍 이점을 제공하지 않습니다. 따라서 [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream)으로 마이그레이션할 것을 권장합니다. - -* 반환된 스트림은 utf-8로 인코딩된 바이트 스트림입니다. 다른 인코딩 스트림이 필요한 경우 텍스트 변환을 위한 변환 스트림을 제공하는 [iconv-lite](https://www.npmjs.com/package/iconv-lite)와 같은 프로젝트를 살펴보세요. - ---- - -## 사용법 {/*usage*/} - -### React 트리를 HTML로 Node.js Readable Stream에 렌더링하기 {/*rendering-a-react-tree-as-html-to-a-nodejs-readable-stream*/} - -`renderToNodeStream` 을 호출하여 서버 응답으로 연결할 수 있는 [Node.js Readable Stream](https://nodejs.org/api/stream.html#readable-streams)을 가져옵니다. - -```js {5-6} -import { renderToNodeStream } from 'react-dom/server'; - -// 라우트 핸들러 구문은 백엔드 프레임워크에 따라 다릅니다. -app.use('/', (request, response) => { - const stream = renderToNodeStream(<App />); - stream.pipe(response); -}); -``` - -스트림은 React 컴포넌트의 초기에 상호작용하지 않는 HTML 출력을 생성합니다. 클라이언트에서 서버에서 생성된 HTML을 *hydrate* 처리하고 상호작용하도록 하려면 [`hydrateRoot`](/reference/react-dom/client/hydrateRoot)를 호출해야 합니다. diff --git a/src/content/reference/react-dom/server/renderToStaticNodeStream.md b/src/content/reference/react-dom/server/renderToStaticNodeStream.md deleted file mode 100644 index 488f403ba..000000000 --- a/src/content/reference/react-dom/server/renderToStaticNodeStream.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -title: renderToStaticNodeStream ---- - -<Intro> - -`renderToStaticNodeStream`은 상호작용하지 않는 React 트리를 [Node.js Readable Stream](https://nodejs.org/api/stream.html#readable-streams)으로 렌더링합니다. - -```js -const stream = renderToStaticNodeStream(reactNode, options?) -``` - -</Intro> - -<InlineToc /> - ---- - -## 레퍼런스 {/*reference*/} - -### `renderToStaticNodeStream(reactNode, options?)` {/*rendertostaticnodestream*/} - -서버에서 `renderToStaticNodeStream`을 호출하여 [Node.js Readable Stream](https://nodejs.org/api/stream.html#readable-streams)을 불러옵니다. - -```js -import { renderToStaticNodeStream } from 'react-dom/server'; - -const stream = renderToStaticNodeStream(<Page />); -stream.pipe(response); -``` - -[아래에서 더 많은 예시를 참고하세요.](#usage) - -stream은 React 컴포넌트의 상호작용하지 않는 HTML 출력을 생성합니다. - -#### 매개변수 {/*parameters*/} - -* `reactNode`: HTML로 렌더링할 React 노드. 예를 들어 `<Page />` 와 같은 JSX 엘리먼트. -* **optional** `options`: 서버 렌더링을 위한 객체입니다. - * **optional** `identifierPrefix`: [`useId`.](/reference/react/useId)에 의해 생성된 ID에 대해 React가 사용하는 문자열 접두사입니다. 같은 페이지에서 여러 루트를 사용할 때 충돌을 피하기 위해 유용합니다. - -#### 반환값 {/*returns*/} - -HTML 문자열을 출력하는 [Node.js Readable Stream](https://nodejs.org/api/stream.html#readable-streams)입니다. 결과 HTML은 클라이언트에서 hydrate 할 수 없습니다. - -#### 주의 사항 {/*caveats*/} - -* `renderToStaticNodeStream`의 출력값은 hydrate 할 수 없습니다. - -* 이 메서드는 출력값이 반환되기 전에 모든 [Suspense boundaries](/reference/react/Suspense)가 완료되기를 기다립니다. - -* React 18부터 이 메서드는 모든 출력값을 버퍼링하기 때문에 스트리밍의 이점을 제공하지 않습니다. - -* 반환된 스트림은 UTF-8로 인코딩된 바이트 스트림입니다. 다른 방식으로 인코딩된 스트림이 필요하다면, 트랜스코딩을 위한 변환 스트림을 제공하는 [iconv-lite](https://www.npmjs.com/package/iconv-lite)와 같은 프로젝트를 살펴보세요. - ---- - -## 사용법 {/*usage*/} - -### React 트리를 정적 HTML로 Node.js Readable Stream에 렌더링 하기 {/*rendering-a-react-tree-as-static-html-to-a-nodejs-readable-stream*/} - -`renderToStaticNodeStream`을 호출하여 서버 응답으로 파이프 통신 할 수 있는 [Node.js Readable Stream](https://nodejs.org/api/stream.html#readable-streams)을 불러옵니다. - -```js {5-6} -import { renderToStaticNodeStream } from 'react-dom/server'; - -// 라우트 핸들러 문법은 백엔드 프레임워크에 따라 다릅니다. -app.use('/', (request, response) => { - const stream = renderToStaticNodeStream(<Page />); - stream.pipe(response); -}); -``` - -stream은 React 컴포넌트의 상호작용하지 않는 초기 HTML 출력을 생성합니다. - -<Pitfall> - -이 메서드는 **hydrate 될 수 없고 상호작용하지 않는 HTML** 을 렌더링합니다. 이 메서드는 React를 간단한 정적 페이지 생성기로 사용하거나 이메일과 같은 완전히 정적인 콘텐츠를 렌더링할 때 유용합니다. - -상호작용을 위한 앱은 서버에서 [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream)을, 클라이언트에서 [`hydrateRoot`](/reference/react-dom/client/hydrateRoot)를 사용해야 합니다. - -</Pitfall> From 1b108ffc226c55d8adfa6e956a11334b679827c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= <rpfos@naver.com> Date: Fri, 3 Jan 2025 21:02:57 +0900 Subject: [PATCH 0500/1164] docs: delete `findDomNode`, `hydrate`, `render`, `unmountComponentAtNode` for deprecation --- .../reference/react-dom/findDOMNode.md | 435 ------------------ src/content/reference/react-dom/hydrate.md | 201 -------- src/content/reference/react-dom/render.md | 218 --------- .../react-dom/unmountComponentAtNode.md | 112 ----- 4 files changed, 966 deletions(-) delete mode 100644 src/content/reference/react-dom/findDOMNode.md delete mode 100644 src/content/reference/react-dom/hydrate.md delete mode 100644 src/content/reference/react-dom/render.md delete mode 100644 src/content/reference/react-dom/unmountComponentAtNode.md diff --git a/src/content/reference/react-dom/findDOMNode.md b/src/content/reference/react-dom/findDOMNode.md deleted file mode 100644 index 26b04965d..000000000 --- a/src/content/reference/react-dom/findDOMNode.md +++ /dev/null @@ -1,435 +0,0 @@ ---- -title: findDOMNode ---- - -<Deprecated> - -이 API는 향후 React의 주요 버전에서 제거될 예정입니다. [대안들을 살펴보세요.](#alternatives) - -</Deprecated> - -<Intro> - -`findDOMNode`는 React의 [클래스 컴포넌트](/reference/react/Component)에서 브라우저의 DOM 노드를 찾는 방법입니다. - -```js -const domNode = findDOMNode(componentInstance) -``` - -</Intro> - -<InlineToc /> - ---- - -## 레퍼런스 {/*reference*/} - -### `findDOMNode(componentInstance)` {/*finddomnode*/} - -`findDOMNode`를 호출하여 주어진 [클래스 컴포넌트](/reference/react/Component)에서 브라우저의 DOM 노드를 찾습니다. - -```js -import { findDOMNode } from 'react-dom'; - -const domNode = findDOMNode(componentInstance); -``` - -[아래 예시를 참고하세요.](#usage) - -#### 매개변수 {/*parameters*/} - -* `componentInstance`: [`컴포넌트`](/reference/react/Component) 하위 클래스의 인스턴스입니다. 예를 들어 클래스 컴포넌트의 경우 `this`가 포함되어 있습니다. - - -#### 반환값 {/*returns*/} - -`findDOMNode`는 주어진 `componentInstance`에서 가장 처음 등장하는 브라우저 DOM 노드를 반환합니다. 컴포넌트가 `null`이나 `false`를 렌더링할 경우 `findDOMNode`는 `null`을 반환합니다. 컴포넌트가 문자열을 렌더링하면 `findDOMNode`는 그 값을 포함한 텍스트 DOM 노드를 반환합니다. - -#### 주의 사항 {/*caveats*/} - -* 컴포넌트가 배열이나 다수의 자식을 가진 [Fragment](/reference/react/Fragment)를 반환할 수 있습니다. 이런 경우 `findDOMNode`는 해당하는 DOM 노드 중 비어있지 않은 첫 번째 자식을 반환합니다. - -* `findDOMNode`는 컴포넌트가 마운트 되었을 때(즉, 컴포넌트가 DOM에 배치되었을 때)만 동작합니다. 컴포넌트가 아직 마운트 되지 않은 상태에서 호출할 경우 (예시로 컴포넌트가 생성되기 전인 `render()` 내에서 `findDOMNode()`를 호출하는 경우) 예외가 발생합니다. - -* `findDOMNode`는 호출할 당시의 결과만 반환합니다. 이후에 자식 컴포넌트가 다른 노드를 렌더링하더라도, 그 변화에 대해 알 수 없습니다. - -* `findDOMNode`는 클래스 컴포넌트에서만 사용할 수 있습니다. 함수 컴포넌트에서는 사용할 수 없습니다. - ---- - -## 사용법 {/*usage*/} - -### 클래스 컴포넌트의 root DOM 노드를 찾기 {/*finding-the-root-dom-node-of-a-class-component*/} - -[클래스 컴포넌트](/reference/react/Component) 인스턴스에서 `findDOMNode`를 호출하여 (주로 `this`) 이를 렌더링한 DOM 노드를 찾습니다. - -```js {3} -class AutoselectingInput extends Component { - componentDidMount() { - const input = findDOMNode(this); - input.select() - } - - render() { - return <input defaultValue="Hello" /> - } -} -``` - -여기서 `input` 변수는 `<input>` DOM 요소를 값으로 갖게 됩니다. 이제 이것을 통해 작업이 가능해집니다. 예를 들어 "Show example"을 클릭하여 입력창을 마운트하고, [`input.select()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/select)로 입력창의 모든 문자를 선택하도록 합니다. - -<Sandpack> - -```js src/App.js -import { useState } from 'react'; -import AutoselectingInput from './AutoselectingInput.js'; - -export default function App() { - const [show, setShow] = useState(false); - return ( - <> - <button onClick={() => setShow(true)}> - Show example - </button> - <hr /> - {show && <AutoselectingInput />} - </> - ); -} -``` - -```js src/AutoselectingInput.js active -import { Component } from 'react'; -import { findDOMNode } from 'react-dom'; - -class AutoselectingInput extends Component { - componentDidMount() { - const input = findDOMNode(this); - input.select() - } - - render() { - return <input defaultValue="Hello" /> - } -} - -export default AutoselectingInput; -``` - -</Sandpack> - ---- - -## 대안 {/*alternatives*/} - -### ref를 통해 컴포넌트의 DOM 노드 읽기 {/*reading-components-own-dom-node-from-a-ref*/} - -`findDOMNode`를 사용하는 코드는 JSX 노드와 이에 해당하는 코드 사이의 연결이 명시적이지 않아 취약합니다. 예시로 `<input />`를 `<div>`로 감싸보세요. - -<Sandpack> - -```js src/App.js -import { useState } from 'react'; -import AutoselectingInput from './AutoselectingInput.js'; - -export default function App() { - const [show, setShow] = useState(false); - return ( - <> - <button onClick={() => setShow(true)}> - Show example - </button> - <hr /> - {show && <AutoselectingInput />} - </> - ); -} -``` - -```js src/AutoselectingInput.js active -import { Component } from 'react'; -import { findDOMNode } from 'react-dom'; - -class AutoselectingInput extends Component { - componentDidMount() { - const input = findDOMNode(this); - input.select() - } - render() { - return <input defaultValue="Hello" /> - } -} - -export default AutoselectingInput; -``` - -</Sandpack> - -이제 코드가 깨질 텐데, 코드는 `findDOMNode(this)`가 `<input>` DOM 노드를 찾을 것으로 기대하고 있었지만 실제로 찾은 것은 `<div>` DOM 노드이기 때문입니다. 이러한 문제를 방지하기 위해 특정 DOM 노드를 관리할 때는 [`createRef`](/reference/react/createRef)를 사용하세요. - -이 예시에선 `findDOMNode`는 더 이상 사용하지 않습니다. 대신 `inputRef = createRef(null)`를 클래스의 인스턴스 필드에 정의하였습니다. 여기서 `this.inputRef.current`를 통해 DOM 노드를 읽을 수 있습니다. 이것을 JSX에 붙이려면, `<input ref={this.inputRef} />`를 렌더링합니다. 이 작업은 DOM 노드를 사용하는 코드와 JSX를 연결합니다. - -<Sandpack> - -```js src/App.js -import { useState } from 'react'; -import AutoselectingInput from './AutoselectingInput.js'; - -export default function App() { - const [show, setShow] = useState(false); - return ( - <> - <button onClick={() => setShow(true)}> - Show example - </button> - <hr /> - {show && <AutoselectingInput />} - </> - ); -} -``` - -```js src/AutoselectingInput.js active -import { createRef, Component } from 'react'; - -class AutoselectingInput extends Component { - inputRef = createRef(null); - - componentDidMount() { - const input = this.inputRef.current; - input.select() - } - - render() { - return ( - <input ref={this.inputRef} defaultValue="Hello" /> - ); - } -} - -export default AutoselectingInput; -``` - -</Sandpack> - -클래스 컴포넌트를 사용하지 않는 최신 React에서는, [`useRef`](/reference/react/useRef)를 대신 호출하여 동일한 기능을 구현합니다. - -<Sandpack> - -```js src/App.js -import { useState } from 'react'; -import AutoselectingInput from './AutoselectingInput.js'; - -export default function App() { - const [show, setShow] = useState(false); - return ( - <> - <button onClick={() => setShow(true)}> - Show example - </button> - <hr /> - {show && <AutoselectingInput />} - </> - ); -} -``` - -```js src/AutoselectingInput.js active -import { useRef, useEffect } from 'react'; - -export default function AutoselectingInput() { - const inputRef = useRef(null); - - useEffect(() => { - const input = inputRef.current; - input.select(); - }, []); - - return <input ref={inputRef} defaultValue="Hello" /> -} -``` - -</Sandpack> - -[refs를 사용한 DOM 조작에 대해 더 알아보세요.](/learn/manipulating-the-dom-with-refs) - ---- - -### forwarded ref를 사용하여 자식 컴포넌트의 DOM 노드를 읽기 {/*reading-a-child-components-dom-node-from-a-forwarded-ref*/} - -이 예시에서는 `findDOMNode(this)`가 다른 컴포넌트에 속한 DOM 노드를 찾습니다. `AutoselectingInput` 컴포넌트는 브라우저의 `<input>`을 렌더링하는 `MyInput` 컴포넌트를 렌더링합니다. - -<Sandpack> - -```js src/App.js -import { useState } from 'react'; -import AutoselectingInput from './AutoselectingInput.js'; - -export default function App() { - const [show, setShow] = useState(false); - return ( - <> - <button onClick={() => setShow(true)}> - Show example - </button> - <hr /> - {show && <AutoselectingInput />} - </> - ); -} -``` - -```js src/AutoselectingInput.js active -import { Component } from 'react'; -import { findDOMNode } from 'react-dom'; -import MyInput from './MyInput.js'; - -class AutoselectingInput extends Component { - componentDidMount() { - const input = findDOMNode(this); - input.select() - } - render() { - return <MyInput />; - } -} - -export default AutoselectingInput; -``` - -```js src/MyInput.js -export default function MyInput() { - return <input defaultValue="Hello" />; -} -``` - -</Sandpack> - -`AutoselectingInput` 컴포넌트의 내부에서 `findDOMNode(this)`를 호출하면, `<input>`에 대한 JSX가 `MyInput` 컴포넌트 내부에 숨겨져 있더라도 문제없이 `<input>` DOM 노드를 찾아낼 수 있습니다. 이러한 동작이 위 예시에서는 편리해 보일 수 있겠지만, 결국은 취약한 코드로 가는 밑거름이 됩니다. 만약 나중에 코드를 수정하며 `MyInput`을 `<div>`로 감싼다고 생각해 보세요. `<input>`을 찾을 것으로 기대하던 `AutoselectingInput`의 코드를 깨뜨리게 됩니다. - -위 예시의 `findDOMNode`를 대체하려면, 두 컴포넌트가 협력해야 합니다. - -1. `AutoSelectingInput`에서는 ref를 선언해야 하고, [이전의 예시](#reading-components-own-dom-node-from-a-ref)처럼 `<MyInput>`으로 전달합니다. -2. `MyInput`은 [`forwardRef`](/reference/react/forwardRef)로 선언해야 하며, 해당 ref를 가져와 `<input>` 노드로 전달합니다. - -아래 방식으로 사용하면 더 이상 `findDOMNode`가 필요하지 않습니다. - -<Sandpack> - -```js src/App.js -import { useState } from 'react'; -import AutoselectingInput from './AutoselectingInput.js'; - -export default function App() { - const [show, setShow] = useState(false); - return ( - <> - <button onClick={() => setShow(true)}> - Show example - </button> - <hr /> - {show && <AutoselectingInput />} - </> - ); -} -``` - -```js src/AutoselectingInput.js active -import { createRef, Component } from 'react'; -import MyInput from './MyInput.js'; - -class AutoselectingInput extends Component { - inputRef = createRef(null); - - componentDidMount() { - const input = this.inputRef.current; - input.select() - } - - render() { - return ( - <MyInput ref={this.inputRef} /> - ); - } -} - -export default AutoselectingInput; -``` - -```js src/MyInput.js -import { forwardRef } from 'react'; - -const MyInput = forwardRef(function MyInput(props, ref) { - return <input ref={ref} defaultValue="Hello" />; -}); - -export default MyInput; -``` - -</Sandpack> - -클래스 컴포넌트 대신 함수 컴포넌트에서 사용할 때는 이런 코드로 동작합니다. - -<Sandpack> - -```js src/App.js -import { useState } from 'react'; -import AutoselectingInput from './AutoselectingInput.js'; - -export default function App() { - const [show, setShow] = useState(false); - return ( - <> - <button onClick={() => setShow(true)}> - Show example - </button> - <hr /> - {show && <AutoselectingInput />} - </> - ); -} -``` - -```js src/AutoselectingInput.js active -import { useRef, useEffect } from 'react'; -import MyInput from './MyInput.js'; - -export default function AutoselectingInput() { - const inputRef = useRef(null); - - useEffect(() => { - const input = inputRef.current; - input.select(); - }, []); - - return <MyInput ref={inputRef} defaultValue="Hello" /> -} -``` - -```js src/MyInput.js -import { forwardRef } from 'react'; - -const MyInput = forwardRef(function MyInput(props, ref) { - return <input ref={ref} defaultValue="Hello" />; -}); - -export default MyInput; -``` - -</Sandpack> - ---- - -### 감싸주는 `<div>` 요소 추가하기 {/*adding-a-wrapper-div-element*/} - -컴포넌트는 종종 자식의 위치와 크기를 알아야 할 때가 있습니다. 때문에 `findDOMNode(this)`를 사용하여 자식들을 찾고, 측정을 위해 [`getBoundingClientRect`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect)와 같은 DOM 메서드를 사용하게 됩니다. - -이러한 사용 사례에 직접적으로 대응되는 방법이 없기 때문에 `findDOMNode`는 더 이상 사용되지 않음에도 React에서 완전히 사라지지는 않았습니다. 그동안 이를 해결하기 위해 콘텐츠 주위를 `<div>` 노드로 감싸주고, 그 노드의 ref를 가져왔습니다. 하지만, 콘텐츠를 감싸는 요소를 추가하는 방법은 스타일을 손상할 수 있습니다. - -```js -<div ref={someRef}> - {children} -</div> -``` - -이는 특정 항목에 초점을 맞추고 스크롤을 하는 경우에도 적용됩니다. diff --git a/src/content/reference/react-dom/hydrate.md b/src/content/reference/react-dom/hydrate.md deleted file mode 100644 index 9d0a90fc8..000000000 --- a/src/content/reference/react-dom/hydrate.md +++ /dev/null @@ -1,201 +0,0 @@ ---- -title: hydrate ---- - -<Deprecated> - -이 API는 향후 React의 주요 버전에서 제거될 예정입니다. - -`hydrate`는 React 18에서 [`hydrateRoot`](/reference/react-dom/client/hydrateRoot)로 바뀌었습니다. React 18에서 `hydrate`를 사용하면 앱이 React 17을 사용하는 것처럼 동작할 것이라는 경고가 표시됩니다. 더 자세한 내용은 [여기](/blog/2022/03/08/react-18-upgrade-guide#updates-to-client-rendering-apis)를 참고하세요. - -</Deprecated> - -<Intro> - -React 17 이하에서, `hydrate`는 [`react-dom/server`](/reference/react-dom/server)로부터 생성된 React 컴포넌트의 HTML 콘텐츠를 브라우저 DOM 노드에 표시할 수 있도록 해줍니다. - -```js -hydrate(reactNode, domNode, callback?) -``` - -</Intro> - -<InlineToc /> - ---- - -## 레퍼런스 {/*reference*/} - -### `hydrate(reactNode, domNode, callback?)` {/*hydrate*/} - -React 17 이하에서 `hydrate`를 호출하면 React가 서버 환경에서 미리 렌더링한 HTML에 React를 연결(attach)할 수 있습니다. - -```js -import { hydrate } from 'react-dom'; - -hydrate(reactNode, domNode); -``` - -React는 `domNode`에 있는 HTML에 연결되고, 그 내부의 DOM 관리를 맡습니다. React로 빌드된 앱은 보통 `hydrate`를 루트 컴포넌트에서 딱 한 번 실행합니다. - -[더 다양한 예시를 읽어보세요.](#usage) - -#### 매개변수 {/*parameters*/} - -* `reactNode`: HTML을 렌더링하기 위해 사용되는 React 노드입니다. React 17의 `renderToString(<App />)`같은 `ReactDOM Server` 메서드로 렌더링 된 `<App />`처럼, 일반적으로 JSX 조각 형태입니다. - -* `domNode`: 서버에서 루트 요소로 렌더링 된 [DOM 요소](https://developer.mozilla.org/en-US/docs/Web/API/Element)입니다. - -* **optional**: `callback`: 컴포넌트가 hydrate 된 후 호출되는 함수입니다. - -#### 반환값 {/*returns*/} - -`hydrate`는 null을 반환합니다. - -#### 주의 사항 {/*caveats*/} -* `hydrate`는 클라이언트에서 렌더링 된 콘텐츠가 서버에서 렌더링 된 콘텐츠와 동일할 것이라고 예상합니다. 텍스트 콘텐츠의 차이 정도는 React가 조정할 수 있긴 하지만, 불일치는 버그로 간주하고 수정해야 합니다. -* 개발 모드에서 React는 hydration 중 일어난 불일치에 대해 경고합니다. 불일치하는 경우 어트리뷰트 차이가 조정된다는 보장은 없습니다. 이는 성능상의 이유로 중요한데, 대부분의 앱에서 불일치가 발생하는 경우는 드물기 때문에 모든 마크업의 유효성을 검사하는 데 엄청난 비용이 들기 때문입니다. -* 각 앱에서 `hydrate`는 한 번만 실행하세요. 프레임워크를 사용하는 경우 프레임워크가 대신 호출하고 있을 것입니다. -* 앱이 서버에서 렌더링 된 HTML 없이 클라이언트에서만 렌더링 되는 경우엔 `hydrate()`를 사용할 수 없습니다. 이럴 때는 [render()](/reference/react-dom/render)(React 17 이하) 또는 [createRoot()](/reference/react-dom/client/createRoot)(React 18+)를 사용하세요. - ---- - -## 사용법 {/*usage*/} - -`hydrate`로 <CodeStep step={1}>React 컴포넌트</CodeStep>를 서버에서 렌더링 된 <CodeStep step={2}>브라우저 DOM 노드</CodeStep>에 연결하세요. - -```js [[1, 3, "<App />"], [2, 3, "document.getElementById('root')"]] -import { hydrate } from 'react-dom'; - -hydrate(<App />, document.getElementById('root')); -``` - -`hydrate()`로 클라이언트에서만 동작하는 (서버 측에서 렌더링 되는 HTML이 없는) 앱을 만들 순 없습니다. 이럴 때는 [render()](/reference/react-dom/render)(React 17 이하) 또는 [createRoot()](/reference/react-dom/client/createRoot)(React 18+)를 사용하세요. - -### 서버에서 렌더링 된 HTML Hydrate 하기 {/*hydrating-server-rendered-html*/} - -React에서 "hydration"은 React가 서버 환경에서 미리 렌더링한 HTML에 연결하는 방식을 말합니다. 클라이언트에서 hydration이 일어나면 React는 서버에서 생성된 마크업에 이벤트 리스너를 연결하고 앱 렌더링을 이어받으려고 합니다. - -React로 빌드된 앱에서는 **보통 앱이 시작될 때 단 한 번 하나의 루트만 hydate 합니다**. - -<Sandpack> - -```html public/index.html -<!-- - <div id="root">...</div> 내의 HTML 콘텐츠는 - react-dom/server을 통해 App으로부터 생성된 부분입니다. ---> -<div id="root"><h1>Hello, world!</h1></div> -``` - -```js src/index.js active -import './styles.css'; -import { hydrate } from 'react-dom'; -import App from './App.js'; - -hydrate(<App />, document.getElementById('root')); -``` - -```js src/App.js -export default function App() { - return <h1>Hello, world!</h1>; -} -``` - -</Sandpack> - -대부분의 경우 `hydrate`를 다시 호출하거나 다른 곳에서 더 호출할 필요는 없습니다. React는 `hydrate`가 호출된 시점부터 애플리케이션의 DOM을 관리합니다. UI를 업데이트해야 한다면 [state를 사용하면 됩니다.](/reference/react/useState) - -hydration에 대한 더 자세한 내용은 [`hydrateRoot` 문서](/reference/react-dom/client/hydrateRoot)를 참고하세요. - ---- - -### 불가피한 hydration 불일치 에러 무시하기 {/*suppressing-unavoidable-hydration-mismatch-errors*/} - -단일 요소의 어트리뷰트나 텍스트 콘텐츠가 서버와 클라이언트 간 다를 수밖에 없는 경우(예: 타임스탬프), hydration 불일치 경고를 무시하도록 처리할 수 있습니다. - -hydration 경고를 무시하려면 `suppressHydrationWarning={true}`를 추가하세요. - -<Sandpack> - -```html public/index.html -<!-- - <div id="root">...</div> 내의 HTML 콘텐츠는 - react-dom/server을 통해 App으로부터 생성된 부분입니다. ---> -<div id="root"><h1>Current Date: 01/01/2020</h1></div> -``` - -```js src/index.js -import './styles.css'; -import { hydrate } from 'react-dom'; -import App from './App.js'; - -hydrate(<App />, document.getElementById('root')); -``` - -```js src/App.js active -export default function App() { - return ( - <h1 suppressHydrationWarning={true}> - Current Date: {new Date().toLocaleDateString()} - </h1> - ); -} -``` - -</Sandpack> - -이 방법은 한 레벨 깊이에서만 작동하며 임시방편일 뿐입니다. 텍스트 콘텐츠가 아닌 이상 React는 조정을 시도하지 않을 것이므로 향후 업데이트가 있을 때까지 일관적이지 않은 상태로 남을 수 있습니다. 남용하지 마세요. - ---- - -### 서로 다른 클라이언트 및 서버 콘텐츠 처리하기 {/*handling-different-client-and-server-content*/} - -서버와 클라이언트에서 의도적으로 다른 것을 렌더링하는 경우, 투 패스 렌더링(two-pass rendering)을 사용해 볼 수 있습니다. `isClient` 같은 [state variable](/reference/react/useState)를 선언해 [Effect](/reference/react/useEffect)에서 `true`로 바꿔 사용하면 됩니다. - -<Sandpack> - -```html public/index.html -<!-- - <div id="root">...</div> 내의 HTML 콘텐츠는 - react-dom/server을 통해 App으로부터 생성된 부분입니다. ---> -<div id="root"><h1>Is Server</h1></div> -``` - -```js src/index.js -import './styles.css'; -import { hydrate } from 'react-dom'; -import App from './App.js'; - -hydrate(<App />, document.getElementById('root')); -``` - -```js src/App.js active -import { useState, useEffect } from "react"; - -export default function App() { - const [isClient, setIsClient] = useState(false); - - useEffect(() => { - setIsClient(true); - }, []); - - return ( - <h1> - {isClient ? 'Is Client' : 'Is Server'} - </h1> - ); -} -``` - -</Sandpack> - -이렇게 하면 첫 번째 렌더링 패스(render pass)에서 서버와 같은 콘텐츠를 렌더링하므로 불일치를 피할 수 있으면서도, hydration 직후 추가 렌더링 패스가 동기적으로 발생하도록 할 수 있습니다. - -<Pitfall> - -이 방법을 사용하면 컴포넌트가 두 번 렌더링 되어야 하므로 hydration 속도가 느려집니다. 자바스크립트 코드는 초기 HTML 렌더링보다 상당히 늦게 로드될 수 있고, hydration 직후에 다른 UI를 렌더링하면 사용자가 어색하게 느낄 여지가 있습니다. 인터넷 속도가 느린 사용자의 경험에 유의하세요. - -</Pitfall> diff --git a/src/content/reference/react-dom/render.md b/src/content/reference/react-dom/render.md deleted file mode 100644 index 24cfb26b6..000000000 --- a/src/content/reference/react-dom/render.md +++ /dev/null @@ -1,218 +0,0 @@ ---- -title: 렌더링하기 ---- - -<Deprecated> - -이 API는 향후 React 메이저 버전에서 삭제될 예정입니다. - -React 18에서 `render`는 [`createRoot`](/reference/react-dom/client/createRoot)로 교체되었습니다. React 18에서 `render`를 사용하면 앱이 React 17을 실행하는 것처럼 동작하므로 경고를 표시합니다. 자세한 내용은 [클라이언트 렌더링 API 업데이트](/blog/2022/03/08/react-18-upgrade-guide#updates-to-client-rendering-apis)를 참조하세요. - -</Deprecated> - -<Intro> - -`render`는 [JSX](/learn/writing-markup-with-jsx) ("React node")를 브라우저 DOM 노드로 렌더링합니다. - -```js -render(reactNode, domNode, callback?) -``` - -</Intro> - -<InlineToc /> - ---- - -## 레퍼런스 {/*reference*/} - -### `render(reactNode, domNode, callback?)` {/*render*/} - -React 컴포넌트를 브라우저 DOM 요소 내에 표시하려면 `render`를 호출하세요. - -```js -import { render } from 'react-dom'; - -const domNode = document.getElementById('root'); -render(<App />, domNode); -``` - -React는 `domNode` 내에 `<App />`을 표시하고 해당 DOM을 관리합니다. - -보통 React로 완전히 구축된 앱은 `render`를 최상 컴포넌트와 함께 한 번만 호출합니다. 페이지의 "일부분"에 React를 사용하는 경우 필요한 만큼 `render`를 호출할 수 있습니다. - -[아래 예시를 참고하세요.](#usage) - -#### 매개변수 {/*parameters*/} - -* `reactNode`: 표시하려는 *React node*입니다. 보통 `<App />`과 같은 JSX를 사용하지만 [`createElement()`](/reference/react/createElement)로 구성된 React 요소, 문자열, 숫자, `null`, 또는 `undefined`를 전달할 수 있습니다. - -* `domNode`: [DOM 요소](https://developer.mozilla.org/ko/docs/Web/API/Element)입니다. React는 전달한 `reactNode`를 이 DOM 요소 내에 표시합니다. 이후로 React는 `domNode` 내부의 DOM을 관리하고 React 트리가 변경될 때 업데이트합니다. - -* **optional** `callback`: 함수입니다. 전달하면 React는 컴포넌트가 DOM에 배치된 후에 이를 호출합니다. - - -#### 반환값 {/*returns*/} - -`render`는 일반적으로 `null`을 반환합니다. 하지만 전달한 `reactNode`가 *클래스 컴포넌트*인 경우, 해당 컴포넌트의 인스턴스를 반환합니다. - -#### 주의 사항 {/*caveats*/} - -* React 18에서 `render`는 [`createRoot`](/reference/react-dom/client/createRoot)로 교체되었습니다. React 18 이상에서는 `createRoot`를 사용하세요. - -* 처음 `render`를 호출하면 React는 React 컴포넌트를 렌더링하기 전에 해당 `domNode` 내 존재하는 HTML을 모두 초기화합니다. 서버에서 혹은 빌드 중에 React에 의해 생성된 HTML이 `domNode`에 포함되어 있다면 기존 HTML에 이벤트 핸들러를 연결하는 [`hydrate()`](/reference/react-dom/hydrate)를 대신 사용하세요. - -* 동일한 `domNode`에서 `render`를 두 번 이상 호출하면 React는 최신 JSX를 반영하기 위해 필요한 만큼 DOM을 업데이트합니다. React는 이전에 렌더링 된 트리와 ["맞춰보며"](/learn/preserving-and-resetting-state) 재사용할 수 있는 DOM 부분과 재생성해야 하는 DOM 부분을 결정합니다. 동일한 `domNode`에 `render`를 재호출하는 것은 최상단 컴포넌트에서 [`set` 함수](/reference/react/useState#setstate)를 호출하는 것과 유사합니다. React는 불필요한 DOM 업데이트를 방지합니다. - -* 앱 전체가 React로 구축된 경우, `render` 호출은 앱에서 한 번만 발생할 것입니다. (프레임워크를 사용하는 경우, 이 호출을 대신 수행할 수 있습니다) 자식 컴포넌트가 아니라 DOM 트리의 다른 부분(예시: 모달 또는 툴팁)에 JSX를 렌더링하려면 `render` 대신 [`createPortal`](/reference/react-dom/createPortal)을 사용하세요. - ---- - -## 사용법 {/*usage*/} - -<CodeStep step={1}>React 컴포넌트</CodeStep>를 <CodeStep step={2}>브라우저 DOM 노드</CodeStep> 안에 표시하려면 `render`를 호출하세요. - -```js [[1, 4, "<App />"], [2, 4, "document.getElementById('root')"]] -import { render } from 'react-dom'; -import App from './App.js'; - -render(<App />, document.getElementById('root')); -``` - -### 최상단 컴포넌트 렌더링하기 {/*rendering-the-root-component*/} - -React로 완전히 구축된 앱에서는 "최상단('root')" 컴포넌트를 렌더링하기 위해--**일반적으로 시작할 때 한 번만 이 작업을 수행합니다.** - -<Sandpack> - -```js src/index.js active -import './styles.css'; -import { render } from 'react-dom'; -import App from './App.js'; - -render(<App />, document.getElementById('root')); -``` - -```js src/App.js -export default function App() { - return <h1>Hello, world!</h1>; -} -``` - -</Sandpack> - -보통 `render`를 다시 호출하거나 다른 곳에서 호출할 필요는 없습니다. 이 시점부터 React가 애플리케이션의 DOM을 관리합니다. UI를 업데이트하려면 컴포넌트에서 [state를 사용](/reference/react/useState)할 것입니다. - ---- - -### 여러 개의 최상단 컴포넌트 렌더링하기 {/*rendering-multiple-roots*/} - -[완전히 React로 구축된](/learn/add-react-to-an-existing-project#using-react-for-a-part-of-your-existing-page) 페이지가 아니라면 React가 관리하는 최상위 UI마다 `render`를 호출하세요. - -<Sandpack> - -```html public/index.html -<nav id="navigation"></nav> -<main> - <p>This paragraph is not rendered by React (open index.html to verify).</p> - <section id="comments"></section> -</main> -``` - -```js src/index.js active -import './styles.css'; -import { render } from 'react-dom'; -import { Comments, Navigation } from './Components.js'; - -render( - <Navigation />, - document.getElementById('navigation') -); - -render( - <Comments />, - document.getElementById('comments') -); -``` - -```js src/Components.js -export function Navigation() { - return ( - <ul> - <NavLink href="/">Home</NavLink> - <NavLink href="/about">About</NavLink> - </ul> - ); -} - -function NavLink({ href, children }) { - return ( - <li> - <a href={href}>{children}</a> - </li> - ); -} - -export function Comments() { - return ( - <> - <h2>Comments</h2> - <Comment text="Hello!" author="Sophie" /> - <Comment text="How are you?" author="Sunil" /> - </> - ); -} - -function Comment({ text, author }) { - return ( - <p>{text} — <i>{author}</i></p> - ); -} -``` - -```css -nav ul { padding: 0; margin: 0; } -nav ul li { display: inline-block; margin-right: 20px; } -``` - -</Sandpack> - -[`unmountComponentAtNode()`](/reference/react-dom/unmountComponentAtNode)를 사용하여 렌더링 된 트리를 제거할 수 있습니다. - ---- - -### 렌더링 된 트리 업데이트하기 {/*updating-the-rendered-tree*/} - -동일한 DOM 노드에서 `render`를 여러 번 호출할 수 있습니다. 이전에 렌더링 된 구조와 컴포넌트 트리가 일치한다면 React는 [state를 보존](/learn/preserving-and-resetting-state)합니다. - -<Sandpack> - -```js src/index.js active -import { render } from 'react-dom'; -import './styles.css'; -import App from './App.js'; - -let i = 0; -setInterval(() => { - render( - <App counter={i} />, - document.getElementById('root') - ); - i++; -}, 1000); -``` - -```js src/App.js -export default function App({counter}) { - return ( - <> - <h1>Hello, world! {counter}</h1> - <input placeholder="Type something here" /> - </> - ); -} -``` - -</Sandpack> - -`render`를 여러 번 호출하는 것은 일반적이지 않습니다. 보통 컴포넌트 내에서 [상태를 업데이트](/reference/react/useState)합니다. diff --git a/src/content/reference/react-dom/unmountComponentAtNode.md b/src/content/reference/react-dom/unmountComponentAtNode.md deleted file mode 100644 index 0ed8e433d..000000000 --- a/src/content/reference/react-dom/unmountComponentAtNode.md +++ /dev/null @@ -1,112 +0,0 @@ ---- -title: unmountComponentAtNode ---- - -<Deprecated> - -이 API는 향후 React의 주요 버전에서 제거될 예정입니다. - -React 18에서 `unmountComponentAtNode`는 [`root.unmount()`](/reference/react-dom/client/createRoot#root-unmount)로 교체되었습니다. - -</Deprecated> - -<Intro> - -`unmountComponentAtNode`는 DOM에 마운트된 React 컴포넌트를 제거합니다. - -```js -unmountComponentAtNode(domNode) -``` - -</Intro> - -<InlineToc /> - ---- - -## 레퍼런스 {/*reference*/} - -### `unmountComponentAtNode(domNode)` {/*unmountcomponentatnode*/} - -`unmountComponentAtNode`를 호출해서 DOM에 마운트된 React 컴포넌트를 제거하고 관련된 이벤트 핸들러와 state를 정리합니다. - -```js -import { unmountComponentAtNode } from 'react-dom'; - -const domNode = document.getElementById('root'); -render(<App />, domNode); - -unmountComponentAtNode(domNode); -``` - -[아래에서 더 많은 예시를 확인하세요.](#usage) - -#### 매개변수 {/*parameters*/} - -* `domNode`: [DOM 엘리먼트입니다.](https://developer.mozilla.org/en-US/docs/Web/API/Element) React는 이 엘리먼트에 마운트된 컴포넌트를 제거합니다. - -#### 반환값 {/*returns*/} - -`unmountComponentAtNode`는 컴포넌트가 마운트 해제되면 `true`를 반환하고 그렇지 않으면 `false`를 반환합니다. - ---- - -## 사용법 {/*usage*/} - -`unmountComponentAtNode`를 호출해서 <CodeStep step={2}>브라우저 DOM 노드</CodeStep>에서 <CodeStep step={1}>마운트된 React 컴포넌트</CodeStep>를 제거하고 관련된 이벤트 핸들러와 state를 정리합니다. - -```js [[1, 5, "<App />"], [2, 5, "rootNode"], [2, 8, "rootNode"]] -import { render, unmountComponentAtNode } from 'react-dom'; -import App from './App.js'; - -const rootNode = document.getElementById('root'); -render(<App />, rootNode); - -// ... -unmountComponentAtNode(rootNode); -``` - -### DOM 엘리먼트에서 React 애플리케이션 제거하기 {/*removing-a-react-app-from-a-dom-element*/} - -때때로 기존 페이지나 일부만 React로 작성된 페이지에서 React를 "포함"하고 싶을 수 있습니다. 이런 경우 렌더링 된 DOM 노드에서 UI와 state 및 리스너를 모두 제거해서 React 애플리케이션을 "중지"해야 할 수 있습니다. - -아래 예시에서는 "Render React App"을 클릭하면 React 애플리케이션을 렌더링합니다. "Unmount React App"을 클릭하면 React 애플리케이션을 제거합니다. - -<Sandpack> - -```html index.html -<!DOCTYPE html> -<html> - <head><title>My app - - - - -
- - -``` - -```js src/index.js active -import './styles.css'; -import { render, unmountComponentAtNode } from 'react-dom'; -import App from './App.js'; - -const domNode = document.getElementById('root'); - -document.getElementById('render').addEventListener('click', () => { - render(, domNode); -}); - -document.getElementById('unmount').addEventListener('click', () => { - unmountComponentAtNode(domNode); -}); -``` - -```js src/App.js -export default function App() { - return

Hello, world!

; -} -``` - - From c5ed7b8972bed810e962aea411a6e9594975b47c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Fri, 3 Jan 2025 21:06:30 +0900 Subject: [PATCH 0501/1164] docs: update `client/index.md` --- src/content/reference/react-dom/client/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/reference/react-dom/client/index.md b/src/content/reference/react-dom/client/index.md index 498d78760..16bbf609a 100644 --- a/src/content/reference/react-dom/client/index.md +++ b/src/content/reference/react-dom/client/index.md @@ -4,7 +4,7 @@ title: Client React DOM APIs -`react-dom/client` API를 사용하면 클라이언트(브라우저)에서 React 컴포넌트를 렌더링 할 수 있습니다. 이러한 API는 일반적으로 앱의 최상위 수준에서 React 트리를 초기화하기 위해 사용됩니다. [프레임워크](/learn/start-a-new-react-project#production-grade-react-frameworks)가 대신 호출할 수도 있습니다. 대부분의 컴포넌트는 이를 가져오거나 사용할 필요가 없습니다. +`react-dom/client` API를 사용하면 클라이언트(브라우저)에서 React 컴포넌트를 렌더링 할 수 있습니다. 이러한 API는 일반적으로 앱의 최상위 수준에서 React 트리를 초기화하기 위해 사용합니다. [프레임워크](/learn/start-a-new-react-project#production-grade-react-frameworks)가 대신 호출할 수도 있습니다. 대부분의 컴포넌트는 이를 가져오거나 사용할 필요가 없습니다. --- @@ -12,7 +12,7 @@ title: Client React DOM APIs ## Client APIs {/*client-apis*/} * [`createRoot`](/reference/react-dom/client/createRoot)를 사용하면 브라우저 DOM 노드 안에 React 컴포넌트를 표시하는 루트를 생성할 수 있습니다. -* [`hydrateRoot`](/reference/react-dom/client/hydrateRoot)를 사용하면 이전에 [`react-dom/server`.](/reference/react-dom/server)에 의해 생성된 HTML 콘텐츠가 있는 브라우저 DOM 노드 안에 React 컴포넌트를 표시할 수 있습니다. +* [`hydrateRoot`](/reference/react-dom/client/hydrateRoot)를 사용하면 이전에 [`react-dom/server`](/reference/react-dom/server)에 의해 생성된 HTML 콘텐츠가 있는 브라우저 DOM 노드 안에 React 컴포넌트를 표시할 수 있습니다. --- ## 지원 브라우저 {/*browser-support*/} From 77e99b60dfe178b1a9e8c129e9a844372ac85bb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Sat, 4 Jan 2025 01:23:54 +0900 Subject: [PATCH 0502/1164] docs: update `createRoot.md` --- .../reference/react-dom/client/createRoot.md | 57 +++++++++++-------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/src/content/reference/react-dom/client/createRoot.md b/src/content/reference/react-dom/client/createRoot.md index 6a8435aa3..584020571 100644 --- a/src/content/reference/react-dom/client/createRoot.md +++ b/src/content/reference/react-dom/client/createRoot.md @@ -36,25 +36,17 @@ root.render(); 온전히 React만으로 작성된 앱에서는 일반적으로 루트 컴포넌트에 대한 `createRoot` 호출이 하나만 있습니다. 페이지의 일부에 React를 "뿌려서" 사용하는 페이지의 경우에는 루트를 필요로 하는 만큼 작성할 수 있습니다. -[아래에서 더 많은 예시를 확인하세요.](#usage) +[아래 예시를 참고하세요.](#usage) #### 매개변수 {/*parameters*/} -* `domNode`: [DOM 엘리먼트.](https://developer.mozilla.org/en-US/docs/Web/API/Element) React는 DOM 엘리먼트에 대한 루트를 생성하고 렌더링된 React 콘텐츠를 표시하는 `render`와 같은 함수를 루트에서 호출할 수 있도록 합니다. +* `domNode`: [DOM 엘리먼트](https://developer.mozilla.org/en-US/docs/Web/API/Element). React는 DOM 엘리먼트에 대한 루트를 생성하고 렌더링된 React 콘텐츠를 표시하는 `render`와 같은 함수를 루트에서 호출할 수 있도록 합니다. * **optional** `options`: React 루트에 대한 옵션을 가진 객체입니다. - -<<<<<<< HEAD - * **optional** `onCaughtError`: Callback called when React catches an error in an Error Boundary. Called with the `error` caught by the Error Boundary, and an `errorInfo` object containing the `componentStack`. - * **optional** `onUncaughtError`: Callback called when an error is thrown and not caught by an Error Boundary. Called with the `error` that was thrown, and an `errorInfo` object containing the `componentStack`. - * **optional** `onRecoverableError`: React가 오류로부터 자동으로 복구될 때 호출되는 콜백. - * **optional** `identifierPrefix` : React가 [`useId`](/reference/react/useId)에 의해 생성된 ID에 사용하는 문자열 접두사. 같은 페이지에서 여러개의 루트를 사용할 때 충돌을 피하는 데 유용합니다. -======= * **optional** `onCaughtError`: Callback called when React catches an error in an Error Boundary. Called with the `error` caught by the Error Boundary, and an `errorInfo` object containing the `componentStack`. * **optional** `onUncaughtError`: Callback called when an error is thrown and not caught by an Error Boundary. Called with the `error` that was thrown, and an `errorInfo` object containing the `componentStack`. - * **optional** `onRecoverableError`: Callback called when React automatically recovers from errors. Called with an `error` React throws, and an `errorInfo` object containing the `componentStack`. Some recoverable errors may include the original error cause as `error.cause`. - * **optional** `identifierPrefix`: A string prefix React uses for IDs generated by [`useId`.](/reference/react/useId) Useful to avoid conflicts when using multiple roots on the same page. ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc + * **optional** `onRecoverableError`: React가 오류로부터 자동으로 복구될 때 호출되는 콜백. Called with an `error` React throws, and an `errorInfo` object containing the `componentStack`. Some recoverable errors may include the original error cause as `error.cause`. + * **optional** `identifierPrefix`: React가 [`useId`](/reference/react/useId)에 의해 생성된 ID에 사용하는 문자열 접두사. 같은 페이지에서 여러개의 루트를 사용할 때 충돌을 피하는 데 유용합니다. #### 반환값 {/*returns*/} @@ -69,7 +61,7 @@ root.render(); ### `root.render(reactNode)` {/*root-render*/} -`root.render`를 호출하여 [JSX](/learn/writing-markup-with-jsx)조각("React 노드")을 React 루트의 브라우저 DOM 노드에 표시합니다. +`root.render`를 호출하여 [JSX](/learn/writing-markup-with-jsx) 조각("React 노드")을 React 루트의 브라우저 DOM 노드에 표시합니다. ```js root.render(); @@ -77,7 +69,7 @@ root.render(); React는 `root`에 ``을 표시하고 그 안에 있는 DOM을 관리합니다. -[아래에서 더 많은 예시를 확인하세요.](#usage) +[아래 예시를 참고하세요.](#usage) #### 매개변수 {/*root-render-parameters*/} @@ -110,7 +102,7 @@ root.unmount(); 이 함수는 주로 React 루트의 DOM 노드(또는 그 조상 노드)가 다른 코드에 의해 DOM에서 제거될 수 있는 경우에 유용합니다. 예를 들어 DOM에서 비활성 탭을 제거하는 jQuery 탭 패널을 상상해 보세요. 탭이 제거되면 그 안에 있는 모든 것(내부의 React 루트를 포함)이 DOM에서 제거됩니다. 이 경우 `root.unmount`를 호출하여 제거된 루트의 콘텐츠 관리를 "중지"하도록 React에 지시해야 합니다. 그렇지 않으면 제거된 루트 내부의 컴포넌트는 구독과 같은 전역 리소스를 정리하고 확보하는 법을 모르는 채로 있게 됩니다. -`root.unmount`를 호출하면 루트에 있는 모든 컴포넌트가 마운트 해제되고, 트리상의 이벤트 핸들러나 state가 제거되며, 루트 DOM 노드에서 React가 "분리"됩니다. +`root.unmount`를 호출하면 루트에 있는 모든 컴포넌트가 마운트 해제되고, 트리상의 이벤트 핸들러나 State가 제거되며, 루트 DOM 노드에서 React가 "분리"됩니다. #### 매개변수 {/*root-unmount-parameters*/} @@ -126,7 +118,7 @@ root.unmount(); * `root.unmount`를 호출하면 트리의 모든 컴포넌트가 마운트 해제되고 루트 DOM 노드에서 React가 "분리"됩니다. -* `root.unmount`를 한 번 호출한 후에는 같은 루트에서 `root.render`를 다시 호출할 수 없습니다. 마운트 해제된 루트에서 `root.render`를 호출하려고 하면 "마운트 해제된 root를 업데이트할 수 없습니다." 오류가 발생합니다. 그러나 해당 노드의 이전 루트가 마운트 해제된 후 동일한 DOM 노드에 새로운 루트를 만들 수는 있습니다. +* `root.unmount`를 한 번 호출한 후에는 같은 루트에서 `root.render`를 다시 호출할 수 없습니다. 마운트 해제된 루트에서 `root.render`를 호출하려고 하면 "마운트 해제된 root를 업데이트할 수 없습니다.Cannot update an unmounted root" 오류가 발생합니다. 그러나 해당 노드의 이전 루트가 마운트 해제된 후 동일한 DOM 노드에 새로운 루트를 만들 수는 있습니다. --- @@ -196,7 +188,7 @@ function Counter() { **앱이 온전히 React만으로 작성된 경우, 추가적으로 루트를 더 만들거나 [`root.render`](#root-render)를 다시 호출할 필요가 없습니다.** -이 시점부터 React는 전체 앱의 DOM을 관리합니다. 컴포넌트를 더 추가하려면 [ `App` 컴포넌트 안에 중첩](/learn/importing-and-exporting-components)시키세요. UI 업데이트는 각 컴포넌트의 [state를 통해](/reference/react/useState) 수행할 수 있습니다. 모달이나 툴팁과 같은 추가 콘텐츠를 DOM 노드 외부에 표시해야 하는 경우 [portal로 렌더링](/reference/react-dom/createPortal)하세요. +이 시점부터 React는 전체 앱의 DOM을 관리합니다. 컴포넌트를 더 추가하려면 [ `App` 컴포넌트 안에 중첩](/learn/importing-and-exporting-components)시키세요. UI 업데이트는 각 컴포넌트의 [State를 통해](/reference/react/useState) 수행할 수 있습니다. 모달이나 툴팁과 같은 추가 콘텐츠를 DOM 노드 외부에 표시해야 하는 경우 [Portal로 렌더링](/reference/react-dom/createPortal)하세요. @@ -206,13 +198,13 @@ HTML이 비어있으면, 앱의 자바스크립트 코드가 로드되고 실행
``` -이것은 매우 느리게 느껴질 수 있습니다! 이 문제를 해결하기 위해 [서버에서 또는 빌드 중에](/reference/react-dom/server) 컴포넌트로부터 초기 HTML을 생성할 수 있습니다. 그러면 방문자는 자바스크립트 코드가 로드되기 전에 텍스트를 읽고, 이미지를 보고, 링크를 클릭할 수 있습니다. 이 최적화를 기본적으로 수행하는 [프레임워크를 사용](/learn/start-a-new-react-project#production-grade-react-frameworks)하는 것이 좋습니다. 실행 시점에 따라 이를 *서버 측 렌더링(SSR)* 또는 *정적 사이트 생성(SSG)* 이라고 합니다. +이것은 매우 느리게 느껴질 수 있습니다! 이 문제를 해결하기 위해 [서버에서 또는 빌드 중에](/reference/react-dom/server) 컴포넌트로부터 초기 HTML을 생성할 수 있습니다. 그러면 방문자는 자바스크립트 코드가 로드되기 전에 텍스트를 읽고, 이미지를 보고, 링크를 클릭할 수 있습니다. 이 최적화를 기본적으로 수행하는 [프레임워크를 사용](/learn/start-a-new-react-project#production-grade-react-frameworks)하는 것이 좋습니다. 실행 시점에 따라 이를 *서버 측 렌더링SSR* 또는 *정적 사이트 생성SSG* 이라고 합니다.
-**서버 렌더링이나 정적 생성을 사용하는 앱은 `createRoot` 대신 [`hydrateRoot`](/reference/react-dom/client/hydrateRoot)를 호출해야 합니다.** 그러면 React는 DOM 노드를 파괴하고 다시 생성하는 대신 HTML으로부터 *hydrate*(재사용)합니다. +**서버 측 렌더링이나 정적 사이트 생성을 사용하는 앱은 `createRoot` 대신 [`hydrateRoot`](/reference/react-dom/client/hydrateRoot)를 호출해야 합니다.** 그러면 React는 DOM 노드를 파괴하고 다시 생성하는 대신 HTML으로부터 *Hydrate*(재사용)합니다. --- @@ -221,7 +213,7 @@ HTML이 비어있으면, 앱의 자바스크립트 코드가 로드되고 실행 페이지가 [React만으로 작성되지 않은 경우](/learn/add-react-to-an-existing-project#using-react-for-a-part-of-your-existing-page), React가 관리하는 각 최상위 UI에 대한 루트를 생성하기 위해 `createRoot`를 여러 번 호출할 수 있습니다. 루트마다 [`root.render`](#root-render)를 호출함으로써 각각 다른 콘텐츠를 표시할 수 있습니다. -다음 예시에서는 서로 다른 두 개의 React 컴포넌트가 `index.html` 파일에 정의된 두 개의 DOM 노드에 렌더링합니다. +다음 예시에서는 서로 다른 두 개의 React 컴포넌트를 `index.html` 파일에 정의된 두 개의 DOM 노드에 렌더링합니다. @@ -316,7 +308,7 @@ root.unmount(); ### Updating a root component {/*updating-a-root-component*/} -같은 루트에서 `render`를 두 번 이상 호출할 수도 있습니다. 컴포넌트 트리 구조가 이전 렌더링과 일치하는 한, React는 [기존 state를 유지](/learn/preserving-and-resetting-state)합니다. 다음 예시에서 input에 어떻게 타이핑하든 관계없이, 매 초 반복되는 `render` 호출로 인한 업데이트가 아무런 문제를 일으키지 않음을 주목하세요. +같은 루트에서 `render`를 두 번 이상 호출할 수도 있습니다. 컴포넌트 트리 구조가 이전 렌더링과 일치하는 한, React는 [기존 State를 유지](/learn/preserving-and-resetting-state)합니다. 다음 예시에서 입력 창에 어떻게 타이핑하든 관계없이, 매 초 반복되는 `render` 호출로 인한 업데이트가 아무런 문제를 일으키지 않음을 주목하세요. @@ -347,7 +339,7 @@ export default function App({counter}) { -`render`를 여러 번 호출하는 경우는 흔하지 않습니다. 일반적으로는, 컴포넌트가 [state를 업데이트](/reference/react/useState)합니다. +`render`를 여러 번 호출하는 경우는 흔하지 않습니다. 일반적으로는, 컴포넌트가 [State를 업데이트](/reference/react/useState)합니다. ### Show a dialog for uncaught errors {/*show-a-dialog-for-uncaught-errors*/} @@ -1136,7 +1128,7 @@ root.render(); --- -### "대상 컨테이너가 DOM 엘리먼트가 아닙니다" 라는 오류가 발생합니다. {/*im-getting-an-error-target-container-is-not-a-dom-element*/} +### I'm getting an error: "You passed a second argument to root.render" {/*im-getting-an-error-you-passed-a-second-argument-to-root-render*/} A common mistake is to pass the options for `createRoot` to `root.render(...)`: @@ -1156,6 +1148,21 @@ const root = createRoot(container, {onUncaughtError}); root.render(); ``` +--- + +### "대상 컨테이너가 DOM 엘리먼트가 아닙니다" 라는 오류가 발생합니다. {/*im-getting-an-error-target-container-is-not-a-dom-element*/} + +This error means that whatever you're passing to `createRoot` is not a DOM node. + +If you're not sure what's happening, try logging it: + +```js {2} +const domNode = document.getElementById('root'); +console.log(domNode); // ??? +const root = createRoot(domNode); +root.render(); +``` + 예를 들어 `domNode`가 `null`이면 [`getElementById`](https://developer.mozilla.org/ko/docs/Web/API/Document/getElementById) 가 `null`을 반환했음을 의미합니다. 이는 호출 시점에 문서에 지정된 ID를 가진 노드가 없는 경우에 발생합니다. 여기에는 몇 가지 이유가 있을 수 있습니다. 1. 찾고자 하는 ID가 HTML 파일에서 사용한 ID와 다를 수 있습니다. 오타가 있는지 확인하세요! @@ -1169,7 +1176,7 @@ root.render(); 이 오류는 `root.render`에 전달하는 것이 React 컴포넌트가 아님을 의미합니다. -이 오류는 `` 대신 `Component`로 `root.render`를 호출할 때 발생할 수 있습니다 +이 오류는 `` 대신 `Component`로 `root.render`를 호출할 때 발생할 수 있습니다. ```js {2,5} // 🚩 Wrong: App is a function, not a Component. @@ -1193,7 +1200,7 @@ root.render(createApp()); ### 서버에서 렌더링된 HTML이 처음부터 다시 생성됩니다 {/*my-server-rendered-html-gets-re-created-from-scratch*/} -앱이 서버에서 렌더링 되고 React의 초기 HTML을 포함하는 경우에, 루트를 생성해서 `root.render`를 호출하면, 모든 HTML이 삭제되고 모든 DOM 노드가 처음부터 다시 생성되는 것을 볼 수 있습니다. 이렇게 하면 속도가 느려지고, 포커스와 스크롤 위치가 재설정되며, 그 밖의 다른 사용자 입력들이 손실될 수 있습니다. +앱이 서버에서 렌더링되고 React의 초기 HTML을 포함하는 경우에, 루트를 생성해서 `root.render`를 호출하면, 모든 HTML이 삭제되고 모든 DOM 노드가 처음부터 다시 생성되는 것을 볼 수 있습니다. 이렇게 하면 속도가 느려지고, 포커스와 스크롤 위치가 재설정되며, 그 밖의 다른 사용자 입력들이 손실될 수 있습니다. 서버에서 렌더링된 앱은 `createRoot` 대신 [`hydrateRoot`](/reference/react-dom/client/hydrateRoot)를 사용해야 합니다. From bbb67f5577f01322f520055ae198ed678a0d3290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Sat, 4 Jan 2025 15:02:18 +0900 Subject: [PATCH 0503/1164] docs: update `hydrateRoot.md` --- .../reference/react-dom/client/createRoot.md | 8 +- .../reference/react-dom/client/hydrateRoot.md | 196 ++++++++---------- 2 files changed, 90 insertions(+), 114 deletions(-) diff --git a/src/content/reference/react-dom/client/createRoot.md b/src/content/reference/react-dom/client/createRoot.md index 584020571..3215ac45d 100644 --- a/src/content/reference/react-dom/client/createRoot.md +++ b/src/content/reference/react-dom/client/createRoot.md @@ -50,11 +50,11 @@ root.render(); #### 반환값 {/*returns*/} -`createRoot`는 [`render`](#root-render)와 [`unmount`](#root-unmount) 두 가지 메서드가 있는 객체를 반환합니다. +`createRoot`는 [`render`](#root-render)와 [`unmount`](#root-unmount) 두 가지 메서드를 포함한 객체를 반환합니다. #### 주의 사항 {/*caveats*/} * 앱이 서버에서 렌더링 되는 경우 `createRoot()`는 사용할 수 없습니다. 대신 [`hydrateRoot()`](/reference/react-dom/client/hydrateRoot)를 사용하세요. -* 앱에 `createRoot` 호출이 단 하나만 있을 가능성이 높습니다. 프레임워크를 사용하는 경우 프레임워크가 이 호출을 대신 수행할 수도 있습니다. +* 앱에서 `createRoot` 호출이 단 한번만 있을 가능성이 높습니다. 프레임워크를 사용하는 경우 프레임워크가 이 호출을 대신 수행할 수도 있습니다. * 컴포넌트의 자식이 아닌 DOM 트리의 다른 부분(예: 모달 또는 툴팁)에 JSX 조각을 렌더링하려는 경우, `createRoot` 대신 [`createPortal`](/reference/react-dom/createPortal)을 사용하세요. --- @@ -92,7 +92,7 @@ React는 `root`에 ``을 표시하고 그 안에 있는 DOM을 관리합 ### `root.unmount()` {/*root-unmount*/} -`root.unmount`를 호출하면 React 루트 내부에서 렌더링 된 트리를 삭제합니다. +`root.unmount`를 호출하면 React 루트 내부에서 렌더링된 트리를 삭제합니다. ```js root.unmount(); @@ -118,7 +118,7 @@ root.unmount(); * `root.unmount`를 호출하면 트리의 모든 컴포넌트가 마운트 해제되고 루트 DOM 노드에서 React가 "분리"됩니다. -* `root.unmount`를 한 번 호출한 후에는 같은 루트에서 `root.render`를 다시 호출할 수 없습니다. 마운트 해제된 루트에서 `root.render`를 호출하려고 하면 "마운트 해제된 root를 업데이트할 수 없습니다.Cannot update an unmounted root" 오류가 발생합니다. 그러나 해당 노드의 이전 루트가 마운트 해제된 후 동일한 DOM 노드에 새로운 루트를 만들 수는 있습니다. +* `root.unmount`를 한 번 호출한 후에는 같은 루트에서 `root.render`를 다시 호출할 수 없습니다. 마운트 해제된 루트에서 `root.render`를 호출하려고 하면 "마운트 해제된 루트를 업데이트할 수 없습니다.Cannot update an unmounted root" 오류가 발생합니다. 그러나 해당 노드의 이전 루트가 마운트 해제된 후 동일한 DOM 노드에 새로운 루트를 만들 수는 있습니다. --- diff --git a/src/content/reference/react-dom/client/hydrateRoot.md b/src/content/reference/react-dom/client/hydrateRoot.md index 34fd04f4b..db0a3b9d7 100644 --- a/src/content/reference/react-dom/client/hydrateRoot.md +++ b/src/content/reference/react-dom/client/hydrateRoot.md @@ -4,7 +4,7 @@ title: hydrateRoot -`hydrateRoot`는 [`react-dom/server`](/reference/react-dom/server)를 통해 사전에 만들어진 HTML로 그려진 브라우저 DOM 노드 내부에 React 컴포넌트를 렌더링합니다. +`hydrateRoot`는 이전에 [`react-dom/server`](/reference/react-dom/server)로 생성된 HTML 콘텐츠를 가진 브라우저 DOM 노드 안에 React 컴포넌트를 표시할 수 있게 해줍니다. ```js const root = hydrateRoot(domNode, reactNode, options?) @@ -20,7 +20,7 @@ const root = hydrateRoot(domNode, reactNode, options?) ### `hydrateRoot(domNode, reactNode, options?)` {/*hydrateroot*/} -서버 환경에서 React로 앞서 만들어진 HTML에 후에 만들어진 React를 `hydrateRoot`를 호출해 "붙입니다". +`hydrateRoot`를 호출하여 이미 서버 환경에서 렌더링된 기존 HTML에 React를 "붙여넣기" 합니다. ```js import { hydrateRoot } from 'react-dom/client'; @@ -29,82 +29,78 @@ const domNode = document.getElementById('root'); const root = hydrateRoot(domNode, reactNode); ``` -React는 `domNode` 내부의 HTML에 붙어, 내부 DOM을 직접 관리할 것입니다. App을 React로 전부 만들었다면 보통은 단 하나의 root 컴포넌트와 함께 `hydrateRoot`를 한 번 호출할 것입니다. +React는 `domNode` 내부에 존재하는 HTML에 연결되어, 그 내부의 DOM 관리를 맡게 됩니다. React로 완전히 구축된 앱은 일반적으로 루트 컴포넌트와 함께 하나의 `hydrateRoot` 호출만 가집니다. -[아래 여러 예시를 확인해보세요.](#usage) +[아래 예시를 참고하세요.](#usage) -#### Parameters {/*parameters*/} +#### 매개변수 {/*parameters*/} -* `domNode`: 서버에서 root 엘리먼트로 렌더링된 [DOM 엘리먼트](https://developer.mozilla.org/en-US/docs/Web/API/Element) +* `domNode`: 서버에서 루트 요소Element로 렌더링된 [DOM 요소](https://developer.mozilla.org/en-US/docs/Web/API/Element). -* `reactNode`: 앞서 존재하는 HTML에 렌더링하기 위한 "React 노드" 입니다. 주로 `ReactDOM Server`의 `renderToPipeableStream()`와 같은 메소드로 렌더링된 ``같은 JSX 조각들입니다. - -* **optional** `options`: React root에 옵션을 주기 위한 객체입니다. +* `reactNode`: 기존 HTML에 렌더링하기 위한 "React 노드" 입니다. 주로 `ReactDOM Server`의 `renderToPipeableStream()`와 같은 메서드로 렌더링된 ``과 같은 JSX 조각들입니다. +* **optional** `options`: React 루트에 대한 옵션을 가진 객체입니다. * **optional** `onCaughtError`: Callback called when React catches an error in an Error Boundary. Called with the `error` caught by the Error Boundary, and an `errorInfo` object containing the `componentStack`. * **optional** `onUncaughtError`: Callback called when an error is thrown and not caught by an Error Boundary. Called with the `error` that was thrown and an `errorInfo` object containing the `componentStack`. - * **optional** `onRecoverableError`: Callback called when React automatically recovers from errors. Called with the `error` React throws, and an `errorInfo` object containing the `componentStack`. Some recoverable errors may include the original error cause as `error.cause`. - * **optional** `identifierPrefix`: A string prefix React uses for IDs generated by [`useId`.](/reference/react/useId) Useful to avoid conflicts when using multiple roots on the same page. Must be the same prefix as used on the server. - - * **optional** `onRecoverableError`: React가 에러에서 자동으로 회복되었을 때 호출하는 콜백함수. - * **optional** `identifierPrefix`: React가 ID로 사용하는 접두사로 [`useId`](/reference/react/useId)로 만들어진 값입니다. 같은 페이지에서 여러 root를 사용할 때 충돌을 피할 때 유용하게 사용할 수 있습니다. 서버에서 사용한 값과 반드시 동일한 값이어야 합니다. + * **optional** `onRecoverableError`: React가 오류로부터 자동으로 복구될 때 호출되는 콜백. Called with the `error` React throws, and an `errorInfo` object containing the `componentStack`. Some recoverable errors may include the original error cause as `error.cause`. + * **optional** `identifierPrefix`: React가 [`useId`](/reference/react/useId)에 의해 생성된 ID에 사용하는 문자열 접두사. 같은 페이지에서 여러개의 루트를 사용할 때 충돌을 피하는 데 유용합니다. 서버에서 사용한 값과 반드시 동일한 값이어야 합니다. -#### Returns {/*returns*/} +#### 반환값 {/*returns*/} -`hydrateRoot`는 2가지 메소드가 포함된 객체를 반환합니다 : [`render`](#root-render) 그리고 [`unmount`.](#root-unmount) +`hydrateRoot`는 [`render`](#root-render)와 [`unmount`](#root-unmount) 두 가지 메서드를 포함한 객체를 반환합니다. #### 주의 사항 {/*caveats*/} -* `hydrateRoot()`는 서버에서 렌더링된 내용과 후에 렌더링된 내용이 동일할 것을 기대합니다. 따라서 동일하지 않은 부분들은 직접 버그로 취급해주거나 고쳐줘야 합니다. -* 개발 모드에선, React가 hydration 중에 동일하지 않은 부분에 대해 경고해줍니다. 속성이 동일하지 않을 경우에 해당 속성이 올바르게 적용될 것이라고 보장할 수 없습니다. 모든 마크업을 보장하지 않는 것은 성능면에서 중요하기 때문입니다. 마크업이 동일하지 않는 경우는 드물기 때문에 모든 마크업을 검증하는 비용은 굉장히 비쌉니다. -* 여러분은 App에서 `hydrateRoot`를 단 한 번만 호출하게 될 것입니다. 만약 프레임워크를 사용한다면, 프레임워크가 대신 호출해 줄 것입니다. -* App을 사전에 렌더링된 HTML 없이 클라이언트에서 직접 렌더링을 한다면 `hydrateRoot()`은 지원되지 않습니다. [`createRoot()`](/reference/react-dom/client/createRoot)를 대신 사용해주세요. +* `hydrateRoot()`는 렌더링된 컨텐츠가 서버에서 렌더링된 컨텐츠와 동일할 것을 기대합니다. 따라서 불일치 사항은 버그로 취급하고 수정해야 합니다. +* 개발 모드에서는 React가 Hydration 중 불일치에 대해 경고합니다. 불일치가 발생할 경우 속성 차이가 수정될 것이라는 보장은 없습니다. 이는 성능상의 이유로 중요한데, 대부분의 앱에서 불일치는 드물기 때문에 모든 마크업을 검증하는 것은 매우 비효율적이기 때문입니다. +* 앱에서 `hydrateRoot` 호출이 단 한번만 있을 가능성이 높습니다. 프레임워크를 사용한다면, 프레임워크가 이 호출을 대신 수행할 수도 있습니다. +* 앱을 사전에 렌더링된 HTML 없이 클라이언트에서 직접 렌더링한다면, `hydrateRoot()`는 지원되지 않습니다. [`createRoot()`](/reference/react-dom/client/createRoot)를 대신 사용해주세요. --- ### `root.render(reactNode)` {/*root-render*/} -hydrate된 React root부터 내부 컴포넌트를 새로운 React 컴포넌트로 갱신하기 위해 `root.render`를 호출해주세요. 브라우저 DOM 요소들도 함께 갱신됩니다. +브라우저 DOM 요소 내에서 Hydrate된 React 루트 안의 React 컴포넌트를 업데이트 하려면 `root.render`를 호출하세요. ```js root.render(); ``` -React는 hydrate된 `root`부터 내부를 ``으로 갱신합니다. +React는 Hydrate된 `root`에서 ``을 업데이트합니다. -[아래 예시를 확인해보세요.](#usage) +[아래 예시를 참고하세요.](#usage) -#### Parameters {/*root-render-parameters*/} +#### 매개변수 {/*root-render-parameters*/} -* `reactNode`: 갱신하고 싶은 "React 노드"입니다. 주로 ``같은 JSX를 매개변수로 넘기지만, [`createElement()`](/reference/react/createElement)로 만든 React 엘리먼트를 넘겨도 되고 문자열이나 숫자, `null`, 혹은 `undefined`를 넘겨도 됩니다. +* `reactNode`: 업데이트하고 싶은 "React 노드"입니다. 주로 ``같은 JSX를 매개변수로 넘기지만, [`createElement()`](/reference/react/createElement)로 만든 React 요소 혹은 문자열, 숫자, `null`, `undefined`를 넘겨도 됩니다. -#### Returns {/*root-render-returns*/} +#### 반환값 {/*root-render-returns*/} `root.render`는 `undefined`를 반환합니다. #### 주의 사항 {/*root-render-caveats*/} -* hydrate가 끝나기 전에 `root.render`를 호출하면 React는 서버에서 렌더링된 HTML을 모두 없애고 클라이언트에서 렌더링된 컴포넌트들로 완전히 교체합니다. +* 루트가 Hydrate를 완료하기 전에 `root.render`를 호출하면, React는 서버에서 렌더링된 HTML을 모두 없애고 클라이언트에서 렌더링된 컴포넌트들로 완전히 교체합니다. --- ### `root.unmount()` {/*root-unmount*/} -`root.unmount`를 호출해 React root부터 그 하위에 렌더링된 트리를 삭제합니다. +`root.unmount`를 호출하면 React 루트 내부에서 렌더링된 트리를 삭제합니다. ```js root.unmount(); ``` -처음부터 끝까지 React로 만든 앱은 `root.unmount`를 호출할 경우가 거의 없습니다. +온전히 React만으로 작성된 앱에는 일반적으로 `root.unmount`에 대한 호출이 없습니다. -주로 React root부터 혹은 그 상위에서부터 시작된 DOM node들을 다른 코드에 의해 DOM에서 삭제되어야 하는 경우 유용합니다. 예를 들어, jQuery 탭 패널이 활성화 되어 있지 않은 탭을 DOM에서 지운다고 가정해봅시다. 탭이 지워지면, React root와 그 내부를 포함해 그 안의 모든 것이 지워지게 되고 DOM에서 또한 지워지게 됩니다. `root.unmount`를 호출해 React에게 삭제된 컨텐츠들을 "그만" 다루라고 알려주어야 합니다. 그렇지 않으면 삭제되어버린 React root 내부의 컴포넌트들은 삭제되지 않을 것이며, "구독"처럼 컴퓨팅 자원을 자유롭게 놓아주지 못하게 됩니다. +이 함수는 주로 React 루트의 DOM 노드(또는 그 조상 노드)가 다른 코드에 의해 DOM에서 제거될 수 있는 경우에 유용합니다. 예를 들어 DOM에서 비활성 탭을 제거하는 jQuery 탭 패널을 상상해 보세요. 탭이 제거되면 그 안에 있는 모든 것(내부의 React 루트를 포함)이 DOM에서 제거됩니다. 이 경우 `root.unmount`를 호출하여 제거된 루트의 콘텐츠 관리를 "중지"하도록 React에 지시해야 합니다. 그렇지 않으면 제거된 루트 내부의 컴포넌트는 구독과 같은 전역 리소스를 정리하고 확보하는 법을 모르는 채로 있게 됩니다. -`root.unmount`를 호출하면 root 내부의 모든 컴포넌트를 마운트 해제하고 root DOM node에서 React를 "떼어"냅니다. root 내부의 이벤트 핸들러와 state까지 모두 포함해 마운트 해제 및 삭제됩니다. +`root.unmount`를 호출하면 루트에 있는 모든 컴포넌트가 마운트 해제되고, 트리상의 이벤트 핸들러나 State가 제거되며, 루트 DOM 노드에서 React가 "분리"됩니다. -#### Parameters {/*root-unmount-parameters*/} +#### 매개변수 {/*root-unmount-parameters*/} -`root.unmount`는 그 어떤 매개변수도 받지 않습니다. +`root.unmount`는 매개변수를 받지 않습니다. #### Returns {/*root-unmount-returns*/} @@ -113,17 +109,17 @@ root.unmount(); #### 주의 사항 {/*root-unmount-caveats*/} -* `root.unmount`를 호출하면 root부터 그 안의 모든 컴포넌트가 마운트 해제되고 root DOM node에서 React를 떼어냅니다. +* `root.unmount`를 호출하면 트리의 모든 컴포넌트가 마운트 해제되고 루트 DOM 노드에서 React가 "분리"됩니다. -* `root.unmount`를 한번 호출한 이후엔 `root.render`를 root에 다시 사용할 수 없습니다. 마운트 해제된 root에 다시 `root.render`를 호출하려고 한다면 "Cannot update an unmounted root" 에러를 throw하게 됩니다. +* `root.unmount`를 한 번 호출한 후에는 같은 루트에서 `root.render`를 다시 호출할 수 없습니다. 마운트 해제된 루트에서 `root.render`를 호출하려고 하면 "마운트 해제된 루트를 업데이트할 수 없습니다.Cannot update an unmounted root" 오류가 발생합니다. --- -## 사용 예시 {/*usage*/} +## 사용법 {/*usage*/} -### 서버에서 렌더링된 HTML을 hydrate하기 {/*hydrating-server-rendered-html*/} +### 서버에서 렌더링된 HTML을 Hydrate하기 {/*hydrating-server-rendered-html*/} -[`react-dom/server`](/reference/react-dom/client/createRoot)로 앱의 HTML을 생성했다면, 클라이언트에서 *hydrate*해주어야 합니다. +[`react-dom/server`](/reference/react-dom/client/createRoot)로 앱의 HTML을 생성했다면, 클라이언트에서 *Hydrate* 해주어야 합니다. ```js [[1, 3, "document.getElementById('root')"], [2, 3, ""]] import { hydrateRoot } from 'react-dom/client'; @@ -131,9 +127,9 @@ import { hydrateRoot } from 'react-dom/client'; hydrateRoot(document.getElementById('root'), ); ``` -위 코드를 통해 서버 HTML을 브라우저 DOM node에서 React 컴포넌트를 이용해 hydrate 해줄 것 입니다. 주로 앱을 시작할 때 단 한 번 실행하게 될 것입니다. 프레임워크를 사용중이라면 프레임워크가 알아서 실행해 줄 것입니다. +위 코드를 통해 서버 HTML을 브라우저 DOM 노드에서 React 컴포넌트를 이용해 Hydrate 해줄 것 입니다. 주로 앱을 시작할 때 단 한 번 실행할 것입니다. 프레임워크를 사용중이라면 프레임워크가 대신 실행해 줄 것입니다. -앱을 hydrate하기 위해서 React는 컴포넌트의 로직을 사전에 서버에서 만들어 진 HTML에 "붙일"것 입니다. Hydration을 통해 서버에서 만들어진 최초의 HTML 스냅샷을 브라우저에서 완전히 인터랙티브한 앱으로 바꿔주게 됩니다. +앱을 Hydrate 하기 위해서 React는 컴포넌트의 로직을 사전에 서버에서 만들어 진 HTML에 "붙여넣을"것 입니다. Hydration을 통해 서버에서 만들어진 최초의 HTML 스냅샷을 브라우저에서 완전히 인터랙티브한 앱으로 바꿔주게 됩니다. @@ -180,30 +176,30 @@ function Counter() { -`hydrateRoot`를 다시 호출하거나 다른 곳에서 더 호출할 필요는 없습니다. 이 시점부터 React가 애플리케이션의 DOM을 다루게 됩니다. 대신 UI를 갱신하기 위해선 [state를 사용](/reference/react/useState)해야 합니다. +`hydrateRoot`를 다시 호출하거나 다른 곳에서 더 호출할 필요는 없습니다. 이 시점부터 React가 애플리케이션의 DOM을 다루게 됩니다. 대신 UI를 갱신하기 위해선 [State를 사용](/reference/react/useState)해야 합니다. `hydrateRoot`에 전달한 React 트리는 서버에서 만들었던 React 트리 결과물과 동일해야 합니다. -이는 사용자 경험을 위해서 중요합니다. 사용자는 서버에서 만들어진 HTML을 JavaScript 코드가 로드될 때까지 둘러보게 됩니다. 앱의 로딩을 더 빠르게 하기 위해 서버는 일종의 신기루로서 React 결과물인 HTML 스냅샷을 만들어 보여줍니다. 갑자기 다른 컨텐츠를 보여주게 되면 신기루가 깨져버리게 됩니다. 이런 이유로 서버에서 렌더링한 결과물과 클라이언트에서 최초로 렌더링한 결과물이 같아야 합니다. +이는 사용자 경험을 위해서 중요합니다. 사용자는 서버에서 만들어진 HTML을 자바스크립트 코드가 로드될 때까지 둘러보게 됩니다. 앱의 로딩을 더 빠르게 하기 위해 서버는 일종의 신기루로서 React 결과물인 HTML 스냅샷을 만들어 보여줍니다. 갑자기 다른 컨텐츠를 보여주게 되면 신기루가 깨져버리게 됩니다. 이런 이유로 서버에서 렌더링한 결과물과 클라이언트에서 최초로 렌더링한 결과물이 같아야 합니다. -주로 아래와 같은 원인으로 hydration 에러가 일어납니다. +주로 아래와 같은 원인들로 Hydration 오류가 일어납니다. -* React를 통해 만들어진 HTML의 root node안에 새 줄같은 추가적인 공백. -* `typeof window !== 'undefined'`과 같은 조건을 렌더링 로직에서 사용함. -* [`window.matchMedia`](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia)같은 브라우저에서만 사용가능한 API를 렌더링 로직에 사용함. -* 서버와 클라이언트에서 서로 다른 데이터를 렌더링함. +* React를 통해 만들어진 HTML의 루트 노드안에 공백 혹은 개행같은 추가적인 공백. +* `typeof window !== 'undefined'`과 같은 조건을 렌더링 로직에서 사용. +* [`window.matchMedia`](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia)같은 브라우저에서만 사용가능한 API를 렌더링 로직에 사용. +* 서버와 클라이언트에서 서로 다른 데이터를 렌더링. -React는 hydration 에러에서 복구됩니다, 하지만 **다른 버그들과 같이 반드시 고쳐줘야 합니다.** 가장 나은 경우는 그저 느려지기만 할 뿐이지만, 최악의 경우엔 이벤트 핸들러가 다른 엘리먼트에 붙어버립니다. +React는 Hydration 오류에서 복구됩니다, 하지만 **다른 버그들과 같이 반드시 고쳐줘야 합니다.** 가장 나은 경우는 그저 느려지기만 할 뿐이지만, 최악의 경우엔 이벤트 핸들러가 다른 요소Element에 붙어버립니다. --- -### document 전체를 hydrate하기 {/*hydrating-an-entire-document*/} +### `document` 전체를 Hydrate하기 {/*hydrating-an-entire-document*/} -React로 앱을 모두 만들었을 경우 [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/html)태그를 포함해 JSX로 된 전체 document를 렌더링할 수 있습니다. +React로 앱을 모두 만들었을 경우 [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/html) 태그를 포함해 JSX로 된 전체 `document`를 렌더링할 수 있습니다. ```js {3,13} function App() { @@ -223,7 +219,7 @@ function App() { } ``` -전체 document를 hydrate하기 위해선 글로벌 변수인 [`document`](https://developer.mozilla.org/en-US/docs/Web/API/Window/document)를 `hydrateRoot`의 첫번째 인자로 넘깁니다: +전체 `document`를 Hydrate하기 위해선 전역 변수인 [`document`](https://developer.mozilla.org/en-US/docs/Web/API/Window/document)를 `hydrateRoot`의 첫번째 인수로 넘깁니다. ```js {4} import { hydrateRoot } from 'react-dom/client'; @@ -234,11 +230,11 @@ hydrateRoot(document, ); --- -### 어쩔 수 없는 hydration 불일치 에러 억제하기 {/*suppressing-unavoidable-hydration-mismatch-errors*/} +### 어쩔 수 없는 Hydration 불일치 오류 억제하기 {/*suppressing-unavoidable-hydration-mismatch-errors*/} -어떤 엘리먼트의 속성이나 text content가 서버와 클라이언트에서 어쩔 수 없이 다를 땐(예를 들어, timestamp를 이용했다거나), hydration 불일치 경고를 안보이게 할 수 있습니다. +어떤 요소Element의 속성이나 텍스트 컨텐츠가 서버와 클라이언트에서 어쩔 수 없이 다를 땐(예를 들어, timestamp를 이용했다거나), Hydration 불일치 경고를 안보이게 할 수 있습니다. -해당 엘리먼트에서 hydration 경고를 끄기 위해선 `suppressHydrationWarning={true}`를 추가하면 됩니다. +해당 요소에서 Hydration 경고를 끄기 위해선 `suppressHydrationWarning={true}`를 추가하면 됩니다. @@ -270,13 +266,13 @@ export default function App() { -이것은 한 단계 아래까지만 적용되며 비상 탈출구를 의도한 것입니다. 남용하지 마세요. text context가 아닌 한, React는 잘못된 부분을 수정하지 않을 것이며 갱신이 일어나기 전까지는 불일치한 상태로 남아있을 것입니다. +이것은 한 단계 아래까지만 적용되며 탈출구Escape Hatch를 의도한 것입니다. 남용하지 마세요. 텍스트 컨텐츠가 아닌 한 React는 잘못된 부분을 수정하지 않을 것이며, 갱신이 일어나기 전까지는 불일치 상태로 남아있을 것입니다. --- ### 서로 다른 클라이언트와 서버 컨텐츠 다루기 {/*handling-different-client-and-server-content*/} -의도적으로 서버와 클라이언트에서 서로 다른 내용을 렌더링하길 원한다면, 서버와 클라이언트에서 서로 다른 방법으로 렌더링하면 됩니다. 클라이언트에서 서버와는 다른 것을 렌더링할 때 클라이언트에선 [Effect](/reference/react/useEffect)에서 `true`로 할당되는 `isClient`같은 [상태 변수](/reference/react/useState)를 읽을 수 있습니다. +의도적으로 서버와 클라이언트에서 서로 다른 내용을 렌더링하길 원한다면, 서버와 클라이언트에서 서로 다른 방법으로 렌더링하면 됩니다. 클라이언트에서 서버와는 다른 것을 렌더링할 때 클라이언트에선 [Effect](/reference/react/useEffect)에서 `true`로 할당되는 `isClient`같은 [State 변수](/reference/react/useState)를 읽을 수 있습니다. @@ -316,21 +312,21 @@ export default function App() { -이 방법은 처음엔 서버와 동일한 결과물을 렌더링하게 되어 불일치 문제를 피하게 되고, hydration후에 새로운 결과물이 동기적으로 렌더링됩니다. +이 방법은 처음엔 서버와 동일한 결과물을 렌더링하여 불일치 문제를 피하고, Hydration 후에 새로운 결과물이 동기적으로 렌더링됩니다. -이 방법은 2번 렌더링해야 하기 때문에 hydration을 느리게 합니다. 느린 통신 상태일 경우에 사용자 경험을 염두하세요. 초기 HTML이 렌더된 한참 이후에야 JavaScript 코드를 불러오게 됩니다. 따라서 hydration 이후에 바로 다른 UI를 렌더링하는 것은 사용자에게 UI가 삐걱거리는 것처럼 보일 수 있습니다. +이 방법은 두 번 렌더링해야 하기 때문에 Hydration을 느리게 합니다. 느린 통신 상태일 경우에 사용자 경험을 염두하세요. 초기 HTML이 렌더링된 한참 후에야 자바스크립트 코드를 불러옵니다. 따라서 Hydration 이후에 바로 다른 UI를 렌더링하는 것은 사용자에게 UI가 삐걱거리는 것처럼 보일 수 있습니다. --- -### hydrate된 root 컴포넌트를 업데이트하기 {/*updating-a-hydrated-root-component*/} +### Hydration된 루트 컴포넌트를 업데이트하기 {/*updating-a-hydrated-root-component*/} -root의 hydrating이 끝난 이후에, [`root.render`](#root-render)를 호출해 React 컴포넌트의 root를 업데이트 할 수 있습니다. **[`createRoot`](/reference/react-dom/client/createRoot)와는 다르게 HTML로 최초의 컨텐츠가 이미 렌더링 되어 있기 때문에 자주 사용할 필요는 없습니다.** +루트의 Hydration이 끝난 후에, [`root.render`](#root-render)를 호출해 React 컴포넌트의 루트를 업데이트 할 수 있습니다. **[`createRoot`](/reference/react-dom/client/createRoot)와는 다르게 HTML로 최초의 컨텐츠가 이미 렌더링 되어 있기 때문에 자주 사용할 필요는 없습니다.** -hydration 후 어떤 시점에 `root.render`를 호출한다면, 그리고 컴포넌트의 트리 구조가 이전에 렌더링했던 구조와 일치한다면, React는 [상태를 그대로 보존합니다.](/learn/preserving-and-resetting-state) input에 어떻게 타이핑하는지에 따라 문제가 발생하지 않습니다. 즉, 아래 예시에서처럼 매초 마다 상태를 업데이트하는 반복적인 `render`는 문제 없이 렌더링 된다는 것을 볼 수 있습니다: +Hydration 후 어떤 시점에 `root.render`를 호출한다면, 그리고 컴포넌트의 트리 구조가 이전에 렌더링했던 구조와 일치한다면, React는 [State를 그대로 보존합니다.](/learn/preserving-and-resetting-state) 입력 창Input에 어떻게 타이핑하든지 간에 문제가 발생하지 않습니다. 즉, 아래 예시에서처럼 매초 마다 상태를 업데이트하는 반복적인 `render`를 문제 없이 렌더링 한다는 것을 알 수 있습니다. @@ -371,21 +367,11 @@ export default function App({counter}) { -hydrate된 root에서 [`root.render`](#root-render)를 호출하는 것은 흔한 일은 아닙니다. 내부 컴포넌트 중 한 곳에서 [useState](/reference/react/useState)를 하는 것이 일반적입니다. - -### 처리되지 않은 에러에 대한 대화 상자 표시하기 {/*show-a-dialog-for-uncaught-errors*/} - -<<<<<<< HEAD - +Hydration된 루트에서 [`root.render`](#root-render)를 호출하는 것은 흔한 일은 아닙니다. 내부 컴포넌트 중 한 곳에서 [useState](/reference/react/useState)를 사용하는 것이 일반적입니다. -`onUncaughtError`는 최신 React Canary 릴리스에서만 사용할 수 있습니다. +### 처리되지 않은 오류에 대한 대화 상자 표시하기 {/*show-a-dialog-for-uncaught-errors*/} - - -기본적으로 React는 처리되지 않은 모든 에러를 콘솔에 기록합니다. 자체적인 에러 보고 기능을 구현하려면 선택적 root 옵션인 `onUncaughtError`를 사용할 수 있습니다. -======= -By default, React will log all uncaught errors to the console. To implement your own error reporting, you can provide the optional `onUncaughtError` root option: ->>>>>>> b1a249d597016c6584e4c186daa28b180cc9aafc +기본적으로 React는 처리되지 않은 모든 오류를 콘솔에 기록합니다. 자체적인 오류 보고 기능을 구현하려면 선택적 루트 옵션인 `onUncaughtError`를 사용할 수 있습니다. ```js [[1, 7, "onUncaughtError"], [2, 7, "error", 1], [3, 7, "errorInfo"], [4, 11, "componentStack"]] import { hydrateRoot } from 'react-dom/client'; @@ -406,12 +392,12 @@ const root = hydrateRoot( root.render(); ``` -onUncaughtError 옵션은 두 개의 인자를 받는 함수입니다. +onUncaughtError 옵션은 두 개의 인수를 받는 함수입니다. -1. 발생한 에러. -2. 에러의 componentStack을 포함하는 errorInfo 객체. +1. 발생한 error. +2. 오류의 componentStack을 포함하는 errorInfo 객체. -`onUncaughtError` root 옵션을 사용해 에러 대화 상자를 표시할 수 있습니다. +`onUncaughtError` 루트 옵션을 사용해 오류 대화 상자를 표시할 수 있습니다. @@ -423,7 +409,7 @@ root.render();