diff --git a/eslint.config.mjs b/eslint.config.mjs index 555e4d779..f92991585 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,3 +1,4 @@ +/* eslint-disable import/no-anonymous-default-export */ import mark from 'eslint-plugin-mark'; export default [ @@ -8,7 +9,16 @@ export default [ ...mark.configs.baseGfm, files: ['src/content/**/*.md'], rules: { - 'mark/no-double-spaces': 'error', + 'mark/no-curly-quote': [ + 'error', + {leftSingleQuotationMark: false, rightSingleQuotationMark: false}, + ], + 'mark/no-double-space': 'error', + 'mark/no-git-conflict-marker': ['error', {skipCode: false}], + 'mark/no-irregular-whitespace': [ + 'error', + {skipCode: false, skipInlineCode: false}, + ], }, }, ]; diff --git a/package.json b/package.json index c9c5f8d18..099325c89 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "lint-editorconfig": "yarn editorconfig-checker", "textlint-test": "yarn mocha ./textlint/tests/utils && yarn mocha ./textlint/tests/rules", "textlint-docs": "node ./textlint/generators/genTranslateGlossaryDocs.js && git add wiki/translate-glossary.md", - "textlint-lint": "yarn textlint ./src/content --rulesdir ./textlint/rules -f pretty-error" + "textlint-lint": "yarn textlint ./src/content --rulesdir ./textlint/rules -f pretty-error && npx --yes eslint@9 -c eslint.config.mjs" }, "dependencies": { "@codesandbox/sandpack-react": "2.13.5", @@ -72,7 +72,7 @@ "eslint-plugin-flowtype": "4.x", "eslint-plugin-import": "2.x", "eslint-plugin-jsx-a11y": "6.x", - "eslint-plugin-mark": "^0.1.0-canary.1", + "eslint-plugin-mark": "^0.1.0-canary.2", "eslint-plugin-react": "7.x", "eslint-plugin-react-compiler": "^19.0.0-beta-e552027-20250112", "eslint-plugin-react-hooks": "^0.0.0-experimental-fabef7a6b-20221215", diff --git a/src/components/MDX/ErrorDecoder.tsx b/src/components/MDX/ErrorDecoder.tsx index b04fa9f79..a9b7455df 100644 --- a/src/components/MDX/ErrorDecoder.tsx +++ b/src/components/MDX/ErrorDecoder.tsx @@ -69,7 +69,7 @@ function parseQueryString(search: string): Array { } export default function ErrorDecoder() { - const {errorMessage} = useErrorDecoderParams(); + const {errorMessage, errorCode} = useErrorDecoderParams(); /** error messages that contain %s require reading location.search */ const hasParams = errorMessage?.includes('%s'); const [message, setMessage] = useState(() => @@ -82,23 +82,28 @@ export default function ErrorDecoder() { if (errorMessage == null || !hasParams) { return; } + const args = parseQueryString(window.location.search); + let message = errorMessage; + if (errorCode === '418') { + // Hydration errors have a %s for the diff, but we don't add that to the args for security reasons. + message = message.replace(/%s$/, ''); - setMessage( - urlify( - replaceArgs( - errorMessage, - parseQueryString(window.location.search), - '[missing argument]' - ) - ) - ); + // Before React 19.1, the error message didn't have an arg, and was always HTML. + if (args.length === 0) { + args.push('HTML'); + } else if (args.length === 1 && args[0] === '') { + args[0] = 'HTML'; + } + } + + setMessage(urlify(replaceArgs(message, args, '[missing argument]'))); setIsReady(true); - }, [hasParams, errorMessage]); + }, [errorCode, hasParams, errorMessage]); return ( {message} diff --git a/src/components/MDX/Sandpack/template.ts b/src/components/MDX/Sandpack/template.ts index 42f02f6a6..7fbd537e7 100644 --- a/src/components/MDX/Sandpack/template.ts +++ b/src/components/MDX/Sandpack/template.ts @@ -28,8 +28,8 @@ root.render( eject: 'react-scripts eject', }, dependencies: { - react: '19.0.0-rc-3edc000d-20240926', - 'react-dom': '19.0.0-rc-3edc000d-20240926', + react: '^19.1.0', + 'react-dom': '^19.1.0', 'react-scripts': '^5.0.0', }, }, diff --git a/src/content/blog/2024/12/05/react-19.md b/src/content/blog/2024/12/05/react-19.md index b7a976108..e825af400 100644 --- a/src/content/blog/2024/12/05/react-19.md +++ b/src/content/blog/2024/12/05/react-19.md @@ -4,7 +4,7 @@ author: The React Team date: 2024/12/05 description: React 19 is now available on npm! In this post, we'll give an overview of the new features in React 19, and how you can adopt them. --- - +{/**/} December 05, 2024 by [The React Team](/community/team) --- diff --git a/src/content/community/meetups.md b/src/content/community/meetups.md index b3290a004..186740341 100644 --- a/src/content/community/meetups.md +++ b/src/content/community/meetups.md @@ -81,7 +81,7 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet * [Thessaloniki](https://www.meetup.com/Thessaloniki-ReactJS-Meetup/) ## India {/*india*/} -* [Ahmedabad](https://www.meetup.com/react-ahmedabad/) +* [Ahmedabad](https://reactahmedabad.dev/) * [Bangalore (React)](https://www.meetup.com/ReactJS-Bangalore/) * [Bangalore (React Native)](https://www.meetup.com/React-Native-Bangalore-Meetup) * [Chennai](https://www.linkedin.com/company/chennaireact) @@ -169,6 +169,7 @@ Do you have a local React.js meetup? Add it here! (Please keep the list alphabet * [Cleveland, OH - ReactJS](https://www.meetup.com/Cleveland-React/) * [Columbus, OH - ReactJS](https://www.meetup.com/ReactJS-Columbus-meetup/) * [Dallas, TX - ReactJS](https://www.meetup.com/ReactDallas/) +* [Denver, CO - React Denver](https://reactdenver.com/) * [Detroit, MI - Detroit React User Group](https://www.meetup.com/Detroit-React-User-Group/) * [Indianapolis, IN - React.Indy](https://www.meetup.com/React-Indy) * [Irvine, CA - ReactJS](https://www.meetup.com/ReactJS-OC/) diff --git a/src/content/community/versioning-policy.md b/src/content/community/versioning-policy.md index 64b022f09..711bac32b 100644 --- a/src/content/community/versioning-policy.md +++ b/src/content/community/versioning-policy.md @@ -11,7 +11,7 @@ This versioning policy describes our approach to version numbers for packages su ## Stable releases {/*stable-releases*/} -Stable React releases (also known as “Latest” release channel) follow [semantic versioning (semver)](https://semver.org/lang/ko/) principles. +Stable React releases (also known as "Latest" release channel) follow [semantic versioning (semver)](https://semver.org/lang/ko/) principles. 버전 번호 **x.y.z**를 사용할 때 다음과 같습니다. diff --git a/src/content/learn/build-a-react-app-from-scratch.md b/src/content/learn/build-a-react-app-from-scratch.md index 9a695ff8d..0860cf8c0 100644 --- a/src/content/learn/build-a-react-app-from-scratch.md +++ b/src/content/learn/build-a-react-app-from-scratch.md @@ -65,7 +65,7 @@ Rsbuild includes built-in support for React features like fast refresh, JSX, Typ #### Metro for React Native {/*react-native*/} -If you'd you're starting from scratch with React Native you'll need to use [Metro](https://metrobundler.dev/), the JavaScript bundler for React Native. Metro supports bundling for platforms like iOS and Android, but lacks many features when compared to the tools here. We recommend starting with Vite, Parcel, or Rsbuild unless your project requires React Native support. +If you're starting from scratch with React Native you'll need to use [Metro](https://metrobundler.dev/), the JavaScript bundler for React Native. Metro supports bundling for platforms like iOS and Android, but lacks many features when compared to the tools here. We recommend starting with Vite, Parcel, or Rsbuild unless your project requires React Native support. @@ -83,7 +83,7 @@ Routers are a core part of modern applications, and are usually integrated with We suggest using: -- [React Router](https://reactrouter.com/start/framework/custom) +- [React Router](https://reactrouter.com/start/data/custom) - [Tanstack Router](https://tanstack.com/router/latest) diff --git a/src/content/learn/index.md b/src/content/learn/index.md index dfe86ba5e..ae23d32f3 100644 --- a/src/content/learn/index.md +++ b/src/content/learn/index.md @@ -475,7 +475,7 @@ export default function MyApp() { } ``` -이렇게 전달한 정보를 *props*라고 합니다. 이제 `MyApp` 컴포넌트는 `count` state와 `handleClick` 이벤트 핸들러를 포함하며, *이 두 가지를 각 버튼에 props로 전달합니다*. +이렇게 전달한 정보를 *props*라고 합니다. 이제 `MyApp` 컴포넌트는 `count` state와 `handleClick` 이벤트 핸들러를 포함하며, *이 두 가지를 각 버튼에 props로 전달합니다*. 마지막으로 부모 컴포넌트에서 전달한 props를 *읽도록* `MyButton`을 변경합니다. diff --git a/src/content/learn/installation.md b/src/content/learn/installation.md index 2196c5e51..1d17244e4 100644 --- a/src/content/learn/installation.md +++ b/src/content/learn/installation.md @@ -68,7 +68,6 @@ If a framework is not a good fit for your project, you prefer to build your own No. Create React App has been deprecated. For more information, see [Sunsetting Create React App](/blog/2025/02/14/sunsetting-create-react-app). ->>>>>>> ab18d2f0f5151ab0c927a12eb0a64f8170762eff ## 다음 단계 {/*next-steps*/} diff --git a/src/content/learn/queueing-a-series-of-state-updates.md b/src/content/learn/queueing-a-series-of-state-updates.md index 27e6a6fd0..3e6d3b2d3 100644 --- a/src/content/learn/queueing-a-series-of-state-updates.md +++ b/src/content/learn/queueing-a-series-of-state-updates.md @@ -126,7 +126,7 @@ React가 이벤트 핸들러를 수행하는 동안 여러 코드를 통해 작 React는 `3`을 최종 결과로 저장하고 `useState`에서 반환합니다. -이것이 위 예시 "+3"을 클릭하면 값이 3씩 올바르게 증가하는 이유입니다. +이것이 위 예시 "+3"을 클릭하면 값이 3씩 올바르게 증가하는 이유입니다. ### state를 교체한 후 업데이트하면 어떻게 되나요? {/*what-happens-if-you-update-state-after-replacing-it*/} @@ -230,7 +230,7 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; } 1. `setNumber(number + 5)`: `number` 는 `0` 이므로 `setNumber(0 + 5)`입니다. React는 *"`5`로 바꾸기"* 를 큐에 추가합니다. 2. `setNumber(n => n + 1)`: `n => n + 1` 는 업데이터 함수입니다. React는 *이 함수*를 큐에 추가합니다. -3. `setNumber(42)`: React는 *"`42`로 바꾸기"* 를 큐에 추가합니다. +3. `setNumber(42)`: React는 *"`42`로 바꾸기"* 를 큐에 추가합니다. 다음 렌더링하는 동안, React는 state 큐를 순회합니다. diff --git a/src/content/learn/reusing-logic-with-custom-hooks.md b/src/content/learn/reusing-logic-with-custom-hooks.md index ea22995fe..917e68fc3 100644 --- a/src/content/learn/reusing-logic-with-custom-hooks.md +++ b/src/content/learn/reusing-logic-with-custom-hooks.md @@ -922,7 +922,7 @@ export function useChatRoom({ serverUrl, roomId, onReceiveMessage }) { } ``` -이제 `ChatRoom`가 재렌더링될 때마다 채팅방이 재연결되지 않습니다. 여기 커스텀 Hook에 이벤트 핸들러를 넘겨주는 직접 다뤄볼 수 있는 제대로 동작하는 예시가 있습니다. +이제 `ChatRoom`가 재렌더링될 때마다 채팅방이 재연결되지 않습니다. 여기 커스텀 Hook에 이벤트 핸들러를 넘겨주는 직접 다뤄볼 수 있는 제대로 동작하는 예시가 있습니다. @@ -1332,7 +1332,7 @@ export function useOnlineStatus() { 위의 예시에서 `useOnlineStatus`는 한 쌍의 [`useState`](/reference/react/useState)와 [`useEffect`](/reference/react/useEffect)와 함께 실행됩니다. 하지만 이건 가장 좋은 해결 방법은 아닙니다. 이 해결 방법이 고려하지 못한 수많은 예외 상황이 존재합니다. 예를 들어, 이건 컴포넌트가 마운트됐을 때, `isOnline`이 이미 `true`라고 가정합니다. 하지만 이것은 네트워크가 이미 꺼졌을 때 틀린 가정이 됩니다. 이런 상황을 확인하기 위해 브라우저 [`navigator.onLine`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine) API를 사용할 수도 있습니다. 하지만 이걸 직접적으로 사용하게 되면 초기 HTML을 생성하기 위한 서버에선 동작하지 않습니다. 짧게 말하면 코드는 보완되어야 합니다. -운 좋게도 React 18은 이런 모든 문제를 신경 써주는 [`useSyncExternalStore`](/reference/react/useSyncExternalStore)라고 불리는 섬세한 API를 포함합니다. 여기 새 API의 장점을 가지고 다시 쓰인 `useOnlineStatus`이 있습니다. +React는 이런 모든 문제를 신경 써주는 [`useSyncExternalStore`](/reference/react/useSyncExternalStore)라고 불리는 섬세한 API를 포함합니다. 여기 새 API의 장점을 가지고 다시 쓰인 `useOnlineStatus`이 있습니다. diff --git a/src/content/learn/sharing-state-between-components.md b/src/content/learn/sharing-state-between-components.md index 35f77247e..3d74ae5e8 100644 --- a/src/content/learn/sharing-state-between-components.md +++ b/src/content/learn/sharing-state-between-components.md @@ -125,7 +125,7 @@ state를 올리려면, 조정하려는 *두* 자식 컴포넌트의 가장 가 - `Panel` - `Panel` -예시에서는 `Accordion` 컴포넌트입니다. 이 컴포넌트는 두 패널의 상위에 있고 props를 제어할 수 있기 때문에 현재 어느 패널이 활성화되었는지에 대한 "진리의 원천(source of truth)"이 됩니다. `Accordion` 컴포넌트가 하드 코딩된 값을 가지는 `isActive`를 (예를 들면 `true`) 두 패널에 전달하도록 만듭니다. +예시에서는 `Accordion` 컴포넌트입니다. 이 컴포넌트는 두 패널의 상위에 있고 props를 제어할 수 있기 때문에 현재 어느 패널이 활성화되었는지에 대한 "진리의 원천(source of truth)"이 됩니다. `Accordion` 컴포넌트가 하드 코딩된 값을 가지는 `isActive`를 (예를 들면 `true`) 두 패널에 전달하도록 만듭니다. diff --git a/src/content/learn/tutorial-tic-tac-toe.md b/src/content/learn/tutorial-tic-tac-toe.md index 3425eb723..632bb4dfd 100644 --- a/src/content/learn/tutorial-tic-tac-toe.md +++ b/src/content/learn/tutorial-tic-tac-toe.md @@ -944,7 +944,7 @@ export default function Board() { } ``` -`Array(9).fill(null)`은 9개의 엘리먼트로 배열을 생성하고 각 엘리먼트를 `null`로 설정합니다. 그 주위에 있는 `useState()` 호출은 처음에 해당 배열로 설정된 state 변수 `squares`를 선언합니다. 배열의 각 항목은 사각형의 값에 해당합니다. 나중에 보드를 채우면, `squares` 배열은 다음과 같은 모양이 됩니다. +`Array(9).fill(null)`은 9개의 엘리먼트로 배열을 생성하고 각 엘리먼트를 `null`로 설정합니다. 그 주위에 있는 `useState()` 호출은 처음에 해당 배열로 설정된 state 변수 `squares`를 선언합니다. 배열의 각 항목은 사각형의 값에 해당합니다. 나중에 보드를 채우면, `squares` 배열은 다음과 같은 모양이 됩니다. ```jsx ['O', null, 'X', 'X', 'X', 'O', 'O', null, null] diff --git a/src/content/reference/react-dom/components/input.md b/src/content/reference/react-dom/components/input.md index da36b2f13..d23c7189c 100644 --- a/src/content/reference/react-dom/components/input.md +++ b/src/content/reference/react-dom/components/input.md @@ -56,7 +56,7 @@ You can [make an input controlled](#controlling-an-input-with-a-state-variable) * [`dirname`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#dirname): 문자열 타입. 엘리먼트 방향성에 대한 폼 필드 이름을 지정합니다. * [`disabled`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#disabled): 불리언 타입. `true`일 경우, 입력은 상호작용이 불가능해지며 흐릿하게 보입니다. * `children`: `` 은 자식을 받지 않습니다. -* [`form`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#form): 문자열 타입. 입력이 속하는 `
`의 `id`를 지정합니다. 생략 시 가장 가까운 부모 폼으로 설정됩니다. +* [`form`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#form): 문자열 타입. 입력이 속하는 ``의 `id`를 지정합니다. 생략 시 가장 가까운 부모 폼으로 설정됩니다. * [`formAction`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#formaction): 문자열 타입. `type="submit"` 과 `type="image"`의 부모 `` 을 덮어씁니다. * [`formEnctype`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#formenctype): 문자열 타입. `type="submit"` 과 `type="image"`의 부모 `` 을 덮어씁니다. * [`formMethod`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#formmethod): 문자열 타입. `type="submit"` 과 `type="image"`의 부모 `` 를 덮어씁니다. diff --git a/src/content/reference/react/Component.md b/src/content/reference/react/Component.md index a23eb46c7..aa77ca776 100644 --- a/src/content/reference/react/Component.md +++ b/src/content/reference/react/Component.md @@ -1273,7 +1273,7 @@ button { margin-left: 10px; } error boundary 컴포넌트를 구현하려면 오류에 대한 응답으로 state를 업데이트하고 사용자에게 오류 메시지를 표시할 수 있는 [`static getDerivedStateFromError`](#static-getderivedstatefromerror)를 제공해야 합니다. 또한 선택적으로 [`componentDidCatch`](#componentdidcatch)를 구현하여 분석 서비스에 오류를 기록하는 등의 추가 로직을 추가할 수도 있습니다. - With [`captureOwnerStack`](/reference/react/captureOwnerStack) you can include the Owner Stack during development. +With [`captureOwnerStack`](/reference/react/captureOwnerStack) you can include the Owner Stack during development. ```js {9-12,14-27} import * as React from 'react'; @@ -1298,8 +1298,7 @@ class ErrorBoundary extends React.Component { // in div (created by App) // in App info.componentStack, - // Only available in react@canary. - // Warning: Owner Stack is not available in production. + // Warning: `captureOwnerStack` is not available in production. React.captureOwnerStack(), ); } diff --git a/src/content/reference/react/StrictMode.md b/src/content/reference/react/StrictMode.md index 718548768..7b53a502c 100644 --- a/src/content/reference/react/StrictMode.md +++ b/src/content/reference/react/StrictMode.md @@ -89,7 +89,7 @@ Strict Mode에서는 개발 시 다음과 같은 검사를 가능하게 합니 - 컴포넌트가 순수하지 않은 렌더링으로 인한 버그를 찾기 위해 [추가로 다시 렌더링합니다.](#fixing-bugs-found-by-double-rendering-in-development) - 컴포넌트가 Effect 클린업이 누락되어 발생한 버그를 찾기 위해 [Effect를 다시 실행합니다.](#fixing-bugs-found-by-re-running-effects-in-development) -- Your components will [re-run ref callbacks an extra time](#fixing-bugs-found-by-cleaning-up-and-re-attaching-dom-refs-in-development) to find bugs caused by missing ref cleanup. +- Your components will [re-run refs callbacks an extra time](#fixing-bugs-found-by-re-running-ref-callbacks-in-development) to find bugs caused by missing ref cleanup. - 컴포넌트가 [더 이상 사용되지 않는 API를 사용하는지 확인합니다.](#fixing-deprecation-warnings-enabled-by-strict-mode) @@ -124,6 +124,12 @@ function App() { 이 예시에서 `Header`와 `Footer` 컴포넌트에서는 Strict Mode 검사가 실행되지 않습니다. 그러나 `Sidebar`와 `Content`, 그리고 그 자손 컴포넌트는 깊이에 상관없이 검사가 실행됩니다. + + +When `StrictMode` is enabled for a part of the app, React will only enable behaviors that are possible in production. For example, if `` is not enabled at the root of the app, it will not [re-run Effects an extra time](#fixing-bugs-found-by-re-running-effects-in-development) on initial mount, since this would cause child effects to double fire without the parent effects, which cannot happen in production. + + + --- ### 개발 중 이중 렌더링으로 발견한 버그 수정 {/*fixing-bugs-found-by-double-rendering-in-development*/} diff --git a/src/content/reference/react/act.md b/src/content/reference/react/act.md index c474645ed..5bac94256 100644 --- a/src/content/reference/react/act.md +++ b/src/content/reference/react/act.md @@ -27,7 +27,7 @@ You might find using `act()` directly a bit too verbose. To avoid some of the bo ### `await act(async actFn)` {/*await-act-async-actfn*/} -When writing UI tests, tasks like rendering, user events, or data fetching can be considered as “units” of interaction with a user interface. React provides a helper called `act()` that makes sure all updates related to these “units” have been processed and applied to the DOM before you make any assertions. +When writing UI tests, tasks like rendering, user events, or data fetching can be considered as "units" of interaction with a user interface. React provides a helper called `act()` that makes sure all updates related to these "units" have been processed and applied to the DOM before you make any assertions. The name `act` comes from the [Arrange-Act-Assert](https://wiki.c2.com/?ArrangeActAssert) pattern. diff --git a/src/content/reference/react/captureOwnerStack.md b/src/content/reference/react/captureOwnerStack.md index f8ed21a8c..6d8cc502d 100644 --- a/src/content/reference/react/captureOwnerStack.md +++ b/src/content/reference/react/captureOwnerStack.md @@ -2,12 +2,6 @@ title: captureOwnerStack --- - - -The `captureOwnerStack` API is currently only available in React's Canary and experimental channels. Learn more about [React's release channels here](/community/versioning-policy#all-release-channels). - - - `captureOwnerStack` reads the current Owner Stack in development and returns it as a string if available. @@ -126,22 +120,6 @@ createRoot(document.createElement('div'), { ); ``` -```json package.json hidden -{ - "dependencies": { - "react": "canary", - "react-dom": "canary", - "react-scripts": "latest" - }, - "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test --env=jsdom", - "eject": "react-scripts eject" - } -} -``` - ```html public/index.html hidden @@ -357,22 +335,6 @@ const container = document.getElementById("root"); createRoot(container).render(); ``` -```json package.json hidden -{ - "dependencies": { - "react": "canary", - "react-dom": "canary", - "react-scripts": "latest" - }, - "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test --env=jsdom", - "eject": "react-scripts eject" - } -} -``` - ```js src/App.js function Component() { return ; @@ -417,22 +379,6 @@ export default function App() { } ``` -```json package.json hidden -{ - "dependencies": { - "react": "canary", - "react-dom": "canary", - "react-scripts": "latest" - }, - "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test --env=jsdom", - "eject": "react-scripts eject" - } -} -``` - ### `captureOwnerStack` is not available {/*captureownerstack-is-not-available*/} diff --git a/src/content/reference/react/experimental_taintUniqueValue.md b/src/content/reference/react/experimental_taintUniqueValue.md index fd028f04d..89285d810 100644 --- a/src/content/reference/react/experimental_taintUniqueValue.md +++ b/src/content/reference/react/experimental_taintUniqueValue.md @@ -55,7 +55,7 @@ experimental_taintUniqueValue( #### 매개변수 {/*parameters*/} -* `message`: 클라이언트 컴포넌트에 `value`가 전달될 경우 표시하고자 하는 메시지입니다. 이 메시지는 `value`가 클라이언트 컴포넌트에 전달될 경우 발생하는 오류의 일부로 표시됩니다. +* `message`: 클라이언트 컴포넌트에 `value`가 전달될 경우 표시하고자 하는 메시지입니다. 이 메시지는 `value`가 클라이언트 컴포넌트에 전달될 경우 발생하는 오류의 일부로 표시됩니다. * `lifetime`: `value`가 얼마나 오랫동안 오염Taint 상태를 유지해야 하는지를 나타내는 객체입니다.`value`는 이 객체가 존재하는 동안 클라이언트 컴포넌트로 전달되지 않도록 차단됩니다. 예를 들어 `globalThis`를 전달하면 앱이 종료될 때까지 값이 차단됩니다. `lifetime`은 일반적으로 `value`를 프로퍼티로 가지는 객체입니다. diff --git a/src/content/reference/react/useActionState.md b/src/content/reference/react/useActionState.md index 30a7d720e..0839e8003 100644 --- a/src/content/reference/react/useActionState.md +++ b/src/content/reference/react/useActionState.md @@ -270,7 +270,7 @@ form button { ### 액션이 더 이상 제출된 폼 데이터를 읽을 수 없습니다 {/*my-action-can-no-longer-read-the-submitted-form-data*/} -액션을 `useActionState`로 감싸면 *첫 번째 인수*로 “이전(또는 현재) State”가 추가됩니다. 따라서 일반적인 폼 액션과 달리, 제출된 폼 데이터는 *두 번째 인수*에서 확인해야 합니다. +액션을 `useActionState`로 감싸면 *첫 번째 인수*로 "이전(또는 현재) State"가 추가됩니다. 따라서 일반적인 폼 액션과 달리, 제출된 폼 데이터는 *두 번째 인수*에서 확인해야 합니다. ```js function action(currentState, formData) { diff --git a/src/content/reference/react/useCallback.md b/src/content/reference/react/useCallback.md index 74481136c..ed73881cd 100644 --- a/src/content/reference/react/useCallback.md +++ b/src/content/reference/react/useCallback.md @@ -222,7 +222,7 @@ function useCallback(fn, dependencies) { - [`memo`](/reference/react/memo)로 감싸진 컴포넌트에 prop으로 넘깁니다. 이 값이 변하지 않으면 리렌더링을 건너뛰고 싶습니다. memoization은 의존성이 변했을 때만 컴포넌트가 리렌더링하도록 합니다. - 넘긴 함수가 나중에 어떤 Hook의 의존성으로 사용됩니다. 예를 들어, `useCallback`으로 감싸진 다른 함수가 이 함수에 의존하거나, [`useEffect`](/reference/react/useEffect)에서 이 함수에 의존합니다. -다른 경우에서 `useCallback`으로 함수를 감싸는 것은 아무런 이익이 없습니다. 또한 이렇게 하는 것이 큰 불이익을 가져오지도 않으므로 일부 팀은 개별적인 경우를 따로 생각하지 않고, 가능한 한 많이 memoization하는 방식을 택합니다. 단점은 코드의 가독성이 떨어지는 것입니다. 또한, 모든 memoization이 효과적인 것은 아닙니다. "항상 새로운" 하나의 값이 있다면 전체 컴포넌트의 memoization을 깨기에 충분합니다. +다른 경우에서 `useCallback`으로 함수를 감싸는 것은 아무런 이익이 없습니다. 또한 이렇게 하는 것이 큰 불이익을 가져오지도 않으므로 일부 팀은 개별적인 경우를 따로 생각하지 않고, 가능한 한 많이 memoization하는 방식을 택합니다. 단점은 코드의 가독성이 떨어지는 것입니다. 또한, 모든 memoization이 효과적인 것은 아닙니다. "항상 새로운" 하나의 값이 있다면 전체 컴포넌트의 memoization을 깨기에 충분합니다. `useCallback`이 함수의 *생성*을 막지 않는다는 점을 주의하세요. 항상 함수를 생성하지만 (이건 괜찮습니다!), 그러나 React는 변경이 없는 경우에는 무시하고 캐시된 함수를 반환합니다 diff --git a/src/content/reference/react/useContext.md b/src/content/reference/react/useContext.md index 987132fc3..3febeed3a 100644 --- a/src/content/reference/react/useContext.md +++ b/src/content/reference/react/useContext.md @@ -1188,7 +1188,7 @@ footer { #### 자동으로 중첩된 제목 {/*automatically-nested-headings*/} -Ccontext Provider를 중첩할 때 정보를 "누적"할 수 있습니다. 이 예시에서 `Section` 컴포넌트는 섹션 중첩의 깊이를 지정하는 `LevelContext`를 추적합니다. 이 컴포넌트는 부모 섹션에서 `LevelContext`를 읽은 다음 1씩 증가한 `LevelContext` 숫자를 자식에게 제공합니다. 그 결과 `Heading` 컴포넌트는 얼마나 많은 `Section` 컴포넌트가 중첩되어 있는지에 따라 `

`, `

`, `

`, ..., 태그 중 어떤 태그를 사용할지 자동으로 결정할 수 있습니다. +Ccontext Provider를 중첩할 때 정보를 "누적"할 수 있습니다. 이 예시에서 `Section` 컴포넌트는 섹션 중첩의 깊이를 지정하는 `LevelContext`를 추적합니다. 이 컴포넌트는 부모 섹션에서 `LevelContext`를 읽은 다음 1씩 증가한 `LevelContext` 숫자를 자식에게 제공합니다. 그 결과 `Heading` 컴포넌트는 얼마나 많은 `Section` 컴포넌트가 중첩되어 있는지에 따라 `

`, `

`, `

`, ..., 태그 중 어떤 태그를 사용할지 자동으로 결정할 수 있습니다. 이 예시에 대한 [자세한 안내](/learn/passing-data-deeply-with-context)를 읽어보세요. diff --git a/src/content/reference/react/useImperativeHandle.md b/src/content/reference/react/useImperativeHandle.md index 8e550ffa4..8de388290 100644 --- a/src/content/reference/react/useImperativeHandle.md +++ b/src/content/reference/react/useImperativeHandle.md @@ -294,5 +294,5 @@ export default AddComment; **ref를 과도하게 사용하지 마세요.** ref는 props로 표현할 수 없는 필수적인 행동에만 사용해야 합니다. 예를 들어 특정 노드로 스크롤 하기, 노드에 초점 맞추기, 애니메이션 촉발하기, 텍스트 선택하기 등이 있습니다. -**prop으로 표현할 수 있는 것은 ref를 사용하지 마세요.** 예를 들어 `Modal` 컴포넌트에서 `{ open, close }` 와 같은 imperative handle을 노출하는 대신 ``과 같은 `isOpen` prop을 사용하는 것이 더 좋습니다. [Effects](/learn/synchronizing-with-effects)를 사용하면 prop을 통해 명령형 동작(imperative behavior)을 노출할 수 있습니다. +**prop으로 표현할 수 있는 것은 ref를 사용하지 마세요.** 예를 들어 `Modal` 컴포넌트에서 `{ open, close }` 와 같은 imperative handle을 노출하는 대신 ``과 같은 `isOpen` prop을 사용하는 것이 더 좋습니다. [Effects](/learn/synchronizing-with-effects)를 사용하면 prop을 통해 명령형 동작(imperative behavior)을 노출할 수 있습니다. diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index 4123af521..e2fcc16b5 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -84,7 +84,7 @@ function TodoList({ todos, tab, theme }) { 초기 렌더링에서 `useMemo`에서 얻을 수 있는 계산 함수를 호출한 결과값 입니다. -이후 모든 렌더링에서 React는 종속성 목록을 마지막 렌더링 중에 전달한 종속성 목록과 비교합니다. 만일 ([`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)와 비교했을 때) 종속성이 변경되지 않았다면, `useMemo`는 이전에 이미 계산해둔 값을 반환합니다. 그렇지 않다면 React는 계산을 다시 실행하고 새로운 값을 반환합니다. +이후 모든 렌더링에서 React는 종속성 목록을 마지막 렌더링 중에 전달한 종속성 목록과 비교합니다. 만일 ([`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)와 비교했을 때) 종속성이 변경되지 않았다면, `useMemo`는 이전에 이미 계산해둔 값을 반환합니다. 그렇지 않다면 React는 계산을 다시 실행하고 새로운 값을 반환합니다. 즉, `useMemo`는 종속성이 변경되기 전까지 재렌더링 사이의 계산 결과를 캐싱합니다. diff --git a/src/content/reference/react/useSyncExternalStore.md b/src/content/reference/react/useSyncExternalStore.md index ef0b3692c..8665c6640 100644 --- a/src/content/reference/react/useSyncExternalStore.md +++ b/src/content/reference/react/useSyncExternalStore.md @@ -40,7 +40,7 @@ store에 있는 데이터의 스냅샷을 반환합니다. 두 개의 함수를 #### 매개변수 {/*parameters*/} -* `subscribe`: 하나의 `callback` 인수를 받아 store에 구독하는 함수입니다. store가 변경될 때, 제공된 `callback`이 호출되어 React가 `getSnapshot`을 다시 호출하고 (필요한 경우) 컴포넌트를 다시 렌더링하도록 해야 합니다. `subscribe` 함수는 구독을 정리하는 함수를 반환해야 합니다. +* `subscribe`: 하나의 `callback` 인수를 받아 store에 구독하는 함수입니다. store가 변경될 때, 제공된 `callback`이 호출되어 React가 `getSnapshot`을 다시 호출하고 (필요한 경우) 컴포넌트를 다시 렌더링하도록 해야 합니다. `subscribe` 함수는 구독을 정리하는 함수를 반환해야 합니다. * `getSnapshot`: 컴포넌트에 필요한 store 데이터의 스냅샷을 반환하는 함수입니다. store가 변경되지 않은 상태에서 `getSnapshot`을 반복적으로 호출하면 동일한 값을 반환해야 합니다. 저장소가 변경되어 반환된 값이 다르면 ([`Object.is`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/is)와 비교하여) React는 컴포넌트를 리렌더링합니다. @@ -404,14 +404,14 @@ store 데이터가 변경 가능한 경우 `getSnapshot` 함수는 해당 데이 subscribe 함수는 컴포넌트 내부에 정의되므로 리렌더링할 때마다 달라집니다. -```js {4-7} +```js {2-5} function ChatIndicator() { - const isOnline = useSyncExternalStore(subscribe, getSnapshot); - - // 🚩항상 다른 함수를 사용하므로 React는 렌더링할 때마다 다시 구독합니다. + // 🚩 항상 다른 함수를 사용하므로 React는 렌더링할 때마다 다시 구독합니다. function subscribe() { // ... } + + const isOnline = useSyncExternalStore(subscribe, getSnapshot); // ... } @@ -419,28 +419,28 @@ function ChatIndicator() { 리렌더링 사이에 다른 `subscribe` 함수를 전달하면 React가 store를 다시 구독합니다. 이로 인해 성능 문제가 발생하고 store 재구독을 피하고 싶다면 `subscribe` 함수를 외부로 이동하세요. -```js {6-9} -function ChatIndicator() { - const isOnline = useSyncExternalStore(subscribe, getSnapshot); +```js {1-4} +// ✅ 항상 동일한 함수이므로 React는 다시 구독할 필요가 없습니다. +function subscribe() { // ... } -// ✅ 항상 동일한 함수이므로 React는 다시 구독할 필요가 없습니다. -function subscribe() { +function ChatIndicator() { + const isOnline = useSyncExternalStore(subscribe, getSnapshot); // ... } ``` 또는 일부 인수가 변경될 때만 다시 구독하도록 `subscribe`을 [`useCallback`](/reference/react/useCallback)으로 래핑합니다. -```js {4-8} +```js {2-5} function ChatIndicator({ userId }) { - const isOnline = useSyncExternalStore(subscribe, getSnapshot); - // ✅ userId가 변경되지 않는 한 동일한 함수입니다. const subscribe = useCallback(() => { // ... }, [userId]); + + const isOnline = useSyncExternalStore(subscribe, getSnapshot); // ... } diff --git a/src/content/reference/rules/index.md b/src/content/reference/rules/index.md index 4c28026ba..b13253347 100644 --- a/src/content/reference/rules/index.md +++ b/src/content/reference/rules/index.md @@ -47,6 +47,6 @@ React를 사용하여 UI를 표현하는 방법에 대해 더 알고 싶다면 [ 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을 최상위 레벨에서만 호출하세요](/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) – 일반 자바스크립트 함수에서 Hook을 호출하지 마세요. diff --git a/src/pages/errors/[errorCode].tsx b/src/pages/errors/[errorCode].tsx index de9eab5bb..a67c5742d 100644 --- a/src/pages/errors/[errorCode].tsx +++ b/src/pages/errors/[errorCode].tsx @@ -36,7 +36,7 @@ export default function ErrorDecoderPage({ }} routeTree={sidebarLearn as RouteItem} section="unknown"> -
{parsedContent}
+
{parsedContent}
{/*

We highly recommend using the development build locally when debugging diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 2d4bbc48f..9b24f8787 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -117,6 +117,9 @@ { "title": "cache", "path": "/reference/react/cache" + }, { + "title": "captureOwnerStack", + "path": "/reference/react/captureOwnerStack" }, { "title": "createContext", @@ -147,11 +150,6 @@ "title": "experimental_taintUniqueValue", "path": "/reference/react/experimental_taintUniqueValue", "version": "canary" - }, - { - "title": "captureOwnerStack", - "path": "/reference/react/captureOwnerStack", - "version": "canary" } ] }, diff --git a/src/siteConfig.js b/src/siteConfig.js index 42e89d114..4f777d1a2 100644 --- a/src/siteConfig.js +++ b/src/siteConfig.js @@ -2,7 +2,7 @@ * Copyright (c) Facebook, Inc. and its affiliates. */ exports.siteConfig = { - version: '19', + version: '19.1', // -------------------------------------- // Translations should replace these lines: languageCode: 'ko', diff --git a/yarn.lock b/yarn.lock index 15712dd27..8906c54e4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3912,10 +3912,10 @@ eslint-plugin-jsx-a11y@^6.4.1: safe-regex-test "^1.0.3" string.prototype.includes "^2.0.0" -eslint-plugin-mark@^0.1.0-canary.1: - version "0.1.0-canary.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-mark/-/eslint-plugin-mark-0.1.0-canary.1.tgz#257057e4ef2e8068791b49ee7f99c013beb2b927" - integrity sha512-sbQlw+p36JxiyeVhQhOAPfGiKOM15ZMNXrhb9b2h8iH94HvKxIOYJBUPPObtX5cmHUU0F/KdCtJQ1vPE0D9B7A== +eslint-plugin-mark@^0.1.0-canary.2: + version "0.1.0-canary.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-mark/-/eslint-plugin-mark-0.1.0-canary.2.tgz#b7b05eb6201aab0f3225c99f1c7274c4a0fde3e3" + integrity sha512-0I+AndOwAIkuX/qYthEGr3BfgW0nkIJSPfUAsdhoAXoWjJU60PUMgesPmvz512SEYNZ9T0ojibJqjpoUZIf+Kw== dependencies: "@eslint/markdown" "^6.3.0" "@types/mdast" "^4.0.4"