Skip to content

Sync with react.dev @ 5138e605 #1173

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Apr 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
12 changes: 11 additions & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable import/no-anonymous-default-export */
import mark from 'eslint-plugin-mark';

export default [
Expand All @@ -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},
],
},
},
];
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
29 changes: 17 additions & 12 deletions src/components/MDX/ErrorDecoder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ function parseQueryString(search: string): Array<string | undefined> {
}

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<React.ReactNode | null>(() =>
Expand All @@ -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 (
<code
className={cn(
'block bg-red-100 text-red-600 py-4 px-6 mt-5 rounded-lg',
'whitespace-pre-line block bg-red-100 text-red-600 py-4 px-6 mt-5 rounded-lg',
isReady ? 'opacity-100' : 'opacity-0'
)}>
<b>{message}</b>
Expand Down
4 changes: 2 additions & 2 deletions src/components/MDX/Sandpack/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
},
},
Expand Down
2 changes: 1 addition & 1 deletion src/content/blog/2024/12/05/react-19.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
---

{/*<!-- eslint-disable mark/no-double-space -->*/}
December 05, 2024 by [The React Team](/community/team)

---
Expand Down
3 changes: 2 additions & 1 deletion src/content/community/meetups.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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/)
Expand Down
2 changes: 1 addition & 1 deletion src/content/community/versioning-policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -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**를 사용할 때 다음과 같습니다.

Expand Down
4 changes: 2 additions & 2 deletions src/content/learn/build-a-react-app-from-scratch.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

</Note>

Expand All @@ -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)


Expand Down
2 changes: 1 addition & 1 deletion src/content/learn/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ export default function MyApp() {
}
```

이렇게 전달한 정보를 *props*라고 합니다. 이제 `MyApp` 컴포넌트는 `count` state와 `handleClick` 이벤트 핸들러를 포함하며, *이 두 가지를 각 버튼에 props로 전달합니다*.
이렇게 전달한 정보를 *props*라고 합니다. 이제 `MyApp` 컴포넌트는 `count` state와 `handleClick` 이벤트 핸들러를 포함하며, *이 두 가지를 각 버튼에 props로 전달합니다*.

마지막으로 부모 컴포넌트에서 전달한 props를 *읽도록* `MyButton`을 변경합니다.

Expand Down
1 change: 0 additions & 1 deletion src/content/learn/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).

</Note>
>>>>>>> ab18d2f0f5151ab0c927a12eb0a64f8170762eff

## 다음 단계 {/*next-steps*/}

Expand Down
4 changes: 2 additions & 2 deletions src/content/learn/queueing-a-series-of-state-updates.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ React가 이벤트 핸들러를 수행하는 동안 여러 코드를 통해 작

React는 `3`을 최종 결과로 저장하고 `useState`에서 반환합니다.

이것이 위 예시 "+3"을 클릭하면 값이 3씩 올바르게 증가하는 이유입니다.
이것이 위 예시 "+3"을 클릭하면 값이 3씩 올바르게 증가하는 이유입니다.

### state를 교체한 후 업데이트하면 어떻게 되나요? {/*what-happens-if-you-update-state-after-replacing-it*/}

Expand Down Expand Up @@ -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 큐를 순회합니다.

Expand Down
4 changes: 2 additions & 2 deletions src/content/learn/reusing-logic-with-custom-hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -922,7 +922,7 @@ export function useChatRoom({ serverUrl, roomId, onReceiveMessage }) {
}
```

이제 `ChatRoom`가 재렌더링될 때마다 채팅방이 재연결되지 않습니다. 여기 커스텀 Hook에 이벤트 핸들러를 넘겨주는 직접 다뤄볼 수 있는 제대로 동작하는 예시가 있습니다.
이제 `ChatRoom`가 재렌더링될 때마다 채팅방이 재연결되지 않습니다. 여기 커스텀 Hook에 이벤트 핸들러를 넘겨주는 직접 다뤄볼 수 있는 제대로 동작하는 예시가 있습니다.

<Sandpack>

Expand Down Expand Up @@ -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`이 있습니다.

<Sandpack>

Expand Down
2 changes: 1 addition & 1 deletion src/content/learn/sharing-state-between-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ state를 올리려면, 조정하려는 *두* 자식 컴포넌트의 가장 가
- `Panel`
- `Panel`

예시에서는 `Accordion` 컴포넌트입니다. 이 컴포넌트는 두 패널의 상위에 있고 props를 제어할 수 있기 때문에 현재 어느 패널이 활성화되었는지에 대한 "진리의 원천(source of truth)"이 됩니다. `Accordion` 컴포넌트가 하드 코딩된 값을 가지는 `isActive`를 (예를 들면 `true`) 두 패널에 전달하도록 만듭니다.
예시에서는 `Accordion` 컴포넌트입니다. 이 컴포넌트는 두 패널의 상위에 있고 props를 제어할 수 있기 때문에 현재 어느 패널이 활성화되었는지에 대한 "진리의 원천(source of truth)"이 됩니다. `Accordion` 컴포넌트가 하드 코딩된 값을 가지는 `isActive`를 (예를 들면 `true`) 두 패널에 전달하도록 만듭니다.

<Sandpack>

Expand Down
2 changes: 1 addition & 1 deletion src/content/learn/tutorial-tic-tac-toe.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
2 changes: 1 addition & 1 deletion src/content/reference/react-dom/components/input.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`: `<input>` 은 자식을 받지 않습니다.
* [`form`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#form): 문자열 타입. 입력이 속하는 `<form>`의 `id`를 지정합니다. 생략 시 가장 가까운 부모 폼으로 설정됩니다.
* [`form`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#form): 문자열 타입. 입력이 속하는 `<form>`의 `id`를 지정합니다. 생략 시 가장 가까운 부모 폼으로 설정됩니다.
* [`formAction`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#formaction): 문자열 타입. `type="submit"` 과 `type="image"`의 부모 `<form action>` 을 덮어씁니다.
* [`formEnctype`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#formenctype): 문자열 타입. `type="submit"` 과 `type="image"`의 부모 `<form enctype>` 을 덮어씁니다.
* [`formMethod`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#formmethod): 문자열 타입. `type="submit"` 과 `type="image"`의 부모 `<form method>` 를 덮어씁니다.
Expand Down
5 changes: 2 additions & 3 deletions src/content/reference/react/Component.md
Original file line number Diff line number Diff line change
Expand Up @@ -1273,7 +1273,7 @@ button { margin-left: 10px; }

error boundary 컴포넌트를 구현하려면 오류에 대한 응답으로 state를 업데이트하고 사용자에게 오류 메시지를 표시할 수 있는 [`static getDerivedStateFromError`](#static-getderivedstatefromerror)를 제공해야 합니다. 또한 선택적으로 [`componentDidCatch`](#componentdidcatch)를 구현하여 분석 서비스에 오류를 기록하는 등의 추가 로직을 추가할 수도 있습니다.

<CanaryBadge /> 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';
Expand All @@ -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(),
);
}
Expand Down
8 changes: 7 additions & 1 deletion src/content/reference/react/StrictMode.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)


Expand Down Expand Up @@ -124,6 +124,12 @@ function App() {

이 예시에서 `Header`와 `Footer` 컴포넌트에서는 Strict Mode 검사가 실행되지 않습니다. 그러나 `Sidebar`와 `Content`, 그리고 그 자손 컴포넌트는 깊이에 상관없이 검사가 실행됩니다.

<Note>

When `StrictMode` is enabled for a part of the app, React will only enable behaviors that are possible in production. For example, if `<StrictMode>` 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.

</Note>

---

### 개발 중 이중 렌더링으로 발견한 버그 수정 {/*fixing-bugs-found-by-double-rendering-in-development*/}
Expand Down
2 changes: 1 addition & 1 deletion src/content/reference/react/act.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
54 changes: 0 additions & 54 deletions src/content/reference/react/captureOwnerStack.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@
title: captureOwnerStack
---

<Canary>

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).

</Canary>

<Intro>

`captureOwnerStack` reads the current Owner Stack in development and returns it as a string if available.
Expand Down Expand Up @@ -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
<!DOCTYPE html>
<html lang="en">
Expand Down Expand Up @@ -357,22 +335,6 @@ const container = document.getElementById("root");
createRoot(container).render(<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"
}
}
```

```js src/App.js
function Component() {
return <button onClick={() => console.error('Some console error')}>Trigger console.error()</button>;
Expand Down Expand Up @@ -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"
}
}
```

</Sandpack>

### `captureOwnerStack` is not available {/*captureownerstack-is-not-available*/}
Expand Down
Loading