diff --git a/.github/workflows/discord_notify.yml b/.github/workflows/discord_notify.yml index a553b23a0..2f5b2a497 100644 --- a/.github/workflows/discord_notify.yml +++ b/.github/workflows/discord_notify.yml @@ -1,7 +1,7 @@ name: Discord Notify on: - pull_request: + pull_request_target: types: [opened, ready_for_review] permissions: {} @@ -14,7 +14,6 @@ jobs: contents: read with: actor: ${{ github.event.pull_request.user.login }} - is_remote: true notify: if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }} diff --git a/.github/workflows/label_core_team_prs.yml b/.github/workflows/label_core_team_prs.yml index 6099b8fcb..f9b3328ee 100644 --- a/.github/workflows/label_core_team_prs.yml +++ b/.github/workflows/label_core_team_prs.yml @@ -1,7 +1,7 @@ name: Label Core Team PRs on: - pull_request: + pull_request_target: permissions: {} @@ -18,7 +18,6 @@ jobs: contents: read with: actor: ${{ github.event.pull_request.user.login }} - is_remote: true label: if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }} diff --git a/postcss.config.js b/postcss.config.js index 427294522..d55c43c90 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -17,4 +17,4 @@ module.exports = { }, }, }, -} +}; diff --git a/public/js/jsfiddle-integration-babel.js b/public/js/jsfiddle-integration-babel.js index 006c79c8a..56059472f 100644 --- a/public/js/jsfiddle-integration-babel.js +++ b/public/js/jsfiddle-integration-babel.js @@ -4,12 +4,14 @@ // Do not delete or move this file. // Many fiddles reference it so we have to keep it here. -(function() { +(function () { var tag = document.querySelector( 'script[type="application/javascript;version=1.7"]' ); if (!tag || tag.textContent.indexOf('window.onload=function(){') !== -1) { - alert('Bad JSFiddle configuration, please fork the original React JSFiddle'); + alert( + 'Bad JSFiddle configuration, please fork the original React JSFiddle' + ); } tag.setAttribute('type', 'text/babel'); tag.textContent = tag.textContent.replace(/^\/\/ Checks all files and causes an error if heading ID is missing * yarn lint-heading-ids --fix --> Fixes all markdown file's heading IDs * yarn lint-heading-ids path/to/markdown.md --> Checks that particular file for missing heading ID (path can denote a directory or particular file) * yarn lint-heading-ids --fix path/to/markdown.md --> Fixes that particular file's markdown IDs (path can denote a directory or particular file) -*/ + */ const markdownPaths = process.argv.slice(2); if (markdownPaths.includes('--fix')) { diff --git a/src/components/Layout/Page.tsx b/src/components/Layout/Page.tsx index 24d379589..1040e1aa7 100644 --- a/src/components/Layout/Page.tsx +++ b/src/components/Layout/Page.tsx @@ -8,7 +8,7 @@ import {useRouter} from 'next/router'; import {SidebarNav} from './SidebarNav'; import {Footer} from './Footer'; import {Toc} from './Toc'; -// import SocialBanner from '../SocialBanner'; +import SocialBanner from '../SocialBanner'; import {DocsPageFooter} from 'components/DocsFooter'; import {Seo} from 'components/Seo'; import PageHeading from 'components/PageHeading'; @@ -137,7 +137,7 @@ export function Page({ /> )} - {/**/} + { } 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(() => @@ -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 ( {message} diff --git a/src/components/MDX/Sandpack/template.ts b/src/components/MDX/Sandpack/template.ts index 42f02f6a6..7fbd537e7 100644 --- a/src/components/MDX/Sandpack/template.ts +++ b/src/components/MDX/Sandpack/template.ts @@ -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', }, }, diff --git a/src/components/SocialBanner.tsx b/src/components/SocialBanner.tsx index 2db62c994..ae87d2050 100644 --- a/src/components/SocialBanner.tsx +++ b/src/components/SocialBanner.tsx @@ -7,7 +7,7 @@ import {useRef, useEffect} from 'react'; import cn from 'classnames'; import {ExternalLink} from './ExternalLink'; -const bannerText = 'Stream React Conf on May 15-16.'; +const bannerText = 'Join us for React Conf on Oct 7-8.'; const bannerLink = 'https://conf.react.dev/'; const bannerLinkText = 'Learn more.'; diff --git a/src/content/community/conferences.md b/src/content/community/conferences.md index 2422a09ce..e38c9755c 100644 --- a/src/content/community/conferences.md +++ b/src/content/community/conferences.md @@ -10,16 +10,6 @@ title: React カンファレンス ## Upcoming Conferences {/*upcoming-conferences*/} -### React Paris 2025 {/*react-paris-2025*/} -March 20 - 21, 2025. In-person in Paris, France (hybrid event) - -[Website](https://react.paris/) - [Twitter](https://x.com/BeJS_) - -### React Native Connection 2025 {/*react-native-connection-2025*/} -April 3 (Reanimated Training) + April 4 (Conference), 2025. Paris, France. - -[Website](https://reactnativeconnection.io/) - [X](https://x.com/reactnativeconn) - [Bluesky](https://bsky.app/profile/reactnativeconnect.bsky.social) - ### CityJS London 2025 {/*cityjs-london*/} April 23 - 25, 2025. In-person in London, UK @@ -50,6 +40,11 @@ September 2-4, 2025. Wrocław, Poland. [Website](https://www.reactuniverseconf.com/) - [Twitter](https://twitter.com/react_native_eu) - [LinkedIn](https://www.linkedin.com/events/reactuniverseconf7163919537074118657/) +### React Conf 2025 {/*react-conf-2025*/} +October 7-8, 2025. Henderson, Nevada, USA and free livestream + +[Website](https://conf.react.dev/) - [Twitter](https://x.com/reactjs) - [Bluesky](https://bsky.app/profile/react.dev) + ### React India 2025 {/*react-india-2025*/} October 31 - November 01, 2025. In-person in Goa, India (hybrid event) + Oct 15 2025 - remote day @@ -58,6 +53,16 @@ October 31 - November 01, 2025. In-person in Goa, India (hybrid event) + Oct 15 ## Past Conferences {/*past-conferences*/} +### React Paris 2025 {/*react-paris-2025*/} +March 20 - 21, 2025. In-person in Paris, France (hybrid event) + +[Website](https://react.paris/) - [Twitter](https://x.com/BeJS_) + +### React Native Connection 2025 {/*react-native-connection-2025*/} +April 3 (Reanimated Training) + April 4 (Conference), 2025. Paris, France. + +[Website](https://reactnativeconnection.io/) - [X](https://x.com/reactnativeconn) - [Bluesky](https://bsky.app/profile/reactnativeconnect.bsky.social) + ### React Day Berlin 2024 {/*react-day-berlin-2024*/} December 13 & 16, 2024. In-person in Berlin, Germany + remote (hybrid event) diff --git a/src/content/community/meetups.md b/src/content/community/meetups.md index 43b50b3d7..c1f04c2f2 100644 --- a/src/content/community/meetups.md +++ b/src/content/community/meetups.md @@ -47,6 +47,9 @@ title: React ミーティング ## Colombia {/*colombia*/} * [Medellin](https://www.meetup.com/React-Medellin/) +## Czechia {/*czechia*/} +* [Prague](https://guild.host/react-prague/) + ## Denmark {/*denmark*/} * [Aalborg](https://www.meetup.com/Aalborg-React-React-Native-Meetup/) * [Aarhus](https://www.meetup.com/Aarhus-ReactJS-Meetup/) @@ -78,7 +81,7 @@ title: React ミーティング * [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) @@ -166,6 +169,7 @@ title: React ミーティング * [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/) diff --git a/src/content/learn/build-a-react-app-from-scratch.md b/src/content/learn/build-a-react-app-from-scratch.md index b00205388..d4888524b 100644 --- a/src/content/learn/build-a-react-app-from-scratch.md +++ b/src/content/learn/build-a-react-app-from-scratch.md @@ -83,7 +83,7 @@ React エコシステムには、これらの問題に対するツールがた 以下のライブラリの使用をお勧めします。 -- [React Router](https://reactrouter.com/start/framework/custom) +- [React Router](https://reactrouter.com/start/data/custom) - [Tanstack Router](https://tanstack.com/router/latest) diff --git a/src/content/learn/reusing-logic-with-custom-hooks.md b/src/content/learn/reusing-logic-with-custom-hooks.md index a13f0000f..980465f1b 100644 --- a/src/content/learn/reusing-logic-with-custom-hooks.md +++ b/src/content/learn/reusing-logic-with-custom-hooks.md @@ -1333,7 +1333,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 には、これらの問題をすべて解決してくれる専用の API である [`useSyncExternalStore`](/reference/react/useSyncExternalStore) が含まれています。以下は、この新しい API を活用して書き直された `useOnlineStatus` フックです。 +React には、これらの問題をすべて解決してくれる専用の API である [`useSyncExternalStore`](/reference/react/useSyncExternalStore) が含まれています。以下は、この新しい API を活用して書き直された `useOnlineStatus` フックです。 diff --git a/src/content/reference/react-dom/client/createRoot.md b/src/content/reference/react-dom/client/createRoot.md index e0c9c233c..7dc64ca3c 100644 --- a/src/content/reference/react-dom/client/createRoot.md +++ b/src/content/reference/react-dom/client/createRoot.md @@ -90,6 +90,15 @@ React は `root` に `` を表示し、その内部の DOM の管理を * 同じルートに対して `render` を複数回呼び出すと、React は最新の JSX を反映するために必要なだけの DOM の更新を行います。React は、渡された JSX を以前にレンダーしたツリーと[「マッチング」](/learn/preserving-and-resetting-state)して、DOM のどの部分が再利用でき、どの部分を再作成する必要があるのかを決定します。同じルートに対して複数回 `render` を呼び出すことは、ルートコンポーネントで [`set` 関数](/reference/react/useState#setstate)を呼び出すことに似ており、React は不必要な DOM 更新を回避します。 +* レンダーは一旦始まると同期的に行われますが、`root.render(...)` 自体はそうではありません。つまり `root.render()` の後のコードが、その特定のレンダー内のいずれかのエフェクト (`useLayoutEffect`, `useEffect`) よりも先に実行される可能性があるということです。これは通常問題なく、調整が必要になることは稀です。エフェクトのタイミングが重要となる稀なケースでは、初期レンダーが完全に同期的に実行されるように、`root.render(...)` を [`flushSync`](https://react.dev/reference/react-dom/client/flushSync) で囲むことができます。 + + ```js + const root = createRoot(document.getElementById('root')); + root.render(); + // 🚩 The HTML will not include the rendered yet: + console.log(document.body.innerHTML); + ``` + --- ### `root.unmount()` {/*root-unmount*/} diff --git a/src/content/reference/react/Component.md b/src/content/reference/react/Component.md index 1896a1c93..f98d5e57a 100644 --- a/src/content/reference/react/Component.md +++ b/src/content/reference/react/Component.md @@ -1273,7 +1273,7 @@ button { margin-left: 10px; } エラーバウンダリコンポーネントを実装するためには、エラーに反応して state を更新し、ユーザにエラーメッセージを表示するための [`static getDerivedStateFromError`](#static-getderivedstatefromerror) を提供する必要があります。またオプションで、例えばエラーを分析サービスに記録するなどの追加のロジックを追加するために [`componentDidCatch`](#componentdidcatch) を実装することもできます。 - [`captureOwnerStack`](/reference/react/captureOwnerStack) を使うことで開発中にオーナーのスタックトレースを含めることが可能です。 +[`captureOwnerStack`](/reference/react/captureOwnerStack) を使うことで開発中にオーナーのスタックトレースを含めることが可能です。 ```js {9-12,14-27} import * as React from 'react'; @@ -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(), ); } diff --git a/src/content/reference/react/StrictMode.md b/src/content/reference/react/StrictMode.md index 83b32c714..181686d47 100644 --- a/src/content/reference/react/StrictMode.md +++ b/src/content/reference/react/StrictMode.md @@ -88,7 +88,7 @@ Strict Mode は開発中に以下のチェックを有効にします: - コンポーネントは、純粋でない (impure) レンダーによって引き起こされるバグを見つけるために、[レンダーを追加で 1 回行います](#fixing-bugs-found-by-double-rendering-in-development)。 - コンポーネントは、エフェクトのクリーンアップし忘れによるバグを見つけるために、[エフェクトの実行を追加で 1 回行います](#fixing-bugs-found-by-re-running-effects-in-development)。 -- コンポーネントは、ref のクリーンアップし忘れによるバグを見つけるために、[ref コールバックの実行を追加で 1 回行います](#fixing-bugs-found-by-cleaning-up-and-re-attaching-dom-refs-in-development)。 +- コンポーネントは、ref のクリーンアップし忘れによるバグを見つけるために、[ref コールバックの実行を追加で 1 回行います](#fixing-bugs-found-by-re-running-ref-callbacks-in-development)。 - コンポーネントが[非推奨の API を使っていないかチェック](#fixing-deprecation-warnings-enabled-by-strict-mode)します。 **これらのチェックはすべて開発環境専用であり、本番用ビルドには影響しません。** @@ -122,6 +122,12 @@ function App() { 上記の例では、Strict Mode のチェックは `Header` と `Footer` コンポーネントに対しては実行されません。しかし、`Sidebar` と `Content`、およびそれらの中にあるすべてのコンポーネントに対しては、どれだけ深いところにあってもチェックが実行されます。 + + +`StrictMode` がアプリの一部のみで有効になっている場合、React は本番環境で起こりえる動作のみを再現します。例えば、アプリのルートで `` が有効になっていない場合、初期マウント時に[エフェクトを追加で再実行](#fixing-bugs-found-by-re-running-effects-in-development)することはなくなります。親エフェクトなしに子エフェクトが二重に発火することは本番環境では起こらないためです。 + + + --- ### 開発中の二重レンダーによって見つかったバグの修正 {/*fixing-bugs-found-by-double-rendering-in-development*/} diff --git a/src/content/reference/react/captureOwnerStack.md b/src/content/reference/react/captureOwnerStack.md index f8ed21a8c..6d8cc502d 100644 --- a/src/content/reference/react/captureOwnerStack.md +++ b/src/content/reference/react/captureOwnerStack.md @@ -2,12 +2,6 @@ title: captureOwnerStack --- - - -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). - - - `captureOwnerStack` reads the current Owner Stack in development and returns it as a string if available. @@ -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 @@ -357,22 +335,6 @@ const container = document.getElementById("root"); createRoot(container).render(); ``` -```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 ; @@ -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" - } -} -``` - ### `captureOwnerStack` is not available {/*captureownerstack-is-not-available*/} diff --git a/src/content/reference/react/useId.md b/src/content/reference/react/useId.md index 98df3edc0..77af59360 100644 --- a/src/content/reference/react/useId.md +++ b/src/content/reference/react/useId.md @@ -46,6 +46,8 @@ function PasswordField() { * `useId` を、**リスト内の key の生成には使用しないでください**。[key はデータから生成される必要があります。](/learn/rendering-lists#where-to-get-your-key) +* 現在のところ、`useId` は[非同期のサーバコンポーネント](/reference/rsc/server-components#async-components-with-server-components)では利用できません。 + --- ## 使用法 {/*usage*/} diff --git a/src/content/reference/react/useSyncExternalStore.md b/src/content/reference/react/useSyncExternalStore.md index acf778a54..9c6ec74c6 100644 --- a/src/content/reference/react/useSyncExternalStore.md +++ b/src/content/reference/react/useSyncExternalStore.md @@ -405,14 +405,14 @@ function getSnapshot() { この `subscribe` 関数はコンポーネントの**内部**で定義されているため、再レンダーするたびに異なった値になります: -```js {4-7} +```js {2-5} function ChatIndicator() { - const isOnline = useSyncExternalStore(subscribe, getSnapshot); - // 🚩 Always a different function, so React will resubscribe on every re-render function subscribe() { // ... } + + const isOnline = useSyncExternalStore(subscribe, getSnapshot); // ... } @@ -420,28 +420,28 @@ function ChatIndicator() { React は、再レンダー間で異なる `subscribe` 関数を渡すと、ストアに再サブスクライブします。これがパフォーマンスの問題を引き起こし、再サブスクライブを避けたい場合は、`subscribe` 関数を外部に移動してください: -```js {6-9} -function ChatIndicator() { - const isOnline = useSyncExternalStore(subscribe, getSnapshot); +```js {1-4} +// ✅ Always the same function, so React won't need to resubscribe +function subscribe() { // ... } -// ✅ Always the same function, so React won't need to resubscribe -function subscribe() { +function ChatIndicator() { + const isOnline = useSyncExternalStore(subscribe, getSnapshot); // ... } ``` あるいは、`subscribe` を [`useCallback`](/reference/react/useCallback) でラップすることで、引数が変更されたときのみ再サブスクライブすることができます: -```js {4-8} +```js {2-5} function ChatIndicator({ userId }) { - const isOnline = useSyncExternalStore(subscribe, getSnapshot); - // ✅ Same function as long as userId doesn't change const subscribe = useCallback(() => { // ... }, [userId]); + + const isOnline = useSyncExternalStore(subscribe, getSnapshot); // ... } diff --git a/src/pages/errors/[errorCode].tsx b/src/pages/errors/[errorCode].tsx index de9eab5bb..a67c5742d 100644 --- a/src/pages/errors/[errorCode].tsx +++ b/src/pages/errors/[errorCode].tsx @@ -36,7 +36,7 @@ export default function ErrorDecoderPage({ }} routeTree={sidebarLearn as RouteItem} section="unknown"> -
{parsedContent}
+
{parsedContent}
{/*

We highly recommend using the development build locally when debugging diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 302ac20a5..48aed9260 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -117,6 +117,9 @@ { "title": "cache", "path": "/reference/react/cache" + }, { + "title": "captureOwnerStack", + "path": "/reference/react/captureOwnerStack" }, { "title": "createContext", @@ -147,11 +150,6 @@ "title": "experimental_taintUniqueValue", "path": "/reference/react/experimental_taintUniqueValue", "version": "canary" - }, - { - "title": "captureOwnerStack", - "path": "/reference/react/captureOwnerStack", - "version": "canary" } ] }, diff --git a/src/siteConfig.js b/src/siteConfig.js index da4bc02e0..30758dc82 100644 --- a/src/siteConfig.js +++ b/src/siteConfig.js @@ -2,7 +2,7 @@ * Copyright (c) Facebook, Inc. and its affiliates. */ exports.siteConfig = { - version: '19', + version: '19.1', // -------------------------------------- // Translations should replace these lines: languageCode: 'ja',