Skip to content

Commit

Permalink
docs: update cache.md
Browse files Browse the repository at this point in the history
  • Loading branch information
lumirlumir committed Jan 6, 2025
1 parent 634f9ed commit 5060389
Showing 1 changed file with 24 additions and 24 deletions.
48 changes: 24 additions & 24 deletions src/content/reference/react/cache.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,31 +40,31 @@ function Chart({data}) {
// ...
}
```
`getMetrics`가 처음 `data`를 호출할 때, `getMetrics``calculateMetrics(data)`를 호출하고 캐시에 결과를 저장합니다. `getMetrics`가 같은 `data`와 함께 다시 호출되면, `calculateMetrics(data)`를 다시 호출하는 대신에 캐싱 된 결과를 반환합니다.
`getMetrics`가 처음 `data`를 호출할 때, `getMetrics``calculateMetrics(data)`를 호출하고 캐시에 결과를 저장합니다. `getMetrics`가 같은 `data`와 함께 다시 호출되면, `calculateMetrics(data)`를 다시 호출하는 대신에 캐싱된 결과를 반환합니다.

[아래에 있는 예시를 참고하세요.](#usage)
[아래 예시를 참고하세요.](#usage)

#### 매개변수 {/*parameters*/}

- `fn`: 결과를 저장하고 싶은 함수. `fn` 어떤 인자값도 받을 수 있고 어떤 결과도 반환할 수 있습니다.
- `fn`: 결과를 저장하고 싶은 함수. `fn` 어떤 인수도 받을 수 있고 어떠한 결과도 반환할 수 있습니다.

#### 반환값 {/*returns*/}

`cache`는 같은 타입 시그니처를 가진 `fn`캐싱 된 버전을 반환합니다. 이 과정에서 `fn` 호출하지 않습니다.
`cache`는 같은 타입 시그니처를 가진 `fn`캐싱된 버전을 반환합니다. 이 과정에서 `fn` 호출하지 않습니다.

주어진 인자값과 함께 `cachedFn`를 호출할 때, 캐시에 캐싱 된 데이터가 있는지 먼저 확인합니다. 만약 캐싱 된 데이터가 있다면, 그 결과를 반환합니다. 만약 없다면, 매개변수와 함께 `fn`을 호출하고 결과를 캐시에 저장하고 값을 반환합니다. `fn` 유일하게 호출되는 경우는 캐싱 된 데이터가 없는 경우입니다.
주어진 인자값과 함께 `cachedFn`를 호출할 때, 캐시에 캐싱된 데이터가 있는지 먼저 확인합니다. 만약 캐싱된 데이터가 있다면, 그 결과를 반환합니다. 만약 없다면, 매개변수와 함께 `fn`을 호출하고 결과를 캐시에 저장하고 값을 반환합니다. `fn` 유일하게 호출되는 경우는 캐싱된 데이터가 없는 경우입니다.

<Note>

입력을 기반으로 반환 값 캐싱을 최적화하는 것을 [_메모이제이션_](https://ko.wikipedia.org/wiki/%EB%A9%94%EB%AA%A8%EC%9D%B4%EC%A0%9C%EC%9D%B4%EC%85%98)라고 합니다. `cache`에서 반환되는 함수를 메모화된 함수라고 합니다.
입력을 기반으로 반환 값 캐싱을 최적화하는 것을 [_메모이제이션_](https://ko.wikipedia.org/wiki/%EB%A9%94%EB%AA%A8%EC%9D%B4%EC%A0%9C%EC%9D%B4%EC%85%98)이라고 합니다. `cache`에서 반환되는 함수를 메모화된 함수라고 합니다.

</Note>

#### 주의 사항 {/*caveats*/}

- React는 서버 요청마다 모든 메모화된 함수들을 위해 캐시를 무효화합니다.
- `cache`를 호출할 때마다 새 함수가 생성됩니다. 즉, 동일한 함수로 `cache`를 여러 번 호출하면 동일한 캐시를 공유하지 않는 다른 메모화된 함수가 반환됩니다.
- `cachedFn` 또한 캐시 에러를 잡아냅니다. `fn` 특정 인수에 대해 에러를 던지면 캐싱 되고, 동일한 인수로 `cachedFn`를 호출하면 동일한 에러가 다시 발생합니다.
- `cachedFn` 또한 캐시 오류를 잡아냅니다. `fn` 특정 인수에 대해 오류를 던지면 캐싱되고, 동일한 인수로 `cachedFn`를 호출하면 동일한 오류가 다시 발생합니다.
- `cache`[서버 컴포넌트](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components)에서만 사용가능합니다.

---
Expand Down Expand Up @@ -94,11 +94,11 @@ function TeamReport({users}) {
// ...
}
```
같은 `user` 객체가 `Profile``TeamReport`에서 렌더될 때, 두 컴포넌트는 일을 공유하고, `user`를 위한 `calculateUserMetrics`를 한 번만 호출합니다.
같은 `user` 객체가 `Profile``TeamReport`에서 렌더링될 때, 두 컴포넌트는 작업을 공유하고, `user`를 위한 `calculateUserMetrics`를 한 번만 호출합니다.

`Profile`이 먼저 렌더된다고 가정해 봅시다. `Profile`은 <CodeStep step={1}>`getUserMetrics`</CodeStep>를 호출하고, 캐싱 된 결과가 있는지 확인합니다. `user`와 함께 `getUserMetrics`를 처음 호출하기 때문에, 현재 저장된 캐시는 없습니다. `getUserMetrics``user`와 함께 `calculateUserMetrics`를 호출하고 캐시에 결괏값을 저장합니다.
`Profile`이 먼저 렌더링된다고 가정합시다. `Profile`은 <CodeStep step={1}>`getUserMetrics`</CodeStep>를 호출하고, 캐싱된 결과가 있는지 확인합니다. `user`와 함께 `getUserMetrics`를 처음 호출하기 때문에, 현재 저장된 캐시는 없습니다. `getUserMetrics``user`와 함께 `calculateUserMetrics`를 호출하고 캐시에 결과값을 저장합니다.

`TeamReport``users` 목록과 함께 렌더될 때 같은 `user` 객체를 사용하게 되고, 이는 <CodeStep step={2}>`getUserMetrics`</CodeStep>를 호출해 캐시에서 결괏값을 읽어옵니다.
`TeamReport``users` 목록과 함께 렌더링될 때 같은 `user` 객체를 사용하게 되고, 이는 <CodeStep step={2}>`getUserMetrics`</CodeStep>를 호출해 캐시에서 결과값을 읽어옵니다.

<Pitfall>

Expand Down Expand Up @@ -135,9 +135,9 @@ export function Precipitation({cityData}) {

위의 예시에서, <CodeStep step={2}>`Precipitation`</CodeStep>와 <CodeStep step={1}>`Temperature`</CodeStep>는 각각 `cache`를 호출하여 자체 캐시 조회를 통해 새로운 메모화된 함수를 만들어 냅니다. 두 컴포넌트가 같은 `cityData`를 렌더링한다면, `calculateWeekReport`를 호출하는 반복 작업을 하게 됩니다.

게다가, `Temperature`는 컴포넌트가 렌더될 때마다 어떤 캐시 공유도 허용하지 않는 <CodeStep step={1}>새로운 메모화된 함수</CodeStep>를 생성하게 됩니다.
게다가, `Temperature`는 컴포넌트가 렌더링될 때마다 어떤 캐시 공유도 허용하지 않는 <CodeStep step={1}>새로운 메모화된 함수</CodeStep>를 생성하게 됩니다.

캐시 사용을 늘리고 일을 줄이기 위해서 두 컴포넌트는 같은 캐시에 접근하는 같은 메모화된 함수를 호출해야 합니다. 대신, 컴포넌트끼리 [`import` 할 수 있는](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) 전용 모듈에 메모화된 함수를 정의하세요.
캐시 사용을 늘리고 작업을 줄이기 위해서 두 컴포넌트는 같은 캐시에 접근하는 같은 메모화된 함수를 호출해야 합니다. 대신, 컴포넌트끼리 [`import` 할 수 있는](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) 전용 모듈에 메모화된 함수를 정의하세요.

```js [[3, 5, "export default cache(calculateWeekReport)"]]
// getWeekReport.js
Expand Down Expand Up @@ -171,7 +171,7 @@ export default function Precipitation({cityData}) {

### 데이터의 스냅샷 공유하기 {/*take-and-share-snapshot-of-data*/}

컴포넌트끼리 데이터의 스냅샷을 공유하기 위해선 `fetch`와 같이 데이터를 받아오는 함수와 함께 `cache`를 사용해야 합니다. 여러 컴포넌트가 같은 데이터를 받아올 때, 요청이 한 번만 발생하고 받아온 데이터는 캐싱 되며 컴포넌트끼리 공유됩니다. 모든 컴포넌트는 서버 렌더링 전반에 걸쳐 동일한 데이터 스냅샷을 참조합니다.
컴포넌트끼리 데이터의 스냅샷을 공유하기 위해선 `fetch`와 같이 데이터를 가져오는 함수와 함께 `cache`를 사용해야 합니다. 여러 컴포넌트가 같은 데이터를 받아올 때, 요청이 한 번만 발생하고 받아온 데이터는 캐싱되며 컴포넌트끼리 공유됩니다. 모든 컴포넌트는 서버 렌더링 전반에 걸쳐 동일한 데이터 스냅샷을 참조합니다.

```js [[1, 4, "city"], [1, 5, "fetchTemperature(city)"], [2, 4, "getTemperature"], [2, 9, "getTemperature"], [1, 9, "city"], [2, 14, "getTemperature"], [1, 14, "city"]]
import {cache} from 'react';
Expand All @@ -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>가 캐시 키처럼 동작하게 됩니다.

Expand Down Expand Up @@ -251,7 +251,7 @@ function Page({id}) {

#### 비동기 작업 캐싱하기 {/*caching-asynchronous-work*/}

[비동기 함수](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/async_function)의 결과를 보면, [Promise](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise)를 받습니다. 이 Promise는 작업에 대한 상태(_보류 중_, _완료됨_, _실패함_)와 최종적으로 확정된 결과를 가지고 있습니다.
[비동기 함수](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/async_function)의 결과를 보면, [Promise](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise)를 받습니다. 이 Promise는 작업에 대한 상태(_대기_, _완료_, _실패_)와 최종적으로 확정된 결과를 가지고 있습니다.

이 예시에서, 비동기 함수 <CodeStep step={1}>`fetchData`</CodeStep>는 `fetch`를 기다리는 Promise를 반환합니다.

Expand All @@ -272,11 +272,11 @@ async function MyComponent() {

<CodeStep step={2}>`getData`</CodeStep>를 처음 호출할 때, <CodeStep step={1}>`fetchData`</CodeStep>에서 반환된 Promise가 캐싱 됩니다. 이후 조회 시, 같은 Promise를 반환합니다.

첫 번째 <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={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`는 즉시 값을 반환합니다. 두 결과 모두 성능상의 이점이 있습니다.
_완료된_ 결과나 오류에 대한 Promise가 이미 정해진 경우, `await`는 즉시 값을 반환합니다. 두 결과 모두 성능상의 이점이 있습니다.
</DeepDive>

<Pitfall>
Expand Down Expand Up @@ -308,7 +308,7 @@ React는 컴포넌트에서 메모화된 함수의 캐시 접근만 제공합니

<DeepDive>

#### `cache`, [`memo`](/reference/react/memo), or [`useMemo`](/reference/react/useMemo) 중 언제 어떤 걸 사용해야 하나요? {/*cache-memo-usememo*/}
#### `cache`, [`memo`](/reference/react/memo), [`useMemo`](/reference/react/useMemo) 중 언제 어떤 걸 사용해야 하나요? {/*cache-memo-usememo*/}

언급된 모든 API들은 메모이제이션을 제공하지만, 메모화 대상, 캐시 접근 권한, 캐시 무효화 시점에 차이가 있습니다.

Expand Down Expand Up @@ -367,7 +367,7 @@ function App() {

#### `memo` {/*deep-dive-memo*/}

[`memo`](reference/react/memo)는 프로퍼티가 변경되지 않았을 때 컴포넌트가 렌더링 되는 것을 막기 위해 사용합니다.
[`memo`](reference/react/memo)는 프로퍼티가 변경되지 않았을 때 컴포넌트가 다시 렌더링 되는 것을 막기 위해 사용합니다.

```js
'use client';
Expand All @@ -390,9 +390,9 @@ function App() {
}
```

예시에서 `MemoWeatherReport` 컴포넌트 모두 첫 번째 렌더에서 `calculateAvg`를 호출합니다. 하지만 `App` 렌더링 될 때 `record`의 변경이 없다면 프로퍼티의 변경이 없기 때문에 `MemoWeatherReport`가 다시 렌더링 되지 않습니다.
예시에서 `MemoWeatherReport` 컴포넌트 모두 첫 번째 렌더링에서 `calculateAvg`를 호출합니다. 하지만 `App`다시 렌더링 될 때 `record`의 변경이 없다면 프로퍼티의 변경이 없기 때문에 `MemoWeatherReport`가 다시 렌더링되지 않습니다.

`useMemo`와 비교하면 `memo`는 프로퍼티와 특정 계산을 기반으로 컴포넌트 렌더링을 메모화합니다. `useMemo`와 유사하게, 메모화된 컴포넌트는 마지막 프로퍼티 값에 대한 마지막 렌더링을 캐싱합니다. 프로퍼티가 변경되면, 캐쉬는 무효화되고 컴포넌트는 재 렌더링 됩니다.
`useMemo`와 비교하면 `memo`는 프로퍼티와 특정 계산을 기반으로 컴포넌트 렌더링을 메모화합니다. `useMemo`와 유사하게, 메모화된 컴포넌트는 마지막 프로퍼티 값에 대한 마지막 렌더링을 캐싱합니다. 프로퍼티가 변경되면, 캐시는 무효화되고 컴포넌트는 다시 렌더링됩니다.

</DeepDive>

Expand All @@ -408,9 +408,9 @@ function App() {

위의 어느 것도 해당하지 않는다면, React가 캐시에 무엇이 존재하는지 확인하는 방식에 문제가 있을 수 있습니다.

인자가 [원시 값](https://developer.mozilla.org/ko/docs/Glossary/Primitive)(객체, 함수, 배열 등) 이 아니라면, 같은 객체 참조를 넘겼는지 확인하세요.
인자가 [원시 값](https://developer.mozilla.org/ko/docs/Glossary/Primitive)(객체, 함수, 배열 등)이 아니라면, 같은 객체 참조를 넘겼는지 확인하세요.

메모화된 함수 호출 시, React는 입력된 인자값을 조회해 결과가 이미 캐싱 되어 있는지 확인합니다. React는 인수의 얕은 동등성을 사용해 캐시 히트가 있는지를 결정합니다.
메모화된 함수 호출 시, React는 입력된 인자값을 조회해 결과가 이미 캐싱되어 있는지 확인합니다. React는 인수의 얕은 동등성을 사용해 캐시 히트가 있는지를 결정합니다.

```js
import {cache} from 'react';
Expand Down

0 comments on commit 5060389

Please sign in to comment.