From 4f56a26897dd3eb087da8297366599efa30e0528 Mon Sep 17 00:00:00 2001 From: "youngsun.min" Date: Fri, 30 Oct 2020 22:20:18 +0900 Subject: [PATCH 1/6] Translate Advanced Guides > Forwarding Refs --- content/docs/forwarding-refs.md | 62 +++++++++---------- .../customized-display-name.js | 4 +- examples/forwarding-refs/fancy-button-ref.js | 9 +-- .../fancy-button-simple-ref.js | 2 +- examples/forwarding-refs/fancy-button.js | 4 +- examples/forwarding-refs/log-props-after.js | 8 +-- 6 files changed, 45 insertions(+), 44 deletions(-) diff --git a/content/docs/forwarding-refs.md b/content/docs/forwarding-refs.md index 3318d8499..e9690fefd 100644 --- a/content/docs/forwarding-refs.md +++ b/content/docs/forwarding-refs.md @@ -4,73 +4,73 @@ title: Forwarding Refs permalink: docs/forwarding-refs.html --- -Ref forwarding is a technique for automatically passing a [ref](/docs/refs-and-the-dom.html) through a component to one of its children. This is typically not necessary for most components in the application. However, it can be useful for some kinds of components, especially in reusable component libraries. The most common scenarios are described below. +ref 전달은 컴포넌트를 통해 자식 중 하나에 [ref](/docs/refs-and-the-dom.html)를 자동으로 전달하는 기법입니다. 이것은 일반적으로 애플리케이션 대부분의 컴포넌트에 필요하지는 않습니다. 그렇지만, 특히 재사용 가능한 컴포넌트 라이브러리와 같은 어떤 컴포넌트에서는 유용할 수 있습니다. 가장 보편적인 시나리오를 아래에 설명하겠습니다. -## Forwarding refs to DOM components {#forwarding-refs-to-dom-components} +## DOM 에 refs 전달하기 {#forwarding-refs-to-dom-components} -Consider a `FancyButton` component that renders the native `button` DOM element: +기본 `button` DOM 요소를 렌더링하는 `FancyButton` 컴포넌트를 가정해 봅시다. `embed:forwarding-refs/fancy-button-simple.js` -React components hide their implementation details, including their rendered output. Other components using `FancyButton` **usually will not need to** [obtain a ref](/docs/refs-and-the-dom.html) to the inner `button` DOM element. This is good because it prevents components from relying on each other's DOM structure too much. +`FancyButton`를 사용하는 다른 컴포넌트들은 **일반적으로** 내부 `button` DOM 요소에 대한 [ref를 얻을](/docs/refs-and-the-dom.html) 필요가 없습니다. 이는 컴포넌트들이 서로의 DOM 구조에 지나치게 의존하지 않기 때문에 괜찮습니다. -Although such encapsulation is desirable for application-level components like `FeedStory` or `Comment`, it can be inconvenient for highly reusable "leaf" components like `FancyButton` or `MyTextInput`. These components tend to be used throughout the application in a similar manner as a regular DOM `button` and `input`, and accessing their DOM nodes may be unavoidable for managing focus, selection, or animations. +이런 캡슐화는 `FeedStory`나 `Comment` 같은 애플리케이션 레벨의 컴포넌트에서는 바람직하지만, `FancyButton`이나 `MyTextInput`과 같은 재사용성이 높은 "말단" 요소에서는 불편할 수도 있습니다. 이런 컴포넌트들은 일반적인 DOM `button`, `input`과 유사한 방볍으로 애플리케이션 전체에 걸쳐 사용되는 경향이 있습니다. 그리고 포커스, 선택, 애니메이션을 관리하기 위해서는 이런 DOM 노드에 접근하는 것이 불가피할 수 있습니다. -**Ref forwarding is an opt-in feature that lets some components take a `ref` they receive, and pass it further down (in other words, "forward" it) to a child.** +**Ref 전달하기는 일부 컴포넌트가 수신한 `ref`를 받아 조금 더 아래로 전달(즉, "전송")할 수 있는 옵트인 기능입니다.** -In the example below, `FancyButton` uses `React.forwardRef` to obtain the `ref` passed to it, and then forward it to the DOM `button` that it renders: +아래의 예에서 `FancyButton`은 `React.forwardRef`를 사용하여 전달된 `ref`를 얻고, 그것을 렌더링 되는 DOM `button`으로 전달합니다. `embed:forwarding-refs/fancy-button-simple-ref.js` -This way, components using `FancyButton` can get a ref to the underlying `button` DOM node and access it if necessary—just like if they used a DOM `button` directly. +이런 방법으로 `FancyButton`을 사용하는 컴포넌트들은 `button` DOM 노드에 대한 참조를 가져올 수 있고, 필요한 경우 DOM `button`을 직접 사용하는 것처럼 접근할 수 있습니다. -Here is a step-by-step explanation of what happens in the above example: +위의 예제에서 어떤 일이 일어나는지 단계별로 설명하겠습니다. -1. We create a [React ref](/docs/refs-and-the-dom.html) by calling `React.createRef` and assign it to a `ref` variable. -1. We pass our `ref` down to `` by specifying it as a JSX attribute. -1. React passes the `ref` to the `(props, ref) => ...` function inside `forwardRef` as a second argument. -1. We forward this `ref` argument down to ` )); -// You can now get a ref directly to the DOM button: +// 이제 DOM 버튼으로 ref를 작접 받을 수 있습니다. const ref = React.createRef(); Click me!; diff --git a/examples/forwarding-refs/fancy-button.js b/examples/forwarding-refs/fancy-button.js index 9dcd13e16..8dd94cdc3 100644 --- a/examples/forwarding-refs/fancy-button.js +++ b/examples/forwarding-refs/fancy-button.js @@ -6,7 +6,7 @@ class FancyButton extends React.Component { // ... } -// Rather than exporting FancyButton, we export LogProps. -// It will render a FancyButton though. +// FancyButton을 내보내는 대신 LogProps를 내보냅니다. +// 그래도 FancyButton을 렌더링합니다. // highlight-next-line export default logProps(FancyButton); diff --git a/examples/forwarding-refs/log-props-after.js b/examples/forwarding-refs/log-props-after.js index a603bd697..614741bd7 100644 --- a/examples/forwarding-refs/log-props-after.js +++ b/examples/forwarding-refs/log-props-after.js @@ -9,15 +9,15 @@ function logProps(Component) { // highlight-next-line const {forwardedRef, ...rest} = this.props; - // Assign the custom prop "forwardedRef" as a ref + // 사용자 정의 prop "forwardedRef"를 ref로 할당합니다. // highlight-next-line return ; } } - // Note the second param "ref" provided by React.forwardRef. - // We can pass it along to LogProps as a regular prop, e.g. "forwardedRef" - // And it can then be attached to the Component. + // React.forwardRef에서 제공하는 두 번째 파라미터 "ref"에 주의하십시오. + // 가령 "forwardedRef"같은 일반 prop으로 LogProps에 전달할 수 있습니다. + // 그 다음 Component에 연결할 수 있습니다. // highlight-range{1-3} return React.forwardRef((props, ref) => { return ; From 14c52159b2a3e73665677d802d14cb7ae94195e0 Mon Sep 17 00:00:00 2001 From: "youngsun.min" Date: Sat, 30 Jan 2021 19:39:54 +0900 Subject: [PATCH 2/6] Translate Advanced Guides > Forwarding Refs : feedback --- content/docs/forwarding-refs.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/docs/forwarding-refs.md b/content/docs/forwarding-refs.md index e9690fefd..a8dcc1254 100644 --- a/content/docs/forwarding-refs.md +++ b/content/docs/forwarding-refs.md @@ -4,7 +4,7 @@ title: Forwarding Refs permalink: docs/forwarding-refs.html --- -ref 전달은 컴포넌트를 통해 자식 중 하나에 [ref](/docs/refs-and-the-dom.html)를 자동으로 전달하는 기법입니다. 이것은 일반적으로 애플리케이션 대부분의 컴포넌트에 필요하지는 않습니다. 그렇지만, 특히 재사용 가능한 컴포넌트 라이브러리와 같은 어떤 컴포넌트에서는 유용할 수 있습니다. 가장 보편적인 시나리오를 아래에 설명하겠습니다. +ref 전달은 컴포넌트를 통해 자식 중 하나에 [ref](/docs/refs-and-the-dom.html)를 자동으로 전달하는 기법입니다. 일반적으로 애플리케이션 대부분의 컴포넌트에 필요하지는 않습니다. 그렇지만, 특히 재사용 가능한 컴포넌트 라이브러리와 같은 어떤 컴포넌트에서는 유용할 수 있습니다. 가장 보편적인 시나리오를 아래에 설명하겠습니다. ## DOM 에 refs 전달하기 {#forwarding-refs-to-dom-components} @@ -71,6 +71,6 @@ ref 전달은 컴포넌트를 통해 자식 중 하나에 [ref](/docs/refs-and-t `embed:forwarding-refs/wrapped-component-with-function-name.js` -래핑하는 컴포넌트를 포함하도록 함수의 `displayName` 속성을 설정할 수도 있습니다. +감싸고 있는 컴포넌트를 포함하도록 함수의 `displayName` 속성을 설정할 수도 있습니다. `embed:forwarding-refs/customized-display-name.js` From dbcc18d1aadeba6e0444f21865a58993d300de4f Mon Sep 17 00:00:00 2001 From: "youngsun.min" Date: Mon, 15 Feb 2021 08:50:40 +0900 Subject: [PATCH 3/6] Pull from reactjs/ko.reactjs.org --- .github/PULL_REQUEST_TEMPLATE.md | 2 - content/authors.yml | 11 +- ...11-introducing-reacts-error-code-system.md | 2 +- .../2017-09-08-dom-attributes-in-react-16.md | 8 +- content/blog/2020-08-10-react-v17-rc.md | 376 + ...09-22-introducing-the-new-jsx-transform.md | 267 + content/blog/2020-10-20-react-v17.md | 169 + ...a-fetching-with-react-server-components.md | 24 + content/community/conferences.md | 590 +- content/community/courses.md | 8 +- content/community/examples.md | 4 +- content/community/meetups.md | 15 +- content/community/podcasts.md | 4 +- content/community/team.md | 2 + content/community/videos.md | 10 + content/docs/add-react-to-a-website.md | 14 +- content/docs/addons-animation.md | 2 +- content/docs/addons-perf.md | 4 +- content/docs/cdn-links.md | 10 +- content/docs/code-splitting.md | 24 +- content/docs/concurrent-mode-adoption.md | 2 +- content/docs/concurrent-mode-patterns.md | 410 +- content/docs/concurrent-mode-reference.md | 97 +- content/docs/concurrent-mode-suspense.md | 8 +- content/docs/conditional-rendering.md | 15 +- content/docs/context.md | 2 +- content/docs/design-principles.md | 2 +- content/docs/error-boundaries.md | 2 +- content/docs/faq-ajax.md | 6 +- content/docs/faq-functions.md | 4 - content/docs/faq-styling.md | 30 +- content/docs/faq-versioning.md | 2 +- content/docs/forms.md | 4 +- content/docs/forwarding-refs.md | 2 +- content/docs/getting-started.md | 2 +- content/docs/handling-events.md | 2 +- content/docs/higher-order-components.md | 14 +- content/docs/hooks-custom.md | 68 +- content/docs/hooks-faq.md | 550 +- content/docs/hooks-intro.md | 52 +- content/docs/how-to-contribute.md | 8 +- content/docs/introducing-jsx.md | 2 +- content/docs/legacy-event-pooling.md | 37 + content/docs/optimizing-performance.md | 5 +- content/docs/reconciliation.md | 21 +- content/docs/reference-dom-elements.md | 9 +- content/docs/reference-events.md | 108 +- ...nce-javascript-environment-requirements.md | 2 +- content/docs/reference-profiler.md | 86 +- content/docs/reference-react-component.md | 20 +- content/docs/reference-react-dom-server.md | 2 +- content/docs/reference-react.md | 8 +- content/docs/refs-and-the-dom.md | 2 +- content/docs/release-channels.md | 88 +- content/docs/strict-mode.md | 4 + content/docs/testing-environments.md | 2 +- content/docs/testing-recipes.md | 7 +- content/docs/typechecking-with-proptypes.md | 50 +- content/docs/uncontrolled-components.md | 2 +- .../blog/react-v17-rc/react_17_delegation.png | Bin 0 -> 1761751 bytes content/tutorial/tutorial.md | 6 +- content/versions.yml | 6 + flow-typed/gatsby-plugin-google-analytics.js | 9 + gatsby-config.js | 13 +- package.json | 16 +- .../gatsby-node.js | 2 +- src/components/Banner/Banner.js | 189 + src/components/Banner/index.js | 9 + src/components/FeedbackForm/FeedbackForm.js | 72 + src/components/FeedbackForm/index.js | 9 + src/components/LayoutHeader/Header.js | 45 +- .../MarkdownHeader/MarkdownHeader.js | 45 +- src/components/MarkdownPage/MarkdownPage.js | 25 +- .../StickyResponsiveSidebar.js | 10 +- .../TitleAndMetaTags/TitleAndMetaTags.js | 10 +- src/html.js | 88 + src/images/i_close.svg | 1 + src/pages/index.js | 6 +- src/pages/versions.js | 20 +- src/site-constants.js | 2 +- src/theme.js | 36 +- static/_redirects | 48 +- static/html/single-file-example.html | 6 +- vercel.json | 44 + yarn.lock | 8367 ++++++++++------- 85 files changed, 7917 insertions(+), 4450 deletions(-) create mode 100644 content/blog/2020-08-10-react-v17-rc.md create mode 100644 content/blog/2020-09-22-introducing-the-new-jsx-transform.md create mode 100644 content/blog/2020-10-20-react-v17.md create mode 100644 content/blog/2020-12-21-data-fetching-with-react-server-components.md create mode 100644 content/docs/legacy-event-pooling.md create mode 100644 content/images/blog/react-v17-rc/react_17_delegation.png create mode 100644 flow-typed/gatsby-plugin-google-analytics.js create mode 100644 src/components/Banner/Banner.js create mode 100644 src/components/Banner/index.js create mode 100644 src/components/FeedbackForm/FeedbackForm.js create mode 100644 src/components/FeedbackForm/index.js create mode 100644 src/images/i_close.svg create mode 100644 vercel.json diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 9e5a7c928..e1f36cb59 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,5 +1,3 @@ - - - - + + @@ -67,7 +67,7 @@ React는 처음부터 점진적으로 도입할 수 있게 설계되었습니다 ### 3단계: React 컴포넌트 만들기 {#step-3-create-a-react-component} - `like_button.js` 라는 이름으로 HTML 페이지 옆에 새 파일을 만듭니다. + `like_button.js` 라는 이름으로 HTML 페이지 옆에 새 파일을 만듭니다. 이 **[스타터 코드](https://gist.github.com/gaearon/0b180827c190fe4fd98b4c7f570ea4a8/raw/b9157ce933c79a4559d2aa9ff3372668cce48de7/LikeButton.js)** 를 열고 코드를 방금 만든 파일에 복사해줍니다. @@ -115,8 +115,8 @@ ReactDOM.render(e(LikeButton), domContainer); 애플리케이션 스크립트를 이미 압축했을 경우 배포된 HTML 파일이 `production.min.js`로 끝나는 React 파일을 확실히 실행하기만 하면 **사이트는 프로덕션 준비가 완료된 겁니다.** ```js - - + + ``` 스크립트를 압축하는 절차가 따로 없다면 [이 사이트를 참고해서 설정해보세요.](https://gist.github.com/gaearon/42a2ffa41b8319948f9be4076286e1f3) @@ -184,7 +184,7 @@ JSX를 프로젝트에 추가하는 데에는 복잡한 번들러나 개발 서 `src` 폴더를 만들고 다음 터미널 명령어를 실행하세요. ``` -npx babel --watch src --out-dir . --presets react-app/prod +npx babel --watch src --out-dir . --presets react-app/prod ``` >주의 diff --git a/content/docs/addons-animation.md b/content/docs/addons-animation.md index f83dd63f3..fd724dbef 100644 --- a/content/docs/addons-animation.md +++ b/content/docs/addons-animation.md @@ -50,7 +50,7 @@ class TodoList extends React.Component { render() { const items = this.state.items.map((item, i) => ( -
this.handleRemove(i)}> +
this.handleRemove(i)}> {item}
)); diff --git a/content/docs/addons-perf.md b/content/docs/addons-perf.md index a07b1d05a..221ce2e86 100644 --- a/content/docs/addons-perf.md +++ b/content/docs/addons-perf.md @@ -27,8 +27,8 @@ In addition to giving you an overview of your app's overall performance, `Perf` See these articles for an introduction to React performance tooling: - ["How to Benchmark React Components"](https://medium.com/code-life/how-to-benchmark-react-components-the-quick-and-dirty-guide-f595baf1014c) - - ["Performance Engineering with React"](https://benchling.engineering/performance-engineering-with-react/) - - ["A Deep Dive into React Perf Debugging"](https://benchling.engineering/deep-dive-react-perf-debugging/) + - ["Performance Engineering with React"](https://benchling.engineering/performance-engineering-with-react-e03013e53285) + - ["A Deep Dive into React Perf Debugging"](https://benchling.engineering/a-deep-dive-into-react-perf-debugging-fd2063f5a667) ### Development vs. Production Builds {#development-vs-production-builds} diff --git a/content/docs/cdn-links.md b/content/docs/cdn-links.md index f17572892..69687842c 100644 --- a/content/docs/cdn-links.md +++ b/content/docs/cdn-links.md @@ -9,18 +9,18 @@ next: release-channels.html React와 ReactDOM 모두 CDN을 통해 사용할 수 있습니다. ```html - - + + ``` 위의 코드는 개발용으로 적합하며 배포용 버전에는 적합하지 않습니다. React의 용량 및 성능 최적화된 배포용 버전은 아래와 같이 제공되고 있습니다. ```html - - + + ``` -`react`와 `react-dom`의 특정 버전을 로딩하려면 `16`을 사용하고자 하는 버전 넘버로 대체하면 됩니다. +`react`와 `react-dom`의 특정 버전을 로딩하려면 `17`을 사용하고자 하는 버전 넘버로 대체하면 됩니다. ### `crossorigin` 속성이 필요한 이유 {#why-the-crossorigin-attribute} diff --git a/content/docs/code-splitting.md b/content/docs/code-splitting.md index 18f6b0f98..9209afca3 100644 --- a/content/docs/code-splitting.md +++ b/content/docs/code-splitting.md @@ -42,24 +42,19 @@ console.log(add(16, 26)); // 42 [Create React App](https://create-react-app.dev/)이나 [Next.js](https://nextjs.org/), [Gatsby](https://www.gatsbyjs.org/) 혹은 비슷한 툴을 사용한다면 여러분이 설치한 앱에서 Webpack을 같이 설치했을 겁니다. -이런 툴을 사용하지 않는다면 여러분이 스스로 번들링을 설정해야 합니다. 이 경우 Webpack의 -[설치하기](https://webpack.js.org/guides/installation/) 문서와 -[시작하기](https://webpack.js.org/guides/getting-started/) 문서를 참조해 주세요. +이런 툴을 사용하지 않는다면 여러분이 스스로 번들링을 설정해야 합니다. 이 경우 Webpack의 [설치하기](https://webpack.js.org/guides/installation/) 문서와 [시작하기](https://webpack.js.org/guides/getting-started/) 문서를 참조해 주세요. ## 코드 분할 {#code-splitting} 번들링은 훌륭하지만 여러분의 앱이 커지면 번들도 커집니다. 특히 큰 규모의 서드 파티 라이브러리를 추가할 때 실수로 앱이 커져서 로드 시간이 길어지는 것을 방지하기 위해 코드를 주의 깊게 살펴야 합니다. -번들이 거대해지는 것을 방지하기 위한 좋은 해결방법은 번들을 "나누는" 것입니다. -코드 분할은 런타임에 여러 번들을 동적으로 만들고 불러오는 것으로 [Webpack](https://webpack.js.org/guides/code-splitting/), [Rollup](https://rollupjs.org/guide/en/#code-splitting)과 Browserify ([factor-bundle](https://github.com/browserify/factor-bundle)) 같은 번들러가 지원하는 기능입니다. +번들이 거대해지는 것을 방지하기 위한 좋은 해결방법은 번들을 "나누는" 것입니다. 코드 분할은 런타임에 여러 번들을 동적으로 만들고 불러오는 것으로 [Webpack](https://webpack.js.org/guides/code-splitting/), [Rollup](https://rollupjs.org/guide/en/#code-splitting)과 Browserify ([factor-bundle](https://github.com/browserify/factor-bundle)) 같은 번들러가 지원하는 기능입니다. - -코드 분할은 여러분의 앱을 "지연 로딩" 하게 도와주고 앱 사용자에게 획기적인 성능 향상을 하게 합니다. -앱의 코드 양을 줄이지 않고도 사용자가 필요하지 않은 코드를 불러오지 않게 하며 앱의 초기화 로딩에 필요한 비용을 줄여줍니다. +코드 분할은 여러분의 앱을 "지연 로딩" 하게 도와주고 앱 사용자에게 획기적인 성능 향상을 하게 합니다. 앱의 코드 양을 줄이지 않고도 사용자가 필요하지 않은 코드를 불러오지 않게 하며 앱의 초기화 로딩에 필요한 비용을 줄여줍니다. ## `import()` {#import} - 앱에 코드 분할을 도입하는 가장 좋은 방법은 동적 `import()` 문법을 사용하는 방법입니다. + 앱에 코드 분할을 도입하는 가장 좋은 방법은 동적 `import()` 문법을 사용하는 방법입니다. **Before** @@ -77,9 +72,8 @@ import("./math").then(math => { }); ``` -Webpack이 이 구문을 만나게 되면 앱의 코드를 분할합니다. -Create React App을 사용하고 있다면 이미 Webpack이 구성이 되어 있기 때문에 즉시 [사용](https://facebook.github.io/create-react-app/docs/code-splitting)할 수 있습니다. -[Next.js](https://nextjs.org/docs/advanced-features/dynamic-import) 역시 지원합니다. +Webpack이 이 구문을 만나게 되면 앱의 코드를 분할합니다. Create React App을 사용하고 있다면 이미 Webpack이 구성이 되어 있기 때문에 즉시 [사용](https://create-react-app.dev/docs/code-splitting/)할 수 있습니다. [Next.js](https://nextjs.org/docs/advanced-features/dynamic-import) 역시 지원합니다. + [코드 분할 가이드](https://webpack.js.org/guides/code-splitting/)를 참조하세요. Webpack 설정은 [가이드](https://gist.github.com/gaearon/ca6e803f5c604d37468b0091d9959269)에 있습니다. [Babel](http://babeljs.io/)을 사용할 때는 Babel이 동적 import를 인식할 수 있지만 변환하지는 않도록 합니다. 이를 위해 [babel-plugin-syntax-dynamic-import](https://yarnpkg.com/en/package/babel-plugin-syntax-dynamic-import)를 사용하세요. @@ -175,11 +169,9 @@ const MyComponent = () => ( ## Route-based code splitting {#route-based-code-splitting} -앱에 코드 분할을 어느 곳에 도입할지 결정하는 것은 조금 까다롭습니다. -여러분은 사용자의 경험을 헤치지 않으면서 번들을 균등하게 분배할 곳을 찾고자 합니다. +앱에 코드 분할을 어느 곳에 도입할지 결정하는 것은 조금 까다롭습니다. 여러분은 사용자의 경험을 헤치지 않으면서 번들을 균등하게 분배할 곳을 찾고자 합니다. -이를 시작하기 좋은 장소는 라우트입니다. 웹 페이지를 불러오는 시간은 페이지 전환에 어느 정도 발생하며 대부분 페이지를 한번에 렌더링하기 때문에 -사용자가 페이지를 렌더링하는 동안 다른 요소와 상호작용하지 않습니다. +이를 시작하기 좋은 장소는 라우트입니다. 웹 페이지를 불러오는 시간은 페이지 전환에 어느 정도 발생하며 대부분 페이지를 한번에 렌더링하기 때문에 사용자가 페이지를 렌더링하는 동안 다른 요소와 상호작용하지 않습니다. `React.lazy`를 [React Router](https://reacttraining.com/react-router/) 라이브러리를 사용해서 애플리케이션에 라우트 기반 코드 분할을 설정하는 예시입니다. diff --git a/content/docs/concurrent-mode-adoption.md b/content/docs/concurrent-mode-adoption.md index 6455969d7..a08603e0c 100644 --- a/content/docs/concurrent-mode-adoption.md +++ b/content/docs/concurrent-mode-adoption.md @@ -71,7 +71,7 @@ import ReactDOM from 'react-dom'; // // 다음과 같이 작성하여 Concurrent 모드를 선택할 수 있습니다. -ReactDOM.createRoot( +ReactDOM.unstable_createRoot( document.getElementById('root') ).render(); ``` diff --git a/content/docs/concurrent-mode-patterns.md b/content/docs/concurrent-mode-patterns.md index f591c97b9..b510eb4c2 100644 --- a/content/docs/concurrent-mode-patterns.md +++ b/content/docs/concurrent-mode-patterns.md @@ -1,6 +1,6 @@ --- id: concurrent-mode-patterns -title: Concurrent UI Patterns (Experimental) +title: 컨커런트 UI 패턴 (실험) permalink: docs/concurrent-mode-patterns.html prev: concurrent-mode-suspense.html next: concurrent-mode-adoption.html @@ -15,63 +15,63 @@ next: concurrent-mode-adoption.html
->Caution: +>경고 > ->This page describes **experimental features that are [not yet available](/docs/concurrent-mode-adoption.html) in a stable release**. Don't rely on experimental builds of React in production apps. These features may change significantly and without a warning before they become a part of React. +> 이 페이지의 내용은 **안정된 배포판에서 [사용할 수 없는](/docs/concurrent-mode-adoption.html) 실험적인 기능**입니다. 프로덕션 애플리케이션에 실험적인 React 빌드를 의존하지 마십시오. 이 기능은 React에 편입되기 전에 경고 없이 크게 변경될 수 있습니다. > ->This documentation is aimed at early adopters and people who are curious. **If you're new to React, don't worry about these features** -- you don't need to learn them right now. For example, if you're looking for a data fetching tutorial that works today, read [this article](https://www.robinwieruch.de/react-hooks-fetch-data/) instead. +> 이 문서는 얼리어답터와 호기심 넘치는 사람들을 위해 작성되었습니다. **React 초기 입문자라면 이 기능에 신경 쓰지 않아도 괜찮습니다.** -- 이 내용을 지금 당장 배울 필요는 없습니다. 데이터 패칭을 위한 튜토리얼을 찾는다면 [이 문서](https://www.robinwieruch.de/react-hooks-fetch-data/)를 보세요.
-Usually, when we update the state, we expect to see changes on the screen immediately. This makes sense because we want to keep our app responsive to user input. However, there are cases where we might prefer to **defer an update from appearing on the screen**. - -For example, if we switch from one page to another, and none of the code or data for the next screen has loaded yet, it might be frustrating to immediately see a blank page with a loading indicator. We might prefer to stay longer on the previous screen. Implementing this pattern has historically been difficult in React. Concurrent Mode offers a new set of tools to do that. - -- [Transitions](#transitions) - - [Wrapping setState in a Transition](#wrapping-setstate-in-a-transition) - - [Adding a Pending Indicator](#adding-a-pending-indicator) - - [Reviewing the Changes](#reviewing-the-changes) - - [Where Does the Update Happen?](#where-does-the-update-happen) - - [Transitions Are Everywhere](#transitions-are-everywhere) - - [Baking Transitions Into the Design System](#baking-transitions-into-the-design-system) -- [The Three Steps](#the-three-steps) - - [Default: Receded → Skeleton → Complete](#default-receded-skeleton-complete) - - [Preferred: Pending → Skeleton → Complete](#preferred-pending-skeleton-complete) - - [Wrap Lazy Features in ``](#wrap-lazy-features-in-suspense) - - [Suspense Reveal “Train”](#suspense-reveal-train) - - [Delaying a Pending Indicator](#delaying-a-pending-indicator) - - [Recap](#recap) -- [Other Patterns](#other-patterns) - - [Splitting High and Low Priority State](#splitting-high-and-low-priority-state) - - [Deferring a Value](#deferring-a-value) +일반적으로 상태가 갱신될 때 화면의 즉각적인 변화를 기대합니다. 애플리케이션이 사용자 입력에 반응하는 것을 유지하고 싶기 때문입니다. 하지만 **화면에 나타나는 변화를 지연하고** 싶은 경우도 있습니다. + +예를 들어 한 페이지에서 다른 페이지로 전환할 때 다음 화면에 필요한 코드나 데이터가 전혀 준비되어 있지 않으면 순간적으로 빈 화면에 로딩 중인 모습이 보이고 답답할 수 있습니다. 이전 화면을 좀 더 길게 보여주고 싶을 때도 있습니다. React에서 이런 패턴을 구현하기란 오랫동안 어려웠습니다. 컨커런트 모드는 이 문제를 해결하기 위한 새로운 도구를 제공합니다. + +- [트랜지션](#transitions) + - [setState를 트랜지션에 래핑하기](#wrapping-setstate-in-a-transition) + - [지연 인디케이터 추가하기](#adding-a-pending-indicator) + - [변화 살펴보기](#reviewing-the-changes) + - [어디에서 갱신이 발생하나요?](#where-does-the-update-happen) + - [트랜지션은 모든 곳에 있습니다](#transitions-are-everywhere) + - [디자인 시스템에 트랜지션 구축하기](#baking-transitions-into-the-design-system) +- [세 단계](#the-three-steps) + - [기본: 후퇴 → 스켈레톤 → 완료](#default-receded-skeleton-complete) + - [권장: 보류 → 스켈레톤 → 완료](#preferred-pending-skeleton-complete) + - [지연평가 요소를 ``로 래핑하기](#wrap-lazy-features-in-suspense) + - [서스펜스 공개 '기차'](#suspense-reveal-train) + - [보류 인디케이터 지연하기](#delaying-a-pending-indicator) + - [요약](#recap) +- [기타 패턴](#other-patterns) + - [낮은 우선순위 상태와 높은 우선순위 상태 분할하기](#splitting-high-and-low-priority-state) + - [값 지연하기](#deferring-a-value) - [SuspenseList](#suspenselist) -- [Next Steps](#next-steps) +- [다음 단계](#next-steps) -## Transitions {#transitions} +## 트랜지션 {#transitions} -Let's revisit [this demo](https://codesandbox.io/s/infallible-feather-xjtbu) from the previous page about [Suspense for Data Fetching](/docs/concurrent-mode-suspense.html). +이전 [데이터를 가져오기 위한 서스펜스](/docs/concurrent-mode-suspense.html) 페이지의 [데모를](https://codesandbox.io/s/infallible-feather-xjtbu) 다시 살펴봅시다. -When we click the "Next" button to switch the active profile, the existing page data immediately disappears, and we see the loading indicator for the whole page again. We can call this an "undesirable" loading state. **It would be nice if we could "skip" it and wait for some content to load before transitioning to the new screen.** +프로필을 활성화하기 위해 "Next" 버튼을 누르면 페이지의 데이터가 바로 사라지고 전체 화면에 로딩 화면을 다시 보게 됩니다. '의도치 않은' 로딩 상태라고 할 수 있습니다. **새 화면을 위한 콘텐츠를 불러오는 동안 화면 전환을 생략할 수 있다면 좋을 것입니다.** -React offers a new built-in `useTransition()` Hook to help with this. +React는 이 문제를 해결하기 위해 새로운 `useTransition()` 내장 훅을 제공합니다. -We can use it in three steps. +세 단계에 걸쳐 사용할 수 있습니다. -First, we'll make sure that we're actually using Concurrent Mode. We'll talk more about [adopting Concurrent Mode](/docs/concurrent-mode-adoption.html) later, but for now it's sufficient to know that we need to use `ReactDOM.createRoot()` rather than `ReactDOM.render()` for this feature to work: +먼저 컨커런트 모드를 사용해야 합니다. [컨커런트 모드 채택](/docs/concurrent-mode-adoption.html)에 대해서는 이후 더 많은 이야기를 나눌 것입니다. 지금은 이 기능이 작동하려면 `ReactDOM.render()` 대신 `ReactDOM.createRoot()`를 사용해야 함을 아는 것으로 충분합니다. ```js const rootElement = document.getElementById("root"); -// Opt into Concurrent Mode +// 컨커런트 모드로 설정 ReactDOM.createRoot(rootElement).render(); ``` -Next, we'll add an import for the `useTransition` Hook from React: +그 다음 React에서 `useTransition` 훅을 가져와서 사용합니다. ```js import React, { useState, useTransition, Suspense } from "react"; ``` -Finally, we'll use it inside the `App` component: +마지막으로 `App` 컴포넌트에서 사용합니다. ```js{3-5} function App() { @@ -82,18 +82,18 @@ function App() { // ... ``` -**By itself, this code doesn't do anything yet.** We will need to use this Hook's return values to set up our state transition. There are two values returned from `useTransition`: +**이 코드만으로는 아무것도 실행하지 않습니다.** 상태를 갱신하기 위해 훅의 반환 값을 사용해야 합니다. `useTransition`의 반환 값은 두가지입니다. -* `startTransition` is a function. We'll use it to tell React *which* state update we want to defer. -* `isPending` is a boolean. It's React telling us whether that transition is ongoing at the moment. +* `startTransition`는 함수입니다. React에 **어떤** 상태변화를 지연하고 싶은지 지정할 수 있습니다. +* `isPending`는 불리언 값입니다. 트랜지션 진행 여부를 알 수 있습니다. -We will use them right below. +바로 아래에서 사용하겠습니다. -Note we passed a configuration object to `useTransition`. Its `timeoutMs` property specifies **how long we're willing to wait for the transition to finish**. By passing `{timeoutMs: 3000}`, we say "If the next profile takes more than 3 seconds to load, show the big spinner -- but before that timeout it's okay to keep showing the previous screen". +`useTransition` 훅에 설정 객체를 전달했다는 것을 명심하세요. `timeoutMs` 프로퍼티는 **트랜지션이 완료될 때까지 얼마나 오랫동안 기다릴 것인지** 결정합니다. `{timeoutMs: 3000}` 를 전달한다면 "다음 프로필을 불러오는 데 3초보다 오래 걸린다면 로딩 상태를 보여주고 그전까진 계속 이전 화면을 보여줘도 괜찮아"라는 의미입니다. -### Wrapping setState in a Transition {#wrapping-setstate-in-a-transition} +### setState를 트랜지션에 래핑하기 {#wrapping-setstate-in-a-transition} -Our "Next" button click handler sets the state that switches the current profile in the state: +"Next" 버튼 클릭 이벤트 핸들러는 현재 프로필 상태를 설정합니다. ```js{4} - {isPending ? " Loading..." : null} + {isPending ? "Loading..." : null} ); ``` -**[Try it on CodeSandbox](https://codesandbox.io/s/jovial-lalande-26yep)** +**[CodeSandbox에서 시도해보세요](https://codesandbox.io/s/jovial-lalande-26yep)** -Now, this feels a lot better! When we click Next, it gets disabled because clicking it multiple times doesn't make sense. And the new "Loading..." tells the user that the app didn't freeze. +이제 훨씬 나아 보이네요! 버튼을 여러 번 누르는 것은 이상하기 때문에 버튼을 클릭하면 비활성화됩니다. 그리고 사용자에게 앱이 멈추지 않았다는 것을 알려주기 위해 "Loading..."이라고 알려줍니다. -### Reviewing the Changes {#reviewing-the-changes} +### 변화 살펴보기 {#reviewing-the-changes} -Let's take another look at all the changes we've made since the [original example](https://codesandbox.io/s/infallible-feather-xjtbu): +[원본 예제](https://codesandbox.io/s/infallible-feather-xjtbu) 이후로 변경된 모든 사항을 살펴보겠습니다. ```js{3-5,9,11,14,19} function App() { @@ -182,47 +182,47 @@ function App() { > Next - {isPending ? " Loading..." : null} + {isPending ? "Loading..." : null} ); } ``` -**[Try it on CodeSandbox](https://codesandbox.io/s/jovial-lalande-26yep)** +**[CodeSandbox에서 시도해보세요](https://codesandbox.io/s/jovial-lalande-26yep)** -It took us only seven lines of code to add this transition: +7줄의 코드만으로 트랜지션을 추가했습니다. -* We've imported the `useTransition` Hook and used it the component that updates the state. -* We've passed `{timeoutMs: 3000}` to stay on the previous screen for at most 3 seconds. -* We've wrapped our state update into `startTransition` to tell React it's okay to delay it. -* We're using `isPending` to communicate the state transition progress to the user and to disable the button. +* `useTransition` 훅을 가져와 상태를 업데이트하는 컴포넌트에서 사용했습니다. +* `{timeoutMs: 3000}` 옵션을 전달하여 최대 3초간 이전 화면을 유지하도록 설정했습니다. +* React가 상태 갱신을 지연할 수 있도록 상태 갱신 코드를 `startTransition` 함수로 래핑했습니다. +* `isPending`을 이용하여 사용자에게 작업 상황을 알리고 버튼을 비활성화합니다. -As a result, clicking "Next" doesn't perform an immediate state transition to an "undesirable" loading state, but instead stays on the previous screen and communicates progress there. +결과적으로 "Next" 버튼을 눌러도 의도하지 않은 로딩 상태로 바로 전환되지 않고 이전 화면에서 진행 상태를 알려줍니다. -### Where Does the Update Happen? {#where-does-the-update-happen} +### 어디에서 갱신이 발생하나요? {#where-does-the-update-happen} -This wasn't very difficult to implement. However, if you start thinking about how this could possibly work, it might become a little mindbending. If we set the state, how come we don't see the result right away? *Where* is the next `` rendering? +위 예제를 구현하는 것은 엄청 어렵진 않았습니다. 하지만 어떻게 이게 작동하는지에 대해서 생각하기 시작하면 약간 어지러울 수 있습니다. 상태를 설정했는데 어떻게 그 결과를 바로 볼 수 없는 걸까요? **어디에서** 다음 `` 렌더링이 어디에서 일어날까요? -Clearly, both "versions" of `` exist at the same time. We know the old one exists because we see it on the screen and even display a progress indicator on it. And we know the new version also exists *somewhere*, because it's the one that we're waiting for! +두 '버전'의 ``가 동시에 존재하는 것은 명확합니다. 이전 스크린 화면에서 로딩 상태까지 보여주고 있기 때문에 이전 버전이 존재한다는 것을 알 수 있습니다. 그리고 새 버전 또한 **어디엔가** 존재한다는 것을 압니다. 왜냐하면 그것을 기다리고 있기 때문이죠! -**But how can two versions of the same component exist at the same time?** +**하지만 어떻게 두 가지 버전의 같은 컴포넌트가 동시에 존재할 수 있는 걸까요?** -This gets at the root of what Concurrent Mode is. We've [previously said](/docs/concurrent-mode-intro.html#intentional-loading-sequences) it's a bit like React working on state update on a "branch". Another way we can conceptualize is that wrapping a state update in `startTransition` begins rendering it *"in a different universe"*, much like in science fiction movies. We don't "see" that universe directly -- but we can get a signal from it that tells us something is happening (`isPending`). When the update is ready, our "universes" merge back together, and we see the result on the screen! +이것이 컨커런트 모드의 존재 이유입니다. React의 작업은 '브랜치'의 상태 갱신과 비슷하다고 [앞서 언급했습니다](/docs/concurrent-mode-intro.html#intentional-loading-sequences). 이 개념을 잡기 위한 또 다른 방법은 `startTransition` 함수로 상태 갱신 코드를 래핑하는 것은 공상과학 영화처럼 **다른 평행 우주**에서 렌더링한다고 생각하는 것입니다. 다른 우주를 직접 "볼" 수는 없습니다. 하지만 무언가 일어나고 있다는 신호(`isPending`)를 들을 수 있습니다. 갱신이 준비되면 '우주들'이 다시 병합되고 그 결과를 화면에서 볼 수 있습니다! -Play a bit more with the [demo](https://codesandbox.io/s/jovial-lalande-26yep), and try to imagine it happening. +[이 데모](https://codesandbox.io/s/jovial-lalande-26yep)를 좀 더 가지고 놀고 무엇이 일어나는지 상상해보세요. -Of course, two versions of the tree rendering *at the same time* is an illusion, just like the idea that all programs run on your computer at the same time is an illusion. An operating system switches between different applications very fast. Similarly, React can switch between the version of the tree you see on the screen and the version that it's "preparing" to show next. +물론 두 버전의 트리 렌더링이 **동시에** 일어나진 않습니다. 컴퓨터의 모든 프로그램이 동시에 실행된다는 것이 허상인 것처럼요. 운영체제는 다른 애플리케이션들을 매우 빠르게 전환합니다. 비슷하게 React도 화면에 보이는 트리 버전과 다음에 노출하기 위해 "준비중"인 버전을 전환할 수 있습니다. -An API like `useTransition` lets you focus on the desired user experience, and not think about the mechanics of how it's implemented. Still, it can be a helpful metaphor to imagine that updates wrapped in `startTransition` happen "on a branch" or "in a different world". +`useTransition` 같은 API를 사용하면 원하는 사용자 경험에 초점을 맞출 수 있고 어떻게 구현했는지 생각 하지 않아도 됩니다. `startTransition`에 래핑된 트랜지션이 "브랜치"나 "다른 세계"에서 일어난다는 비유는 이해에 도움이 될 수 있습니다. -### Transitions Are Everywhere {#transitions-are-everywhere} +### 트랜지션은 모든 곳에 있습니다. {#transitions-are-everywhere} -As we learned from the [Suspense walkthrough](/docs/concurrent-mode-suspense.html), any component can "suspend" any time if some data it needs is not ready yet. We can strategically place `` boundaries in different parts of the tree to handle this, but it won't always be enough. +[Suspense walkthrough](/docs/concurrent-mode-suspense.html)에서 어떤 컴포넌트라도 추가적인 데이터가 필요하지만 준비되지 않았다면 언제든지 '서스펜드' 할 수 있다는 것을 배웠습니다. 중단 상태를 처리하기 위해 ``를 트리의 다른 부분에 전략적으로 배치할 수는 있지만 항상 충분하지는 않습니다. -Let's get back to our [first Suspense demo](https://codesandbox.io/s/frosty-hermann-bztrp) where there was just one profile. Currently, it fetches the data only once. We'll add a "Refresh" button to check for server updates. +하나의 프로필만 있던 [첫 번째 서스펜스 데모](https://codesandbox.io/s/frosty-hermann-bztrp)로 돌아가 봅시다. 이 예제는 오직 데이터를 한 번만 페치합니다. 서버 변경사항을 검사하기 위한 "Refresh" 버튼을 추가하겠습니다. -Our first attempt might look like this: +첫 번째 시도는 다음과 같이 생겼습니다. ```js{6-8,13-15} const initialResource = fetchUserAndPosts(); @@ -248,13 +248,13 @@ function ProfilePage() { } ``` -**[Try it on CodeSandbox](https://codesandbox.io/s/boring-shadow-100tf)** +**[CodeSandbox에서 시도해보세요](https://codesandbox.io/s/boring-shadow-100tf)** -In this example, we start data fetching at the load *and* every time you press "Refresh". We put the result of calling `fetchUserAndPosts()` into state so that components below can start reading the new data from the request we just kicked off. +이 예제에선 페이지가 로드되거나 "Refresh" 버튼을 누를 때 마다 데이터를 가져옵니다. `fetchUserAndPosts()`의 반환값을 상태에 저장하여 하위 컴포넌트들이 요청에서 가져온 데이터를 읽을 수 있게 하겠습니다. -We can see in [this example](https://codesandbox.io/s/boring-shadow-100tf) that pressing "Refresh" works. The `` and `` components receive a new `resource` prop that represents the fresh data, they "suspend" because we don't have a response yet, and we see the fallbacks. When the response loads, we can see the updated posts (our fake API adds them every 3 seconds). +[이 예제](https://codesandbox.io/s/boring-shadow-100tf)를 보면 "Refresh" 버튼을 누르는 것은 동작합니다. `` 와 `` 컴포넌트들은 새로운 최신 데이터를 표현하는 `resource` 프로퍼티를 전달받습니다. `fetchUserAndPosts` 호출 직후에 아무런 응답을 받지 못했기 때문에 컴포넌트는 바로 '서스펜드' 상태가 되고 화면에는 폴백을 보게 됩니다. 응답을 받은 뒤엔 새롭게 갱신된 포스트를 볼 수 있습니다. (우리의 목 API는 3초 마다 새로운 포스트를 추가합니다.) -However, the experience feels really jarring. We were browsing a page, but it got replaced by a loading state right as we were interacting with it. It's disorienting. **Just like before, to avoid showing an undesirable loading state, we can wrap the state update in a transition:** +하지만 위 경험은 자연스럽지 않습니다. 우리는 한 페이지를 브라우징하고 있었는데 버튼을 클릭한 직후에 바로 로딩 상태로 전환되어 사용자를 혼란스럽게 합니다. **이전처럼, 의도치 않은 로딩 상태를 숨기기 위해서 상태 갱신을 트랜지션에 래핑할 수 있습니다:** ```js{2-5,9-11,21} function ProfilePage() { @@ -287,15 +287,15 @@ function ProfilePage() { } ``` -**[Try it on CodeSandbox](https://codesandbox.io/s/sleepy-field-mohzb)** +**[CodeSandbox에서 시도해보세요](https://codesandbox.io/s/sleepy-field-mohzb)** -This feels a lot better! Clicking "Refresh" doesn't pull us away from the page we're browsing anymore. We see something is loading "inline", and when the data is ready, it's displayed. +훨씬 나아 보입니다! "Refresh" 버튼을 클릭해도 우리가 브라우징하고 있는 페이지가 사라지지 않습니다. 우리는 인라인으로 뭔가 로딩되고 있다는 것을 보고 데이터가 준비된 이후에 새로운 데이터가 보입니다. -### Baking Transitions Into the Design System {#baking-transitions-into-the-design-system} +### 디자인시스템에 트랜지션 구축하기 {#baking-transitions-into-the-design-system} -We can now see that the need for `useTransition` is *very* common. Pretty much any button click or interaction that can lead to a component suspending needs to be wrapped in `useTransition` to avoid accidentally hiding something the user is interacting with. +이제 `useTransition`의 필요성이 **매우** 일반적이라는 걸 알 수 있습니다. 사용자가 상호작용하는 대상을 실수로 숨기지 않도록 컴포넌트를 서스펜드 상태로 만들 수 있는 대부분 버튼클릭이나 상호작용은 `useTransition`으로 래핑해야 합니다. -This can lead to a lot of repetitive code across components. This is why **we generally recommend to bake `useTransition` into the *design system* components of your app**. For example, we can extract the transition logic into our own `