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 .github/workflows/analyze.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@ jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3

- name: Set up node
uses: actions/setup-node@v1
uses: actions/setup-node@v3
with:
node-version: '20.x'

- name: Install dependencies
uses: bahmutov/[email protected]

- name: Restore next build
uses: actions/cache@v2
uses: actions/cache@v3
id: restore-build-cache
env:
cache-name: cache-next-build
Expand Down
8 changes: 4 additions & 4 deletions src/content/reference/react/useCallback.md
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,7 @@ function ChatRoom({ roomId }) {

useEffect(() => {
const options = createOptions();
const connection = createConnection();
const connection = createConnection(options);
connection.connect();
// ...
```
Expand All @@ -720,7 +720,7 @@ function ChatRoom({ roomId }) {
```js {6}
useEffect(() => {
const options = createOptions();
const connection = createConnection();
const connection = createConnection(options);
connection.connect();
return () => connection.disconnect();
}, [createOptions]); // 🔴 문제점: 이 의존성은 매 렌더링마다 변경됩니다.
Expand All @@ -742,7 +742,7 @@ function ChatRoom({ roomId }) {

useEffect(() => {
const options = createOptions();
const connection = createConnection();
const connection = createConnection(options);
connection.connect();
return () => connection.disconnect();
}, [createOptions]); // ✅ createOptions가 변경될 때만 변경됩니다.
Expand All @@ -764,7 +764,7 @@ function ChatRoom({ roomId }) {
}

const options = createOptions();
const connection = createConnection();
const connection = createConnection(options);
connection.connect();
return () => connection.disconnect();
}, [roomId]); // ✅ roomId가 변경될 때만 변경됩니다.
Expand Down
76 changes: 76 additions & 0 deletions src/content/reference/react/useMemo.md
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,82 @@ label {

---

### Preventing an Effect from firing too often {/*preventing-an-effect-from-firing-too-often*/}

Sometimes, you might want to use a value inside an [Effect:](/learn/synchronizing-with-effects)

```js {4-7,10}
function ChatRoom({ roomId }) {
const [message, setMessage] = useState('');

const options = {
serverUrl: 'https://localhost:1234',
roomId: roomId
}

useEffect(() => {
const connection = createConnection(options);
connection.connect();
// ...
```

This creates a problem. [Every reactive value must be declared as a dependency of your Effect.](/learn/lifecycle-of-reactive-effects#react-verifies-that-you-specified-every-reactive-value-as-a-dependency) However, if you declare `options` as a dependency, it will cause your Effect to constantly reconnect to the chat room:


```js {5}
useEffect(() => {
const connection = createConnection(options);
connection.connect();
return () => connection.disconnect();
}, [options]); // 🔴 Problem: This dependency changes on every render
// ...
```

To solve this, you can wrap the object you need to call from an Effect in `useMemo`:

```js {4-9,16}
function ChatRoom({ roomId }) {
const [message, setMessage] = useState('');

const options = useMemo(() => {
return {
serverUrl: 'https://localhost:1234',
roomId: roomId
};
}, [roomId]); // ✅ Only changes when roomId changes

useEffect(() => {
const options = createOptions();
const connection = createConnection(options);
connection.connect();
return () => connection.disconnect();
}, [options]); // ✅ Only changes when createOptions changes
// ...
```

This ensures that the `options` object is the same between re-renders if `useMemo` returns the cached object.

However, since `useMemo` is performance optimization, not a semantic guarantee, React may throw away the cached value if [there is a specific reason to do that](#caveats). This will also cause the effect to re-fire, **so it's even better to remove the need for a function dependency** by moving your object *inside* the Effect:

```js {5-8,13}
function ChatRoom({ roomId }) {
const [message, setMessage] = useState('');

useEffect(() => {
const options = { // ✅ No need for useMemo or object dependencies!
serverUrl: 'https://localhost:1234',
roomId: roomId
}

const connection = createConnection(options);
connection.connect();
return () => connection.disconnect();
}, [roomId]); // ✅ Only changes when roomId changes
// ...
```

Now your code is simpler and doesn't need `useMemo`. [Learn more about removing Effect dependencies.](/learn/removing-effect-dependencies#move-dynamic-objects-and-functions-inside-your-effect)

### 다른 Hook의 종속성 메모화 {/*memoizing-a-dependency-of-another-hook*/}

컴포넌트 본문에서 직접 생성된 객체에 의존하는 연산이 있다고 가정하겠습니다.
Expand Down
1 change: 1 addition & 0 deletions src/content/reference/react/useReducer.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ function MyComponent() {
#### 주의 사항 {/*caveats*/}

* `useReducer`는 Hook이므로 **컴포넌트의 최상위** 또는 커스텀 Hook에서만 호출할 수 있습니다. 반복문이나 조건문에서는 사용할 수 없습니다. 필요한 경우 새로운 컴포넌트를 추출하고 해당 컴포넌트로 state를 옮겨서 사용할 수 있습니다.
* The `dispatch` function has a stable identity, so you will often see it omitted from effect dependencies, but including it will not cause the effect to fire. If the linter lets you omit a dependency without errors, it is safe to do. [Learn more about removing Effect dependencies.](/learn/removing-effect-dependencies#move-dynamic-objects-and-functions-inside-your-effect)
* Strict Mode에서는 [우연한 비순수성](#my-reducer-or-initializer-function-runs-twice)을 찾아내기 위해 reducer와 init 함수를 두번 호출합니다. 개발 환경에서만 한정된 동작이며, 배포 모드에는 영향을 미치지 않습니다. reducer와 init 함수가 순수 함수라면(그래야만 하듯이) 로직에 어떠한 영향도 미치지 않습니다. 호출 중 하나의 결과는 무시합니다.

---
Expand Down
2 changes: 2 additions & 0 deletions src/content/reference/react/useState.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ function handleClick() {

* React는 [state 업데이트를 batch 합니다. ](/learn/queueing-a-series-of-state-updates) **모든 이벤트 핸들러가 실행되고** `set` 함수를 호출한 후에 화면을 업데이트합니다. 이렇게 하면 단일 이벤트 중에 여러 번 리렌더링 하는 것을 방지할 수 있습니다. 드물지만 DOM에 접근하기 위해 React가 화면을 더 일찍 업데이트하도록 강제해야 하는 경우, [`flushSync`](/reference/react-dom/flushSync)를 사용할 수 있습니다.

* The `set` function has a stable identity, so you will often see it omitted from effect dependencies, but including it will not cause the effect to fire. If the linter lets you omit a dependency without errors, it is safe to do. [Learn more about removing Effect dependencies.](/learn/removing-effect-dependencies#move-dynamic-objects-and-functions-inside-your-effect)

* *렌더링 도중* `set` 함수를 호출하는 것은 현재 렌더링 중인 컴포넌트 내에서만 허용됩니다. React는 해당 출력을 버리고 즉시 새로운 state로 다시 렌더링을 시도합니다. 이 패턴은 거의 필요하지 않지만 **이전 렌더링의 정보를 저장하는 데 사용할 수 있습니다**. [아래 예시를 참고하세요.](#storing-information-from-previous-renders)

* Strict Mode에서 React는 [의도치않은 불순물을 찾기 위해](#my-initializer-or-updater-function-runs-twice) **업데이터 함수를 두 번 호출합니다**. 이는 개발 환경 전용 동작이며 프로덕션 환경에는 영향을 미치지 않습니다. 만약 업데이터 함수가 순수하다면(그래야 합니다) 동작에 영향을 미치지 않습니다. 호출 중 하나의 결과는 무시됩니다.
Expand Down
2 changes: 2 additions & 0 deletions src/content/reference/react/useTransition.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ function TabContainer() {

* `startTransition`에 전달하는 함수는 동기식이어야 합니다. React는 이 함수를 즉시 실행하여 실행하는 동안 발생하는 모든 state 업데이트를 Transition 으로 표시합니다. 나중에 더 많은 state 업데이트를 수행하려고 하면(예시: timeout), Transition 으로 표시되지 않습니다.

* The `startTransition` function has a stable identity, so you will often see it omitted from effect dependencies, but including it will not cause the effect to fire. If the linter lets you omit a dependency without errors, it is safe to do. [Learn more about removing Effect dependencies.](/learn/removing-effect-dependencies#move-dynamic-objects-and-functions-inside-your-effect)

* Transition으로 표시된 state 업데이트는 다른 state 업데이트에 의해 중단됩니다. 예를 들어, Transition 내에서 차트 컴포넌트를 업데이트한 다음 차트가 다시 렌더링 되는 도중에 입력을 시작하면 React는 입력 업데이트를 처리한 후 차트 컴포넌트에서 렌더링 작업을 다시 시작합니다.

* Transition 업데이트는 텍스트 입력을 제어하는 데 사용할 수 없습니다.
Expand Down
2 changes: 1 addition & 1 deletion src/content/reference/rsc/server-actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ React가 `EmptyNote` 서버 컴포넌트를 렌더링할 때, `createNoteAction`
export default function Button({onClick}) {
console.log(onClick);
// {$$typeof: Symbol.for("react.server.reference"), $$id: 'createNoteAction'}
return <button onClick={onClick}>Create Empty Note</button>
return <button onClick={() => onClick()}>Create Empty Note</button>
}
```

Expand Down
Loading