Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/components/PageHeading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ function CopyAsMarkdownButton() {
<Button onClick={handleCopy} className="text-sm py-1 px-3">
<IconCopy className="w-3.5 h-3.5 me-1.5" />
{copied ? (
'Copied!'
'복사 완료!'
) : (
<>
<span className="hidden sm:inline">Copy page</span>
<span className="sm:hidden">Copy</span>
<span className="hidden sm:inline">페이지 복사</span>
<span className="sm:hidden">복사</span>
</>
)}
</Button>
Expand Down
2 changes: 1 addition & 1 deletion src/content/learn/choosing-the-state-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ function sendMessage(text) {

이 코드는 작동하긴 하지만, "불가능한" state를 허용합니다. 예를 들어 `setIsSent`와 `setIsSending`을 함께 호출하는 것을 잊어버린 경우, `isSending`과 `isSent`가 동시에 `true`인 상황에 처할 수 있습니다. 컴포넌트가 복잡할수록 무슨 일이 일어났는지 이해하기가 어렵습니다.

**`isSending`과 `isSent`는 동시에 `true`가 되어서는 안되기 때문에, 이 두 변수를** `'typing'`(초깃값), `'sending'`, `'sent'` **세 가지 유효한 상태 중 하나를 가질 수 있는 `status` state 변수로 대체하는 것이 좋습니다.**
**`isSending`과 `isSent`는 동시에 `true`가 되어서는 안 되기 때문에, 이 두 변수를** `'typing'`(초깃값), `'sending'`, `'sent'` **세 가지 유효한 상태 중 하나를 가질 수 있는 `status` state 변수로 대체하는 것이 좋습니다.**

<Sandpack>

Expand Down
8 changes: 4 additions & 4 deletions src/content/learn/creating-a-react-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ React로 새로운 앱이나 웹사이트를 구축하려면 프레임워크부
npx create-next-app@latest
</TerminalBlock>

Next.js는 [Vercel](https://vercel.com/)에서 유지 관리합니다. [Next.js 앱을 빌드](https://nextjs.org/docs/app/building-your-application/deploying)해서 Node.js, 도커 컨테이너, 서버리스 호스팅, 혹은 자체 서버에 배포할 수 있습니다. Next.js는 또한 서버가 필요없는 [정적 내보내기](https://nextjs.org/docs/app/building-your-application/deploying/static-exports)도 지원합니다.
Next.js는 [Vercel](https://vercel.com/)에서 유지 관리합니다. [Next.js 앱을 빌드](https://nextjs.org/docs/app/building-your-application/deploying)해서 Node.js, 도커 컨테이너, 서버리스 호스팅, 혹은 자체 서버에 배포할 수 있습니다. Next.js는 또한 서버가 필요 없는 [정적 내보내기](https://nextjs.org/docs/app/building-your-application/deploying/static-exports)도 지원합니다.

### React Router (v7) {/*react-router-v7*/}

Expand All @@ -48,23 +48,23 @@ React Router는 [Shopify](https://www.shopify.com)에서 유지 관리합니다.

### Expo (네이티브 앱용) {/*expo*/}

**[Expo](https://expo.dev/)는 네이티브 UI를 사용하여 안드로이드, iOS, 웹을 위한 범용앱을 만들 수 있는 React 프레임워크입니다.** 네이티브 부분을 쉽게 사용할 수 있게 해주는 [React Native SDK](https://reactnative.dev/)를 제공합니다. 새로운 Expo 프로젝트를 생성하려면 다음 명령을 사용하세요.
**[Expo](https://expo.dev/)는 네이티브 UI를 사용하여 안드로이드, iOS, 웹을 위한 범용 앱을 만들 수 있는 React 프레임워크입니다.** 네이티브 부분을 쉽게 사용할 수 있게 해주는 [React Native SDK](https://reactnative.dev/)를 제공합니다. 새로운 Expo 프로젝트를 생성하려면 다음 명령을 사용하세요.

<TerminalBlock>
npx create-expo-app@latest
</TerminalBlock>

Expo를 처음 사용하는 경우, [Expo 자습서](https://docs.expo.dev/tutorial/introduction/)를 참조하세요.

Expo는 [Expo (the company)](https://expo.dev/about)에서 유지 관리합니다. Expo로 앱을 빌드하는 것은 무료이고 구글이나 애플 스토어에 제한없이 제출할 수 있습니다. Expo는 추가적으로 옵트인 유료 클라우드 서비스를 제공합니다.
Expo는 [Expo (the company)](https://expo.dev/about)에서 유지 관리합니다. Expo로 앱을 빌드하는 것은 무료이고 구글이나 애플 스토어에 제한 없이 제출할 수 있습니다. Expo는 추가적으로 옵트인 유료 클라우드 서비스를 제공합니다.


## 다른 프레임워크 {/*other-frameworks*/}

풀스택 React 비전을 향해 나아가고 있는 또 다른 떠오르는 프레임워크가 있습니다.

- [TanStack Start (Beta)](https://tanstack.com/): TanStack Start는 TanStack Router를 기반으로 하는 풀스택 React 프레임워크입니다. Nitro나 Vite와 같이 전체 문서 SSR, 스트리밍, 서버 함수, 번들링과 많은 유용한 도구를 제공합니다.
- [RedwoodJS](https://redwoodjs.com/): Redwood는 쉽게 풀스택 웹 애플리케이션을 만들 수 있도록 사전탑재된 패키지와 구성을 가진 풀스택 React 프레임워크입니다.
- [RedwoodJS](https://redwoodjs.com/): Redwood는 쉽게 풀스택 웹 애플리케이션을 만들 수 있도록 사전 탑재된 패키지와 구성을 가진 풀스택 React 프레임워크입니다.

<DeepDive>

Expand Down
2 changes: 1 addition & 1 deletion src/content/learn/describing-the-ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ React 렌더 트리 예시

트리의 상단에 위치한 컴포넌트와 루트 컴포넌트 근처의 컴포넌트를 최상위 컴포넌트라고 합니다. 자식 컴포넌트가 없는 컴포넌트를 리프 컴포넌트라고 합니다. 이 컴포넌트 분류는 앱의 데이터 흐름과 성능을 이해하는 데 유용합니다.

자바스크립트 모듈 간의 관계를 모델링하는 것은 앱을 이해하는데 유용한 또 다른 방법입니다. 이를 모듈 의존성 트리라고 정의합니다.
자바스크립트 모듈 간의 관계를 모델링하는 것은 앱을 이해하는 데 유용한 또 다른 방법입니다. 이를 모듈 의존성 트리라고 정의합니다.

<Diagram name="generic_dependency_tree" height={250} width={500} alt="A tree graph with five nodes. Each node represents a JavaScript module. The top-most node is labelled 'RootModule.js'. It has three arrows extending to the nodes: 'ModuleA.js', 'ModuleB.js', and 'ModuleC.js'. Each arrow is labelled as 'imports'. 'ModuleC.js' node has a single 'imports' arrow that points to a node labelled 'ModuleD.js'.">

Expand Down
2 changes: 1 addition & 1 deletion src/content/learn/escape-hatches.md
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,7 @@ Effect 재실행을 줄이는 방법을 배우려면 <strong>[Effect의 의존

## 커스텀 Hook으로 로직 재사용하기 {/*reusing-logic-with-custom-hooks*/}

React는 `useState`, `useContext`, 그리고 `useEffect`같은 Hook들이 내장되어 있습니다. 때로는 데이터를 가져오거나 사용자가 온라인 상태인지 여부를 추적하거나 대화방에 연결하는 등 조금 더 구체적인 목적을 가진 Hook이 존재하길 바랄 수도 있습니다. 이를 위해 애플리케이션의 필요에 따라 자신만의 Hook을 만들 수 있습니다.
React는 `useState`, `useContext`, 그리고 `useEffect` 같은 Hook들이 내장되어 있습니다. 때로는 데이터를 가져오거나 사용자가 온라인 상태인지 여부를 추적하거나 대화방에 연결하는 등 조금 더 구체적인 목적을 가진 Hook이 존재하길 바랄 수도 있습니다. 이를 위해 애플리케이션의 필요에 따라 자신만의 Hook을 만들 수 있습니다.

이번 예시에서는 `usePointerPosition` 커스텀 Hook은 커서 위치를 추적하는 반면 `useDelayedValue` 커스텀 Hook은 전달한 값보다 특정 밀리초만큼 "지연"된 값을 반환합니다. 샌드박스 미리보기 영역 위로 커서를 이동하면 커서를 따라 움직이는 점의 흔적을 확인할 수 있습니다.

Expand Down
10 changes: 5 additions & 5 deletions src/content/learn/extracting-state-logic-into-a-reducer.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ function yourReducer(state, action) {

React는 Reducer에서 반환한 값을 State에 설정합니다.

이 예시에서 이벤트 핸들러에 구현 되어있는 State 설정과 관련 로직을 Reducer 함수로 옮기기 위해서 다음과 같이 해보겠습니다.
이 예시에서 이벤트 핸들러에 구현되어 있는 State 설정과 관련 로직을 Reducer 함수로 옮기기 위해서 다음과 같이 해보겠습니다.

1. 첫 번째 인자에 현재 State (`tasks`) 선언하기.
2. 두 번째 인자에 `action` 객체 선언하기.
Expand Down Expand Up @@ -884,13 +884,13 @@ Reducer가 좋은 점만 있는 것은 아닙니다! 아래에서 `useState`와

Reducer를 작성할 때, 다음과 같은 두 가지 팁을 명심하세요.

- **Reducer는 반드시 순수해야 합니다.** [State 업데이트 함수](/learn/queueing-a-series-of-state-updates)와 비슷하게, Reducer는 렌더링 중에 실행됩니다! (Action은 다음 렌더링까지 대기합니다.) 이것은 Reducer는 [반드시 순수](/learn/keeping-components-pure)해야한다는 걸 의미합니다. 즉, 입력 값이 같다면 결과 값도 항상 같아야 합니다. 요청을 보내거나 timeout을 스케쥴링하거나 사이드 이펙트(컴포넌트 외부에 영향을 미치는 작업)를 수행해서는 안 됩니다. Reducer는 [객체](/learn/updating-objects-in-state)와 [배열](/learn/updating-arrays-in-state)을 변경하지 않고 업데이트해야 합니다.
- **Reducer는 반드시 순수해야 합니다.** [State 업데이트 함수](/learn/queueing-a-series-of-state-updates)와 비슷하게, Reducer는 렌더링 중에 실행됩니다! (Action은 다음 렌더링까지 대기합니다.) 이것은 Reducer는 [반드시 순수](/learn/keeping-components-pure)해야 한다는 걸 의미합니다. 즉, 입력 값이 같다면 결과 값도 항상 같아야 합니다. 요청을 보내거나 timeout을 스케줄링하거나 사이드 이펙트(컴포넌트 외부에 영향을 미치는 작업)를 수행해서는 안 됩니다. Reducer는 [객체](/learn/updating-objects-in-state)와 [배열](/learn/updating-arrays-in-state)을 변경하지 않고 업데이트해야 합니다.

- **각 Action은 데이터 안에서 여러 변경들이 있더라도 하나의 사용자 상호작용을 설명해야 합니다.** 예를 들어, 사용자가 Reducer가 관리하는 5개의 필드가 있는 양식에서 '재설정'을 누른 경우, 5개의 개별 `set_field` Action보다는 하나의 `reset_form` Action을 전송하는 것이 더 합리적입니다. 모든 Action을 Reducer에 기록하면 어떤 상호작용이나 응답이 어떤 순서로 일어났는지 재구성할 수 있을 만큼 로그가 명확해야 합니다. 이는 디버깅에 도움이 됩니다!

## Immer로 간결한 Reducer 작성하기 {/*writing-concise-reducers-with-immer*/}

일반적인 State에서 [객체](/learn/updating-objects-in-state#write-concise-update-logic-with-immer)와 [배열](/learn/updating-arrays-in-state#write-concise-update-logic-with-immer)을 업데이트 하는 것처럼, Immer 라이브러리를 사용하면 Reducer를 더 간결하게 작성할 수 있습니다. 이 라이브러리에서 제공하는 [`useImmerReducer`](https://github.com/immerjs/use-immer#useimmerreducer)를 사용하여 `push` 또는 `arr[i] =` 로 값을 할당하므로써 State를 변경해보겠습니다.
일반적인 State에서 [객체](/learn/updating-objects-in-state#write-concise-update-logic-with-immer)와 [배열](/learn/updating-arrays-in-state#write-concise-update-logic-with-immer)을 업데이트하는 것처럼, Immer 라이브러리를 사용하면 Reducer를 더 간결하게 작성할 수 있습니다. 이 라이브러리에서 제공하는 [`useImmerReducer`](https://github.com/immerjs/use-immer#useimmerreducer)를 사용하여 `push` 또는 `arr[i] =`로 값을 할당함으로써 State를 변경해보겠습니다.

<Sandpack>

Expand Down Expand Up @@ -1115,7 +1115,7 @@ Reducer는 순수해야 하기 때문에, 이 안에서는 State를 변경할

현재 `ContactList.js`와 `Chat.js`의 이벤트 핸들러 안에는 `// TODO` 주석이 있습니다. 이 때문에 input에 값을 입력해도 동작하지 않고 탭 버튼을 클릭해도 선택된 수신인을 변경할 수 없습니다.

`// TODO` 주석이 있는 부분을 지우고 상황에 맞는 Action을 `dispatch`하는 코드를 작성해보세요. Action에 대한 힌트를 얻고 싶다면 `messengerReducer.js`에 구현된 reducer를 확인해보세요. 이 reducer는 이미 작성되어있기 때문에 변경할 필요가 없습니다. 여러분은 `ContactList.js`와 `Chat.js`에 Action을 담아 전달하는 코드를 작성하기만 하면 됩니다.
`// TODO` 주석이 있는 부분을 지우고 상황에 맞는 Action을 `dispatch`하는 코드를 작성해보세요. Action에 대한 힌트를 얻고 싶다면 `messengerReducer.js`에 구현된 reducer를 확인해보세요. 이 reducer는 이미 작성되어 있기 때문에 변경할 필요가 없습니다. 여러분은 `ContactList.js`와 `Chat.js`에 Action을 담아 전달하는 코드를 작성하기만 하면 됩니다.

<Hint>

Expand Down Expand Up @@ -1948,7 +1948,7 @@ textarea {

#### 탭 전환 시, input 입력 값 복원하기 {/*restore-input-values-when-switching-between-tabs*/}

이 예시에서 선택된 수신자를 바꾸기 위해 탭 버튼을 누르면 message를 입력받는 input 필드의 텍스트 값이 항상 지워지도록 되어있습니다.
이 예시에서 선택된 수신자를 바꾸기 위해 탭 버튼을 누르면 message를 입력받는 input 필드의 텍스트 값이 항상 지워지도록 되어 있습니다.

```js
case 'changed_selection': {
Expand Down
8 changes: 4 additions & 4 deletions src/content/learn/keeping-components-pure.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,17 +143,17 @@ export default function TeaSet() {

이제 컴포넌트가 `guest` prop에만 의존해 JSX를 반환하므로 순수해졌습니다.

일반적으로 컴포넌트가 특정 순서대로 렌더링될 것이라고 기대하면 안됩니다. <Math><MathI>y</MathI> = 2<MathI>x</MathI></Math>를 <Math><MathI>y</MathI> = 5<MathI>x</MathI></Math>보다 먼저 계산하든 나중에 계산하든 상관없습니다. 두 수식은 서로 독립적으로 결과를 도출하기 때문입니다. 마찬가지로 각 컴포넌트는 "자기 자신만 생각"해야 합니다. 렌더링 도중에 다른 컴포넌트와 영향을 주고받거나, 의존해서는 안됩니다. 렌더링은 마치 학교 시험과 같습니다. 각 컴포넌트는 자신의 JSX를 직접 계산해야 합니다!
일반적으로 컴포넌트가 특정 순서대로 렌더링될 것이라고 기대하면 안 됩니다. <Math><MathI>y</MathI> = 2<MathI>x</MathI></Math>를 <Math><MathI>y</MathI> = 5<MathI>x</MathI></Math>보다 먼저 계산하든 나중에 계산하든 상관없습니다. 두 수식은 서로 독립적으로 결과를 도출하기 때문입니다. 마찬가지로 각 컴포넌트는 "자기 자신만 생각"해야 합니다. 렌더링 도중에 다른 컴포넌트와 영향을 주고받거나, 의존해서는 안 됩니다. 렌더링은 마치 학교 시험과 같습니다. 각 컴포넌트는 자신의 JSX를 직접 계산해야 합니다!

<DeepDive>

#### 엄격 모드(Strict Mode)로 순수하지 않은 연산을 찾아내기 {/*detecting-impure-calculations-with-strict-mode*/}

아직 전부 사용해본 적은 없을 수 있지만, React에서는 렌더링하는 동안 읽을 수 있는 세 가지 종류의 입력 요소가 있습니다. [Props](/learn/passing-props-to-a-component), [State](/learn/state-a-components-memory), 그리고 [Context](/learn/passing-data-deeply-with-context). 이러한 입력 요소는 항상 읽기전용으로 취급해야 합니다.

사용자의 입력에 따라 무언가를 _변경_ 하려는 경우, 변수 값을 직접 수정하는 대신 [State](/learn/state-a-components-memory)를 설정(set)해야 합니다. 컴포넌트가 렌더링되는 동안엔 기존 변수나 객체를 변경하면 안됩니다.
사용자의 입력에 따라 무언가를 _변경_ 하려는 경우, 변수 값을 직접 수정하는 대신 [State](/learn/state-a-components-memory)를 설정(set)해야 합니다. 컴포넌트가 렌더링되는 동안엔 기존 변수나 객체를 변경하면 안 됩니다.

React는 개발 중에 각 컴포넌트의 함수를 두 번 호출하는 "엄격 모드"를 제공합니다. **컴포넌트 함수를 두 번 호출함으로써, 엄격 모드는 이러한 규칙을 위반하는 컴포넌트를 찾는데 도움을 줍니다.**
React는 개발 중에 각 컴포넌트의 함수를 두 번 호출하는 "엄격 모드"를 제공합니다. **컴포넌트 함수를 두 번 호출함으로써, 엄격 모드는 이러한 규칙을 위반하는 컴포넌트를 찾는 데 도움을 줍니다.**

원래 예시에서 "Guest #1", "Guest #2", "Guest #3" 대신 "Guest #2", "Guest #4", "Guest #6"이 어떻게 표시되었는지 확인해보세요. 기존 함수가 순수하지 않았기에 엄격 모드로 인해 두 번 호출되는 과정에서 로직이 깨져버렸습니다. 그러나 수정된 순수 버전의 함수는 두 번씩 호출되더라도 동작합니다. **순수 함수는 오직 계산만 수행하므로 두 번 호출되더라도 아무것도 변하지 않습니다.** `double(2)`를 두 번 호출해도 반환값은 변하지 않는 것과 <Math><MathI>y</MathI> = 2<MathI>x</MathI></Math>을 두 번 푼다고 해도 <MathI>y</MathI>값이 바뀌지는 않는 것처럼, 항상 같은 입력이면 같은 출력을 내보냅니다.

Expand Down Expand Up @@ -219,7 +219,7 @@ React에서, **사이드 이펙트는 보통 [이벤트 핸들러](/learn/respon
* **자신의 일에만 집중합니다.** 렌더링 전에 존재했던 객체나 변수를 변경하지 않아야 합니다.
* **같은 입력, 같은 출력.** 입력이 같을 경우, 컴포넌트는 항상 같은 JSX를 반환해야 합니다.
* 렌더링은 언제든지 발생할 수 있으므로 컴포넌트는 서로의 렌더링 순서에 의존하지 않아야 합니다.
* 컴포넌트가 렌더링을 위해 사용하는 입력을 변경해서는 안됩니다. 여기에는 Props, State, Context가 포함됩니다. 화면을 업데이트하려면 기존 객체를 변경하는 대신 [State를 "set"](/learn/state-a-components-memory)하세요.
* 컴포넌트가 렌더링을 위해 사용하는 입력을 변경해서는 안 됩니다. 여기에는 Props, State, Context가 포함됩니다. 화면을 업데이트하려면 기존 객체를 변경하는 대신 [State를 "set"](/learn/state-a-components-memory)하세요.
* 반환하는 JSX에서 컴포넌트의 로직을 표현하기 위해 노력하세요. "무언가를 변경"해야 할 경우 일반적으로 이벤트 핸들러에서 변경하고 싶을 것입니다. 최후의 수단으로 `useEffect`를 사용할 수 있습니다.
* 순수 함수를 작성하는 것은 약간의 연습이 필요하지만, React 패러다임의 힘을 발휘하게 합니다.

Expand Down
4 changes: 2 additions & 2 deletions src/content/learn/manipulating-the-dom-with-refs.md
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ li {

Strict Mode가 활성화되어 있다면 개발 모드에서 ref 콜백이 두 번 실행됩니다.

ref 콜백에서 [이 방식이 버그를 찾는데 어떻게 도움이 되는지](/reference/react/StrictMode#fixing-bugs-found-by-re-running-ref-callbacks-in-development) 자세히 알아보세요.
ref 콜백에서 [이 방식이 버그를 찾는 데 어떻게 도움이 되는지](/reference/react/StrictMode#fixing-bugs-found-by-re-running-ref-callbacks-in-development) 자세히 알아보세요.

</Note>

Expand Down Expand Up @@ -460,7 +460,7 @@ export default function Form() {
React의 모든 갱신은 [두 단계](/learn/render-and-commit#step-3-react-commits-changes-to-the-dom)로 나눌 수 있습니다.

* **렌더링** 단계에서 React는 화면에 무엇을 그려야 하는지 알아내도록 컴포넌트를 호출합니다.
* **커밋** 단계에서 React는 변경사항을 DOM에 적용합니다.
* **커밋** 단계에서 React는 변경 사항을 DOM에 적용합니다.

일반적으로 렌더링하는 중 ref에 접근하는 것을 [원하지 않습니다](/learn/referencing-values-with-refs#best-practices-for-refs). DOM 노드를 보유하는 ref도 마찬가지입니다. 첫 렌더링에서 DOM 노드는 아직 생성되지 않아서 `ref.current`는 `null`인 상태입니다. 그리고 갱신에 의한 렌더링에서 DOM 노드는 아직 업데이트되지 않은 상태입니다. 두 상황 모두 ref를 읽기에 너무 이른 상황입니다.

Expand Down
Loading
Loading