diff --git a/.eslintrc b/.eslintrc index f617dea26..f8b03f98a 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,11 +2,13 @@ "root": true, "extends": "next/core-web-vitals", "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint"], + "plugins": ["@typescript-eslint", "eslint-plugin-react-compiler"], "rules": { "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": ["error", { "varsIgnorePattern": "^_" }], - "react-hooks/exhaustive-deps": "error" + "@typescript-eslint/no-unused-vars": ["error", {"varsIgnorePattern": "^_"}], + "react-hooks/exhaustive-deps": "error", + "react/no-unknown-property": ["error", {"ignore": ["meta"]}], + "react-compiler/react-compiler": "error" }, "env": { "node": true, diff --git a/.github/workflows/discord_notify.yml b/.github/workflows/discord_notify.yml new file mode 100644 index 000000000..a4b8c9137 --- /dev/null +++ b/.github/workflows/discord_notify.yml @@ -0,0 +1,28 @@ +name: Discord Notify + +on: + pull_request_target: + types: [opened, ready_for_review] + +jobs: + check_maintainer: + uses: facebook/react/.github/workflows/shared_check_maintainer.yml@main + with: + actor: ${{ github.event.pull_request.user.login }} + is_remote: true + + notify: + if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }} + needs: check_maintainer + runs-on: ubuntu-latest + steps: + - name: Discord Webhook Action + uses: tsickert/discord-webhook@v6.0.0 + with: + webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }} + embed-author-name: ${{ github.event.pull_request.user.login }} + embed-author-url: ${{ github.event.pull_request.user.html_url }} + embed-author-icon-url: ${{ github.event.pull_request.user.avatar_url }} + embed-title: '#${{ github.event.number }} (+${{github.event.pull_request.additions}} -${{github.event.pull_request.deletions}}): ${{ github.event.pull_request.title }}' + embed-description: ${{ github.event.pull_request.body }} + embed-url: ${{ github.event.pull_request.html_url }} diff --git a/.github/workflows/label_core_team_prs.yml b/.github/workflows/label_core_team_prs.yml new file mode 100644 index 000000000..3d9fa2be1 --- /dev/null +++ b/.github/workflows/label_core_team_prs.yml @@ -0,0 +1,32 @@ +name: Label Core Team PRs + +on: + pull_request_target: + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout + SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1 + +jobs: + check_maintainer: + uses: facebook/react/.github/workflows/shared_check_maintainer.yml@main + with: + actor: ${{ github.event.pull_request.user.login }} + is_remote: true + + label: + if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }} + runs-on: ubuntu-latest + needs: check_maintainer + steps: + - name: Label PR as React Core Team + uses: actions/github-script@v7 + with: + script: | + github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: ${{ github.event.number }}, + labels: ['React Core Team'] + }); diff --git a/next-env.d.ts b/next-env.d.ts index 4f11a03dc..52e831b43 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -2,4 +2,4 @@ /// // NOTE: This file should not be edited -// see https://nextjs.org/docs/basic-features/typescript for more information. +// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information. diff --git a/next.config.js b/next.config.js index 61ff1944a..861792c8e 100644 --- a/next.config.js +++ b/next.config.js @@ -9,10 +9,8 @@ const nextConfig = { pageExtensions: ['jsx', 'js', 'ts', 'tsx', 'mdx', 'md'], reactStrictMode: true, experimental: { - // TODO: Remove after https://github.com/vercel/next.js/issues/49355 is fixed - appDir: false, scrollRestoration: true, - legacyBrowsers: false, + reactCompiler: true, }, env: {}, webpack: (config, {dev, isServer, ...options}) => { diff --git a/package.json b/package.json index 327e9ba67..e48f4cac5 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "ci-check": "npm-run-all prettier:diff --parallel lint tsc lint-heading-ids rss", "tsc": "tsc --noEmit", "start": "next start", - "postinstall": "patch-package && (is-ci || husky install .husky)", + "postinstall": "is-ci || husky install .husky", "check-all": "npm-run-all prettier lint:fix tsc rss", "rss": "node scripts/generateRss.js", "textlint": "cd textlint && yarn --frozen-lockfile && yarn textlint", @@ -26,8 +26,8 @@ }, "dependencies": { "@codesandbox/sandpack-react": "2.13.5", - "@docsearch/css": "^3.6.1", - "@docsearch/react": "^3.6.1", + "@docsearch/css": "^3.8.3", + "@docsearch/react": "^3.8.3", "@headlessui/react": "^1.7.0", "@radix-ui/react-context-menu": "^2.1.5", "body-scroll-lock": "^3.1.3", @@ -35,12 +35,12 @@ "date-fns": "^2.16.1", "debounce": "^1.2.1", "github-slugger": "^1.3.0", - "next": "^13.4.1", + "next": "15.1.0", "next-remote-watch": "^1.0.0", "parse-numeric-range": "^1.2.0", - "react": "^0.0.0-experimental-16d053d59-20230506", + "react": "^19.0.0", "react-collapsed": "4.0.4", - "react-dom": "^0.0.0-experimental-16d053d59-20230506", + "react-dom": "^19.0.0", "remark-frontmatter": "^4.0.1", "remark-gfm": "^3.0.1" }, @@ -56,13 +56,14 @@ "@types/mdx-js__react": "^1.5.2", "@types/node": "^14.6.4", "@types/parse-numeric-range": "^0.0.1", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.5", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", "@typescript-eslint/eslint-plugin": "^5.36.2", "@typescript-eslint/parser": "^5.36.2", "asyncro": "^3.0.0", "autoprefixer": "^10.4.2", "babel-eslint": "10.x", + "babel-plugin-react-compiler": "19.0.0-beta-e552027-20250112", "eslint": "7.x", "eslint-config-next": "12.0.3", "eslint-config-react-app": "^5.2.1", @@ -70,6 +71,7 @@ "eslint-plugin-import": "2.x", "eslint-plugin-jsx-a11y": "6.x", "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", "fs-extra": "^9.0.1", "globby": "^11.0.1", @@ -80,7 +82,6 @@ "mdast-util-to-string": "^1.1.0", "metro-cache": "0.72.2", "npm-run-all": "^4.1.5", - "patch-package": "^6.2.2", "postcss": "^8.4.5", "postcss-flexbugs-fixes": "4.2.1", "postcss-preset-env": "^6.7.0", @@ -96,7 +97,7 @@ "retext-smartypants": "^4.0.0", "rss": "^1.2.2", "tailwindcss": "^3.4.1", - "typescript": "^4.0.2", + "typescript": "^5.7.2", "unist-util-visit": "^2.0.3", "webpack-bundle-analyzer": "^4.5.0" }, @@ -111,5 +112,6 @@ "lint-staged": { "*.{js,ts,jsx,tsx,css}": "yarn prettier", "src/**/*.md": ["yarn fix-headings", "yarn textlint-staged --"] - } + }, + "packageManager": "yarn@1.22.22" } diff --git a/patches/next+13.4.1.patch b/patches/next+13.4.1.patch deleted file mode 100644 index 6de490aa4..000000000 --- a/patches/next+13.4.1.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff --git a/node_modules/next/dist/server/render.js b/node_modules/next/dist/server/render.js -index a1f8648..1b3d608 100644 ---- a/node_modules/next/dist/server/render.js -+++ b/node_modules/next/dist/server/render.js -@@ -758,9 +758,14 @@ async function renderToHTML(req, res, pathname, query, renderOpts) { - // Always using react concurrent rendering mode with required react version 18.x - const renderShell = async (EnhancedApp, EnhancedComponent)=>{ - const content = renderContent(EnhancedApp, EnhancedComponent); -- return await (0, _nodewebstreamshelper.renderToInitialStream)({ -- ReactDOMServer: _serverbrowser.default, -- element: content -+ return new Promise((resolve, reject) => { -+ (0, _nodewebstreamshelper.renderToInitialStream)({ -+ ReactDOMServer: _serverbrowser.default, -+ element: content, -+ streamOptions: { -+ onError: reject -+ } -+ }).then(resolve, reject); - }); - }; - const createBodyResult = (0, _tracer.getTracer)().wrap(_constants2.RenderSpan.createBodyResult, (initialStream, suffix)=>{ diff --git a/patches/next-remote-watch+1.0.0.patch b/patches/next-remote-watch+1.0.0.patch deleted file mode 100644 index c9ecef84d..000000000 --- a/patches/next-remote-watch+1.0.0.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff --git a/node_modules/next-remote-watch/bin/next-remote-watch b/node_modules/next-remote-watch/bin/next-remote-watch -index c055b66..a2f749c 100755 ---- a/node_modules/next-remote-watch/bin/next-remote-watch -+++ b/node_modules/next-remote-watch/bin/next-remote-watch -@@ -66,7 +66,10 @@ app.prepare().then(() => { - } - } - -- app.server.hotReloader.send('reloadPage') -+ app.server.hotReloader.send({ -+ event: 'serverOnlyChanges', -+ pages: ['/[[...markdownPath]]'] -+ }); - } - ) - } diff --git a/public/images/team/andrey-lunyov.jpg b/public/images/team/andrey-lunyov.jpg deleted file mode 100644 index aeaaec06a..000000000 Binary files a/public/images/team/andrey-lunyov.jpg and /dev/null differ diff --git a/public/images/team/hendrik.jpg b/public/images/team/hendrik.jpg new file mode 100644 index 000000000..b39ea5be2 Binary files /dev/null and b/public/images/team/hendrik.jpg differ diff --git a/public/images/team/jordan.jpg b/public/images/team/jordan.jpg new file mode 100644 index 000000000..d8874a29f Binary files /dev/null and b/public/images/team/jordan.jpg differ diff --git a/public/images/team/kathryn-middleton.jpg b/public/images/team/kathryn-middleton.jpg deleted file mode 100644 index 904c3b134..000000000 Binary files a/public/images/team/kathryn-middleton.jpg and /dev/null differ diff --git a/public/images/team/lauren.jpg b/public/images/team/lauren.jpg index 26d46bd2f..a8615aa00 100644 Binary files a/public/images/team/lauren.jpg and b/public/images/team/lauren.jpg differ diff --git a/public/images/team/luna-wei.jpg b/public/images/team/luna-wei.jpg deleted file mode 100644 index cdc4a2b6a..000000000 Binary files a/public/images/team/luna-wei.jpg and /dev/null differ diff --git a/public/images/team/mike.jpg b/public/images/team/mike.jpg new file mode 100644 index 000000000..39fe23fea Binary files /dev/null and b/public/images/team/mike.jpg differ diff --git a/public/images/team/noahlemen.jpg b/public/images/team/noahlemen.jpg deleted file mode 100644 index e3f788d89..000000000 Binary files a/public/images/team/noahlemen.jpg and /dev/null differ diff --git a/public/images/team/pieter.jpg b/public/images/team/pieter.jpg new file mode 100644 index 000000000..d098e5abe Binary files /dev/null and b/public/images/team/pieter.jpg differ diff --git a/public/images/team/sam.jpg b/public/images/team/sam.jpg deleted file mode 100644 index f73474b91..000000000 Binary files a/public/images/team/sam.jpg and /dev/null differ diff --git a/public/images/team/sathya.jpg b/public/images/team/sathya.jpg deleted file mode 100644 index 0f087f4a3..000000000 Binary files a/public/images/team/sathya.jpg and /dev/null differ diff --git a/public/images/team/tianyu.jpg b/public/images/team/tianyu.jpg deleted file mode 100644 index aeb6ed9fa..000000000 Binary files a/public/images/team/tianyu.jpg and /dev/null differ diff --git a/src/components/ExternalLink.tsx b/src/components/ExternalLink.tsx index 38b1f2c5f..13fe6d3a9 100644 --- a/src/components/ExternalLink.tsx +++ b/src/components/ExternalLink.tsx @@ -1,13 +1,17 @@ /* * Copyright (c) Facebook, Inc. and its affiliates. */ +import type {DetailedHTMLProps, AnchorHTMLAttributes} from 'react'; export function ExternalLink({ href, target, children, ...props -}: JSX.IntrinsicElements['a']) { +}: DetailedHTMLProps< + AnchorHTMLAttributes, + HTMLAnchorElement +>) { return ( {children} diff --git a/src/components/Icon/IconArrow.tsx b/src/components/Icon/IconArrow.tsx index 714cccd82..61e4e52cd 100644 --- a/src/components/Icon/IconArrow.tsx +++ b/src/components/Icon/IconArrow.tsx @@ -4,9 +4,10 @@ import {memo} from 'react'; import cn from 'classnames'; +import type {SVGProps} from 'react'; export const IconArrow = memo< - JSX.IntrinsicElements['svg'] & { + SVGProps & { /** * The direction the arrow should point. * `start` and `end` are relative to the current locale. diff --git a/src/components/Icon/IconArrowSmall.tsx b/src/components/Icon/IconArrowSmall.tsx index 6653dc387..4a3d3ad02 100644 --- a/src/components/Icon/IconArrowSmall.tsx +++ b/src/components/Icon/IconArrowSmall.tsx @@ -4,9 +4,10 @@ import {memo} from 'react'; import cn from 'classnames'; +import type {SVGProps} from 'react'; export const IconArrowSmall = memo< - JSX.IntrinsicElements['svg'] & { + SVGProps & { /** * The direction the arrow should point. * `start` and `end` are relative to the current locale. diff --git a/src/components/Icon/IconBsky.tsx b/src/components/Icon/IconBsky.tsx index 6645152dd..5d461556f 100644 --- a/src/components/Icon/IconBsky.tsx +++ b/src/components/Icon/IconBsky.tsx @@ -3,10 +3,9 @@ */ import {memo} from 'react'; +import type {SVGProps} from 'react'; -export const IconBsky = memo(function IconBsky( - props -) { +export const IconBsky = memo>(function IconBsky(props) { return ( (function IconClose( +export const IconClose = memo>(function IconClose( props ) { return ( diff --git a/src/components/Icon/IconFacebookCircle.tsx b/src/components/Icon/IconFacebookCircle.tsx index 0900d6815..7f1080afa 100644 --- a/src/components/Icon/IconFacebookCircle.tsx +++ b/src/components/Icon/IconFacebookCircle.tsx @@ -3,8 +3,9 @@ */ import {memo} from 'react'; +import type {SVGProps} from 'react'; -export const IconFacebookCircle = memo( +export const IconFacebookCircle = memo>( function IconFacebookCircle(props) { return ( ( - function IconGitHub(props) { - return ( - - - - ); - } -); +export const IconGitHub = memo>(function IconGitHub( + props +) { + return ( + + + + ); +}); diff --git a/src/components/Icon/IconHamburger.tsx b/src/components/Icon/IconHamburger.tsx index 5e6aa725a..8bc90ee0c 100644 --- a/src/components/Icon/IconHamburger.tsx +++ b/src/components/Icon/IconHamburger.tsx @@ -3,8 +3,9 @@ */ import {memo} from 'react'; +import type {SVGProps} from 'react'; -export const IconHamburger = memo( +export const IconHamburger = memo>( function IconHamburger(props) { return ( ( +export const IconInstagram = memo>( function IconInstagram(props) { return ( (function IconLink( - props -) { +export const IconLink = memo>(function IconLink(props) { return ( ( - function IconNewPage(props) { - return ( - - - - - ); - } -); +export const IconNewPage = memo>(function IconNewPage( + props +) { + return ( + + + + + ); +}); diff --git a/src/components/Icon/IconRss.tsx b/src/components/Icon/IconRss.tsx index f2a52ee25..6208236f4 100644 --- a/src/components/Icon/IconRss.tsx +++ b/src/components/Icon/IconRss.tsx @@ -3,10 +3,9 @@ */ import {memo} from 'react'; +import type {SVGProps} from 'react'; -export const IconRss = memo(function IconRss( - props -) { +export const IconRss = memo>(function IconRss(props) { return ( ( - function IconSearch(props) { - return ( - - - - ); - } -); +export const IconSearch = memo>(function IconSearch( + props +) { + return ( + + + + ); +}); diff --git a/src/components/Icon/IconThreads.tsx b/src/components/Icon/IconThreads.tsx index 5a007657f..9ea0bafdf 100644 --- a/src/components/Icon/IconThreads.tsx +++ b/src/components/Icon/IconThreads.tsx @@ -3,22 +3,23 @@ */ import {memo} from 'react'; +import type {SVGProps} from 'react'; -export const IconThreads = memo( - function IconThreads(props) { - return ( - - - - ); - } -); +export const IconThreads = memo>(function IconThreads( + props +) { + return ( + + + + ); +}); diff --git a/src/components/Icon/IconTwitter.tsx b/src/components/Icon/IconTwitter.tsx index e7b0cf09e..e84971f4e 100644 --- a/src/components/Icon/IconTwitter.tsx +++ b/src/components/Icon/IconTwitter.tsx @@ -3,20 +3,21 @@ */ import {memo} from 'react'; +import type {SVGProps} from 'react'; -export const IconTwitter = memo( - function IconTwitter(props) { - return ( - - - - - ); - } -); +export const IconTwitter = memo>(function IconTwitter( + props +) { + return ( + + + + + ); +}); diff --git a/src/components/Layout/Sidebar/SidebarRouteTree.tsx b/src/components/Layout/Sidebar/SidebarRouteTree.tsx index 54f02b925..72003df74 100644 --- a/src/components/Layout/Sidebar/SidebarRouteTree.tsx +++ b/src/components/Layout/Sidebar/SidebarRouteTree.tsx @@ -38,6 +38,7 @@ function CollapseWrapper({ // Disable pointer events while animating. const isExpandedRef = useRef(isExpanded); if (typeof window !== 'undefined') { + // eslint-disable-next-line react-compiler/react-compiler // eslint-disable-next-line react-hooks/rules-of-hooks useLayoutEffect(() => { const wasExpanded = isExpandedRef.current; diff --git a/src/components/Logo.tsx b/src/components/Logo.tsx index 07e72c992..8c4f7da4f 100644 --- a/src/components/Logo.tsx +++ b/src/components/Logo.tsx @@ -1,8 +1,9 @@ /* * Copyright (c) Facebook, Inc. and its affiliates. */ +import type {SVGProps} from 'react'; -export function Logo(props: JSX.IntrinsicElements['svg']) { +export function Logo(props: SVGProps) { return ( = {}; let content: React.ReactElement[] = []; Children.forEach(children, (child) => { - const {props, type} = child; + const {props, type} = child as React.ReactElement<{ + children?: string; + id?: string; + }>; switch ((type as any).mdxName) { case 'Solution': { challenge.solution = child; diff --git a/src/components/MDX/CodeBlock/CodeBlock.tsx b/src/components/MDX/CodeBlock/CodeBlock.tsx index 7eef0abe8..42165c57d 100644 --- a/src/components/MDX/CodeBlock/CodeBlock.tsx +++ b/src/components/MDX/CodeBlock/CodeBlock.tsx @@ -289,7 +289,7 @@ function getSyntaxHighlight(theme: any): HighlightStyle { function getLineDecorators( code: string, - meta: string + meta?: string ): Array<{ line: number; className: string; @@ -309,7 +309,7 @@ function getLineDecorators( function getInlineDecorators( code: string, - meta: string + meta?: string ): Array<{ step: number; line: number; @@ -336,6 +336,7 @@ function getInlineDecorators( line.step === 3, 'bg-green-40 border-green-40 text-green-60 dark:text-green-30': line.step === 4, + // TODO: Some codeblocks use up to 6 steps. } ), }) diff --git a/src/components/MDX/CodeDiagram.tsx b/src/components/MDX/CodeDiagram.tsx index 7a503f068..2a198fc56 100644 --- a/src/components/MDX/CodeDiagram.tsx +++ b/src/components/MDX/CodeDiagram.tsx @@ -17,7 +17,14 @@ export function CodeDiagram({children, flip = false}: CodeDiagramProps) { }); const content = Children.toArray(children).map((child: any) => { if (child.type?.mdxName === 'pre') { - return ; + return ( + + ); } else if (child.type === 'img') { return null; } else { diff --git a/src/components/MDX/ConsoleBlock.tsx b/src/components/MDX/ConsoleBlock.tsx index 6e704b417..6044b1370 100644 --- a/src/components/MDX/ConsoleBlock.tsx +++ b/src/components/MDX/ConsoleBlock.tsx @@ -38,7 +38,8 @@ export function ConsoleBlock({level = 'error', children}: ConsoleBlockProps) { if (typeof children === 'string') { message = children; } else if (isValidElement(children)) { - message = children.props.children; + message = (children as React.ReactElement<{children?: React.ReactNode}>) + .props.children; } return ( @@ -113,7 +114,8 @@ export function ConsoleLogLine({children, level}: ConsoleBlockProps) { if (typeof children === 'string') { message = children; } else if (isValidElement(children)) { - message = children.props.children; + message = (children as React.ReactElement<{children?: React.ReactNode}>) + .props.children; } else if (Array.isArray(children)) { message = children.reduce((result, child) => { if (typeof child === 'string') { diff --git a/src/components/MDX/ErrorDecoder.tsx b/src/components/MDX/ErrorDecoder.tsx index 198aa939d..b04fa9f79 100644 --- a/src/components/MDX/ErrorDecoder.tsx +++ b/src/components/MDX/ErrorDecoder.tsx @@ -11,7 +11,7 @@ function replaceArgs( return msg.replace(/%s/g, function () { const arg = argList[argIdx++]; // arg can be an empty string: ?args[0]=&args[1]=count - return arg === undefined || arg === '' ? replacer : arg; + return arg === undefined ? replacer : arg; }); } diff --git a/src/components/MDX/InlineCode.tsx b/src/components/MDX/InlineCode.tsx index 0e8db0165..5759a7c0a 100644 --- a/src/components/MDX/InlineCode.tsx +++ b/src/components/MDX/InlineCode.tsx @@ -3,6 +3,7 @@ */ import cn from 'classnames'; +import type {HTMLAttributes} from 'react'; interface InlineCodeProps { isLink?: boolean; @@ -11,7 +12,7 @@ interface InlineCodeProps { function InlineCode({ isLink, ...props -}: JSX.IntrinsicElements['code'] & InlineCodeProps) { +}: HTMLAttributes & InlineCodeProps) { return ( in case of RTL languages to avoid like `()console.log` to be rendered as `console.log()` diff --git a/src/components/MDX/MDXComponents.tsx b/src/components/MDX/MDXComponents.tsx index d00b9b33e..fffa4637a 100644 --- a/src/components/MDX/MDXComponents.tsx +++ b/src/components/MDX/MDXComponents.tsx @@ -5,6 +5,7 @@ import {Children, useContext, useMemo} from 'react'; import * as React from 'react'; import cn from 'classnames'; +import type {HTMLAttributes} from 'react'; import CodeBlock from './CodeBlock'; import {CodeDiagram} from './CodeDiagram'; @@ -59,21 +60,21 @@ function CodeStep({children, step}: {children: any; step: number}) { ); } -const P = (p: JSX.IntrinsicElements['p']) => ( +const P = (p: HTMLAttributes) => (

); -const Strong = (strong: JSX.IntrinsicElements['strong']) => ( +const Strong = (strong: HTMLAttributes) => ( ); -const OL = (p: JSX.IntrinsicElements['ol']) => ( +const OL = (p: HTMLAttributes) => (

    ); -const LI = (p: JSX.IntrinsicElements['li']) => ( +const LI = (p: HTMLAttributes) => (
  1. ); -const UL = (p: JSX.IntrinsicElements['ul']) => ( +const UL = (p: HTMLAttributes) => (
      ); @@ -139,10 +140,7 @@ const RSCBadge = ({title}: {title: string}) => ( ); -const Blockquote = ({ - children, - ...props -}: JSX.IntrinsicElements['blockquote']) => { +const Blockquote = ({children, ...props}: HTMLAttributes) => { return (
      ({}); if (!lineCountRef.current[activeFile]) { + // eslint-disable-next-line react-compiler/react-compiler lineCountRef.current[activeFile] = code.split('\n').length; } const lineCount = lineCountRef.current[activeFile]; diff --git a/src/components/MDX/Sandpack/LoadingOverlay.tsx b/src/components/MDX/Sandpack/LoadingOverlay.tsx index cd3f38fca..de883629c 100644 --- a/src/components/MDX/Sandpack/LoadingOverlay.tsx +++ b/src/components/MDX/Sandpack/LoadingOverlay.tsx @@ -17,7 +17,7 @@ export const LoadingOverlay = ({ clientId: string; dependenciesLoading: boolean; forceLoading: boolean; -} & React.HTMLAttributes): JSX.Element | null => { +} & React.HTMLAttributes): React.ReactNode | null => { const loadingOverlayState = useLoadingOverlayState( clientId, dependenciesLoading, @@ -64,6 +64,7 @@ export const LoadingOverlay = ({ transition: `opacity ${FADE_ANIMATION_DURATION}ms ease-out`, }}>
      + {/* @ts-ignore: the OpenInCodeSandboxButton type from '@codesandbox/sandpack-react/unstyled' is incompatible with JSX in React 19 */}
      diff --git a/src/components/MDX/Sandpack/NavigationBar.tsx b/src/components/MDX/Sandpack/NavigationBar.tsx index 26ed5783d..bf2c3186c 100644 --- a/src/components/MDX/Sandpack/NavigationBar.tsx +++ b/src/components/MDX/Sandpack/NavigationBar.tsx @@ -115,7 +115,10 @@ export function NavigationBar({providedFiles}: {providedFiles: Array}) { return (
      + {/* If Prettier reformats this block, the two @ts-ignore directives will no longer be adjacent to the problematic lines, causing TypeScript errors */} + {/* prettier-ignore */}
      + {/* @ts-ignore: the Listbox type from '@headlessui/react' is incompatible with JSX in React 19 */}
      @@ -129,8 +132,10 @@ export function NavigationBar({providedFiles}: {providedFiles: Array}) { 'w-[fit-content]', showDropdown ? 'invisible' : '' )}> + {/* @ts-ignore: the FileTabs type from '@codesandbox/sandpack-react/unstyled' is incompatible with JSX in React 19 */}
      + {/* @ts-ignore: the Listbox type from '@headlessui/react' is incompatible with JSX in React 19 */} {({open}) => ( // If tabs don't fit, display the dropdown instead. @@ -160,10 +165,10 @@ export function NavigationBar({providedFiles}: {providedFiles: Array}) {
      - {isMultiFile && showDropdown && ( - - {visibleFiles.map((filePath: string) => ( - + {/* @ts-ignore: the Listbox type from '@headlessui/react' is incompatible with JSX in React 19 */} + {isMultiFile && showDropdown && ( + {/* @ts-ignore: the Listbox type from '@headlessui/react' is incompatible with JSX in React 19 */} + {visibleFiles.map((filePath: string) => ( {({active}) => (
    • { ) { return result; } - const {props} = codeSnippet.props.children; + const {props} = ( + codeSnippet.props as PropsWithChildren<{ + children: ReactElement< + HTMLAttributes & {meta?: string} + >; + }> + ).children; let filePath; // path in the folder structure let fileHidden = false; // if the file is available as a tab let fileActive = false; // if the file tab is shown by default diff --git a/src/components/MDX/TeamMember.tsx b/src/components/MDX/TeamMember.tsx index e1b9198d8..2c2fffa73 100644 --- a/src/components/MDX/TeamMember.tsx +++ b/src/components/MDX/TeamMember.tsx @@ -3,7 +3,7 @@ */ import * as React from 'react'; -import Image from 'next/image'; +import Image from 'next/legacy/image'; import {IconTwitter} from '../Icon/IconTwitter'; import {IconThreads} from '../Icon/IconThreads'; import {IconBsky} from '../Icon/IconBsky'; @@ -39,11 +39,9 @@ export function TeamMember({ personal, }: TeamMemberProps) { if (name == null || title == null || permalink == null || children == null) { + const identifier = name ?? title ?? permalink ?? 'unknown'; throw new Error( - 'Expected name, title, permalink, and children for ' + name ?? - title ?? - permalink ?? - 'unknown' + `Expected name, title, permalink, and children for ${identifier}` ); } return ( diff --git a/src/components/MDX/TerminalBlock.tsx b/src/components/MDX/TerminalBlock.tsx index fc13af338..475292716 100644 --- a/src/components/MDX/TerminalBlock.tsx +++ b/src/components/MDX/TerminalBlock.tsx @@ -31,9 +31,11 @@ function TerminalBlock({level = 'info', children}: TerminalBlockProps) { message = children; } else if ( isValidElement(children) && - typeof children.props.children === 'string' + typeof (children as React.ReactElement<{children: string}>).props + .children === 'string' ) { - message = children.props.children; + message = (children as React.ReactElement<{children: string}>).props + .children; } else { throw Error('Expected TerminalBlock children to be a plain string.'); } @@ -71,7 +73,7 @@ function TerminalBlock({level = 'info', children}: TerminalBlockProps) {
    • diff --git a/src/components/Search.tsx b/src/components/Search.tsx index f5c963f67..c7401487b 100644 --- a/src/components/Search.tsx +++ b/src/components/Search.tsx @@ -9,6 +9,8 @@ import {lazy, useEffect} from 'react'; import * as React from 'react'; import {createPortal} from 'react-dom'; import {siteConfig} from 'siteConfig'; +import type {ComponentType, PropsWithChildren} from 'react'; +import type {DocSearchModalProps} from '@docsearch/react/modal'; export interface SearchProps { appId?: string; @@ -83,9 +85,10 @@ const options = { }; const DocSearchModal: any = lazy(() => - // @ts-ignore import('@docsearch/react/modal').then((mod) => ({ - default: mod.DocSearchModal, + default: mod.DocSearchModal as ComponentType< + PropsWithChildren + >, })) ); diff --git a/src/content/blog/2020/12/21/data-fetching-with-react-server-components.md b/src/content/blog/2020/12/21/data-fetching-with-react-server-components.md index e6a55fbb3..7d99f5ecc 100644 --- a/src/content/blog/2020/12/21/data-fetching-with-react-server-components.md +++ b/src/content/blog/2020/12/21/data-fetching-with-react-server-components.md @@ -5,7 +5,7 @@ date: 2020/12/21 description: 2020 年は長い 1 年でした。本年の最後に、我々の研究における特別なホリデーアップデートとして、バンドルサイズゼロで動作する React サーバコンポーネントの紹介をしたいと思います。 --- -December 21, 2020 by [Dan Abramov](https://twitter.com/dan_abramov), [Lauren Tan](https://twitter.com/potetotes), [Joseph Savona](https://twitter.com/en_JS), and [Sebastian Markbåge](https://twitter.com/sebmarkbage) +December 21, 2020 by [Dan Abramov](https://bsky.app/profile/danabra.mov), [Lauren Tan](https://twitter.com/potetotes), [Joseph Savona](https://twitter.com/en_JS), and [Sebastian Markbåge](https://twitter.com/sebmarkbage) --- diff --git a/src/content/blog/2021/06/08/the-plan-for-react-18.md b/src/content/blog/2021/06/08/the-plan-for-react-18.md index 431033436..9e8a2d928 100644 --- a/src/content/blog/2021/06/08/the-plan-for-react-18.md +++ b/src/content/blog/2021/06/08/the-plan-for-react-18.md @@ -5,7 +5,7 @@ date: 2021/06/08 description: React チームより幾つかのお知らせがあります! 次のメジャーバージョンとなる React 18 リリースに向けての作業を開始しました。コミュニティが React 18 の新機能を段階的に導入できるようにするため、ワーキンググループを作成しました。ライブラリの作者が試用してフィードバックを送れるようにするため、React 18 のアルファ版を公開しました。 --- -June 8, 2021 by [Andrew Clark](https://twitter.com/acdlite), [Brian Vaughn](https://github.com/bvaughn), [Christine Abernathy](https://twitter.com/abernathyca), [Dan Abramov](https://twitter.com/dan_abramov), [Rachel Nabors](https://twitter.com/rachelnabors), [Rick Hanlon](https://twitter.com/rickhanlonii), [Sebastian Markbåge](https://twitter.com/sebmarkbage), and [Seth Webster](https://twitter.com/sethwebster) +June 8, 2021 by [Andrew Clark](https://twitter.com/acdlite), [Brian Vaughn](https://github.com/bvaughn), [Christine Abernathy](https://twitter.com/abernathyca), [Dan Abramov](https://bsky.app/profile/danabra.mov), [Rachel Nabors](https://twitter.com/rachelnabors), [Rick Hanlon](https://twitter.com/rickhanlonii), [Sebastian Markbåge](https://twitter.com/sebmarkbage), and [Seth Webster](https://twitter.com/sethwebster) --- diff --git a/src/content/blog/2021/12/17/react-conf-2021-recap.md b/src/content/blog/2021/12/17/react-conf-2021-recap.md index d4ce4a1cb..1607c0f4b 100644 --- a/src/content/blog/2021/12/17/react-conf-2021-recap.md +++ b/src/content/blog/2021/12/17/react-conf-2021-recap.md @@ -131,7 +131,7 @@ React の学習や React による設計についての一連の発表は [Rache まずは発表者の方々に感謝します。[Aakansha Doshi](https://twitter.com/aakansha1216)、[Andrew Clark](https://twitter.com/acdlite)、[Brian Vaughn](https://twitter.com/brian_d_vaughn)、[Daishi Kato](https://twitter.com/dai_shi)、[Debbie O'Brien](https://twitter.com/debs_obrien)、[Delba de Oliveira](https://twitter.com/delba_oliveira)、[Diego Haz](https://twitter.com/diegohaz)、[Eric Rozell](https://twitter.com/EricRozell)、[Helen Lin](https://twitter.com/wizardlyhel)、[Juan Tejada](https://twitter.com/_jstejada)、[Lauren Tan](https://twitter.com/potetotes)、[Linton Ye](https://twitter.com/lintonye)、[Lyle Troxell](https://twitter.com/lyle)、[Rachel Nabors](https://twitter.com/rachelnabors)、[Rick Hanlon](https://twitter.com/rickhanlonii)、[Robert Balicki](https://twitter.com/StatisticsFTW)、[Roman Rädle](https://twitter.com/raedle)、[Sarah Rainsberger](https://twitter.com/sarah11918)、[Shaundai Person](https://twitter.com/shaundai)、[Shruti Kapoor](https://twitter.com/shrutikapoor08)、[Steven Moyes](https://twitter.com/moyessa)、[Tafu Nakazaki](https://twitter.com/hawaiiman0)、[Xuan Huang (黄玄)](https://twitter.com/Huxpro)。 -発表についてのフィードバックを頂いた方々に感謝します。[Andrew Clark](https://twitter.com/acdlite)、[Dan Abramov](https://twitter.com/dan_abramov)、[Dave McCabe](https://twitter.com/mcc_abe)、[Eli White](https://twitter.com/Eli_White)、[Joe Savona](https://twitter.com/en_JS)、[Lauren Tan](https://twitter.com/potetotes)、[Rachel Nabors](https://twitter.com/rachelnabors)、[Tim Yung](https://twitter.com/yungsters)。 +発表についてのフィードバックを頂いた方々に感謝します。[Andrew Clark](https://twitter.com/acdlite)、[Dan Abramov](https://bsky.app/profile/danabra.mov)、[Dave McCabe](https://twitter.com/mcc_abe)、[Eli White](https://twitter.com/Eli_White)、[Joe Savona](https://twitter.com/en_JS)、[Lauren Tan](https://twitter.com/potetotes)、[Rachel Nabors](https://twitter.com/rachelnabors)、[Tim Yung](https://twitter.com/yungsters)。 カンファレンス Discord のセットアップを行い Discord 管理者になっていただいた [Lauren Tan](https://twitter.com/potetotes) に感謝します。 diff --git a/src/content/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.md b/src/content/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.md index c71d4e9f8..2ed270aba 100644 --- a/src/content/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.md +++ b/src/content/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.md @@ -5,7 +5,7 @@ date: 2022/06/15 description: React 18 の完成は数年がかりの仕事であり、React チームはそこから貴重な教訓を得ることになりました。このリリースは何年も研究を行い、様々なアプローチを試した結果として生まれたものです。いくつかのアプローチはうまく行った一方で、多くは行き詰まって新たな知見のみをもたらすことになりました。ここから我々が学んだことは、我々がどんなことを試しているのかをコミュニティに知らせることなくただお待たせするというのは、フラストレーションの元だ、ということです。 --- -June 15, 2022 by [Andrew Clark](https://twitter.com/acdlite), [Dan Abramov](https://twitter.com/dan_abramov), [Jan Kassens](https://twitter.com/kassens), [Joseph Savona](https://twitter.com/en_JS), [Josh Story](https://twitter.com/joshcstory), [Lauren Tan](https://twitter.com/potetotes), [Luna Ruan](https://twitter.com/lunaruan), [Mengdi Chen](https://twitter.com/mengdi_en), [Rick Hanlon](https://twitter.com/rickhanlonii), [Robert Zhang](https://twitter.com/jiaxuanzhang01), [Sathya Gunasekaran](https://twitter.com/_gsathya), [Sebastian Markbåge](https://twitter.com/sebmarkbage), and [Xuan Huang](https://twitter.com/Huxpro) +June 15, 2022 by [Andrew Clark](https://twitter.com/acdlite), [Dan Abramov](https://bsky.app/profile/danabra.mov), [Jan Kassens](https://twitter.com/kassens), [Joseph Savona](https://twitter.com/en_JS), [Josh Story](https://twitter.com/joshcstory), [Lauren Tan](https://twitter.com/potetotes), [Luna Ruan](https://twitter.com/lunaruan), [Mengdi Chen](https://twitter.com/mengdi_en), [Rick Hanlon](https://twitter.com/rickhanlonii), [Robert Zhang](https://twitter.com/jiaxuanzhang01), [Sathya Gunasekaran](https://twitter.com/_gsathya), [Sebastian Markbåge](https://twitter.com/sebmarkbage), and [Xuan Huang](https://twitter.com/Huxpro) --- @@ -27,7 +27,7 @@ June 15, 2022 by [Andrew Clark](https://twitter.com/acdlite), [Dan Abramov](http 特に、I/O ライブラリをフォークして例えば react-fetch のようなものを作成していく、というアイディアは捨て去ることにし、代わりに互換性のために async/await モデルを採用することにします。データフェッチングにはルータを使うこともできるのでこれにより RSC のリリースが遅れるということはありません。もうひとつの変更は、ファイルの拡張子でサーバコンポーネントかどうかを区別するというアプローチをやめ、[区別を注釈で行う](https://github.com/reactjs/rfcs/pull/189#issuecomment-1116482278)ことにする、というものです。 -Webpack と Vite の両方で振る舞いが同じになるようバンドラのサポートを共通化することについて、Vercel および Shopify とともに取り組んでいます。リリース前に、React のエコシステム全体で RSC の振る舞いが同じになるようにしたいと考えています。この部分が安定化前の最大の障壁となっています。 +webpack と Vite の両方で振る舞いが同じになるようバンドラのサポートを共通化することについて、Vercel および Shopify とともに取り組んでいます。リリース前に、React のエコシステム全体で RSC の振る舞いが同じになるようにしたいと考えています。この部分が安定化前の最大の障壁となっています。 ## アセットのロード {/*asset-loading*/} diff --git a/src/content/blog/2023/03/16/introducing-react-dev.md b/src/content/blog/2023/03/16/introducing-react-dev.md index 804dd19f1..a7969a0ed 100644 --- a/src/content/blog/2023/03/16/introducing-react-dev.md +++ b/src/content/blog/2023/03/16/introducing-react-dev.md @@ -5,7 +5,7 @@ date: 2023/03/16 description: 本日、React とそのドキュメントの新しいホームとなる react.dev の立ち上げを発表することができ、大変うれしく思います。この記事では、新しいサイトの見どころをご紹介します。 --- -March 16, 2023 by [Dan Abramov](https://twitter.com/dan_abramov) and [Rachel Nabors](https://twitter.com/rachelnabors) +March 16, 2023 by [Dan Abramov](https://bsky.app/profile/danabra.mov) and [Rachel Nabors](https://twitter.com/rachelnabors) --- @@ -631,7 +631,7 @@ React を学ぶには、今がこれまでで最高のタイミングだと思 ## 誰がこのプロジェクトに取り組んだのか? {/*who-worked-on-this*/} -React チームでは、[Rachel Nabors](https://twitter.com/rachelnabors/) がプロジェクトをリードし(イラストも提供)、[Dan Abramov](https://twitter.com/dan_abramov) がカリキュラムをデザインしました。この 2 人が共同でほとんどのコンテンツを執筆しました。 +React チームでは、[Rachel Nabors](https://twitter.com/rachelnabors/) がプロジェクトをリードし(イラストも提供)、[Dan Abramov](https://bsky.app/profile/danabra.mov) がカリキュラムをデザインしました。この 2 人が共同でほとんどのコンテンツを執筆しました。 もちろん、これほど大きなプロジェクトが少人数で進むことはありません。お礼を言いたい方がたくさんいます! diff --git a/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md b/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md index 73d3db3f3..70e71ffd1 100644 --- a/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md +++ b/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md @@ -97,9 +97,9 @@ Transition Tracing API により、[React のトランジション](/reference/r * * * このページでのアップデートに加えて、私たちのチームは最近、コミュニティのポッドキャストやライブストリームにゲスト出演し、取り組みについてより多くのことをお話しし、質問に答える機会がありました。 -* [Dan Abramov](https://twitter.com/dan_abramov) と [Joe Savona](https://twitter.com/en_JS) は [Kent C. Dodds の YouTube チャンネル](https://www.youtube.com/watch?v=h7tur48JSaw) でインタビューを受け、React Server Components に関する懸念について議論を行いました。 -* [Dan Abramov](https://twitter.com/dan_abramov) と [Joe Savona](https://twitter.com/en_JS) は [JSParty ポッドキャスト](https://jsparty.fm/267) のゲストとして招かれ、React の未来についての考えを共有しました。 +* [Dan Abramov](https://bsky.app/profile/danabra.mov) と [Joe Savona](https://twitter.com/en_JS) は [Kent C. Dodds の YouTube チャンネル](https://www.youtube.com/watch?v=h7tur48JSaw) でインタビューを受け、React Server Components に関する懸念について議論を行いました。 +* [Dan Abramov](https://bsky.app/profile/danabra.mov) と [Joe Savona](https://twitter.com/en_JS) は [JSParty ポッドキャスト](https://jsparty.fm/267) のゲストとして招かれ、React の未来についての考えを共有しました。 -この投稿のレビューに協力していただいた [Andrew Clark](https://twitter.com/acdlite)、[Dan Abramov](https://twitter.com/dan_abramov)、[Dave McCabe](https://twitter.com/mcc_abe)、[Luna Wei](https://twitter.com/lunaleaps)、[Matt Carroll](https://twitter.com/mattcarrollcode)、[Sean Keegan](https://twitter.com/DevRelSean)、[Sebastian Silbermann](https://twitter.com/sebsilbermann)、[Seth Webster](https://twitter.com/sethwebster)、[Sophie Alpert](https://twitter.com/sophiebits) に感謝します。 +この投稿のレビューに協力していただいた [Andrew Clark](https://twitter.com/acdlite)、[Dan Abramov](https://bsky.app/profile/danabra.mov)、[Dave McCabe](https://twitter.com/mcc_abe)、[Luna Wei](https://twitter.com/lunaleaps)、[Matt Carroll](https://twitter.com/mattcarrollcode)、[Sean Keegan](https://twitter.com/DevRelSean)、[Sebastian Silbermann](https://twitter.com/sebsilbermann)、[Seth Webster](https://twitter.com/sethwebster)、[Sophie Alpert](https://twitter.com/sophiebits) に感謝します。 お読みいただきありがとうございました。次のアップデートでお会いしましょう! diff --git a/src/content/blog/2023/05/03/react-canaries.md b/src/content/blog/2023/05/03/react-canaries.md index 6d9242022..ab068d91f 100644 --- a/src/content/blog/2023/05/03/react-canaries.md +++ b/src/content/blog/2023/05/03/react-canaries.md @@ -5,7 +5,7 @@ date: 2023/05/03 description: 私たちは、安定版がリリースされる前に、個々の新機能の設計がほぼ確定した段階でそれらを採用できるという選択肢を、React コミュニティに提供したいと考えています。これは、Meta が長年、React の最先端バージョンを社内で使用してきたやり方に似ています。私たちは、新たに公式サポート対象となる Canary リリースチャンネルを導入します。これにより、フレームワークのような統合済セットアップが、個々の React 機能の採用を React のリリーススケジュールから切り離して行えるようになります。 --- -May 3, 2023 by [Dan Abramov](https://twitter.com/dan_abramov), [Sophie Alpert](https://twitter.com/sophiebits), [Rick Hanlon](https://twitter.com/rickhanlonii), [Sebastian Markbåge](https://twitter.com/sebmarkbage), and [Andrew Clark](https://twitter.com/acdlite) +May 3, 2023 by [Dan Abramov](https://bsky.app/profile/danabra.mov), [Sophie Alpert](https://twitter.com/sophiebits), [Rick Hanlon](https://twitter.com/rickhanlonii), [Sebastian Markbåge](https://twitter.com/sebmarkbage), and [Andrew Clark](https://twitter.com/acdlite) --- diff --git a/src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md b/src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md index bf2f882d6..b95c82e4d 100644 --- a/src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md +++ b/src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md @@ -5,7 +5,7 @@ date: 2024/02/15 description: React Labs 記事では、現在活発に研究・開発が行われているプロジェクトについて述べていきます。前回のアップデートから大きな進展がありましたので、我々が学んだことを共有していきます。 --- -February 15, 2024 by [Joseph Savona](https://twitter.com/en_JS), [Ricky Hanlon](https://twitter.com/rickhanlonii), [Andrew Clark](https://twitter.com/acdlite), [Matt Carroll](https://twitter.com/mattcarrollcode), and [Dan Abramov](https://twitter.com/dan_abramov). +February 15, 2024 by [Joseph Savona](https://twitter.com/en_JS), [Ricky Hanlon](https://twitter.com/rickhanlonii), [Andrew Clark](https://twitter.com/acdlite), [Matt Carroll](https://twitter.com/mattcarrollcode), and [Dan Abramov](https://bsky.app/profile/danabra.mov). --- diff --git a/src/content/blog/2024/04/25/react-19-upgrade-guide.md b/src/content/blog/2024/04/25/react-19-upgrade-guide.md index 6d2c92abb..bf68baeab 100644 --- a/src/content/blog/2024/04/25/react-19-upgrade-guide.md +++ b/src/content/blog/2024/04/25/react-19-upgrade-guide.md @@ -24,7 +24,7 @@ React 19 へのアップグレードを容易にするため、`react@18.3` リ React 19 にアップグレードする前に、問題点を見つけるためにまず React 18.3 にアップグレードすることをお勧めします。 -18.3 における変更点については、[リリースノート](https://github.com/facebook/react/blob/main/CHANGELOG.md)をご覧ください。 +18.3 における変更点については、[リリースノート](https://github.com/facebook/react/blob/main/CHANGELOG.md#1830-april-25-2024)をご覧ください。 @@ -113,7 +113,7 @@ npx codemod@latest react/19/migration-recipe - [`replace-string-ref`](https://github.com/reactjs/react-codemod?tab=readme-ov-file#replace-string-ref) - [`replace-act-import`](https://github.com/reactjs/react-codemod?tab=readme-ov-file#replace-act-import) - [`replace-use-form-state`](https://github.com/reactjs/react-codemod?tab=readme-ov-file#replace-use-form-state) -- [`prop-types-typescript`](https://codemod.com/registry/react-prop-types-typescript) +- [`prop-types-typescript`](https://github.com/reactjs/react-codemod#react-proptypes-to-prop-types) これには TypeScript 関連の変更は含まれていません。以下の [TypeScript 関連の変更](#typescript-changes)を参照してください。 diff --git a/src/content/blog/2024/05/22/react-conf-2024-recap.md b/src/content/blog/2024/05/22/react-conf-2024-recap.md index edbac1810..538ba0e64 100644 --- a/src/content/blog/2024/05/22/react-conf-2024-recap.md +++ b/src/content/blog/2024/05/22/react-conf-2024-recap.md @@ -42,7 +42,7 @@ _[1 日目の全ストリームはこちらから視聴できます。](https:// - [React Unpacked: A Roadmap to React 19](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=10112s) by [Sam Selikoff](https://twitter.com/samselikoff) - [React 19 Deep Dive: Coordinating HTML](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=24916s) by [Josh Story](https://twitter.com/joshcstory) - [Enhancing Forms with React Server Components](https://www.youtube.com/watch?v=0ckOUBiuxVY&t=25280s) by [Aurora Walberg Scharff](https://twitter.com/aurorascharff) -- [React for Two Computers](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=18825s) by [Dan Abramov](https://twitter.com/dan_abramov2) +- [React for Two Computers](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=18825s) by [Dan Abramov](https://bsky.app/profile/danabra.mov) - [And Now You Understand React Server Components](https://www.youtube.com/watch?v=0ckOUBiuxVY&t=11256s) by [Kent C. Dodds](https://twitter.com/kentcdodds) 基調講演の締めくくりとして、[Joe Savona](https://twitter.com/en_JS)、[Sathya Gunasekaran](https://twitter.com/_gsathya)、[Mofei Zhang](https://twitter.com/zmofei) が、React Compiler が[オープンソース](https://github.com/facebook/react/pull/29061)化されたことを発表し、React Compiler の実験バージョンを共有しました。 diff --git a/src/content/blog/2025/02/14/sunsetting-create-react-app.md b/src/content/blog/2025/02/14/sunsetting-create-react-app.md new file mode 100644 index 000000000..9ced6231c --- /dev/null +++ b/src/content/blog/2025/02/14/sunsetting-create-react-app.md @@ -0,0 +1,320 @@ +--- +title: "Sunsetting Create React App" +author: Matt Carroll and Ricky Hanlon +date: 2025/02/14 +description: Today, we’re deprecating Create React App for new apps, and encouraging existing apps to migrate to a framework, or to migrate to a build tool like Vite, Parcel, or RSBuild. We’re also providing docs for when a framework isn’t a good fit for your project, you want to build your own framework, or you just want to learn how React works by building a React app from scratch. +--- + +February 14, 2025 by [Matt Carroll](https://twitter.com/mattcarrollcode) and [Ricky Hanlon](https://bsky.app/profile/ricky.fm) + +--- + + + +Today, we’re deprecating [Create React App](https://create-react-app.dev/) for new apps, and encouraging existing apps to migrate to a [framework](#how-to-migrate-to-a-framework), or to [migrate to a build tool](#how-to-migrate-to-a-build-tool) like Vite, Parcel, or RSBuild. + +We’re also providing docs for when a framework isn’t a good fit for your project, you want to build your own framework, or you just want to learn how React works by [building a React app from scratch](/learn/build-a-react-app-from-scratch). + + + +----- + +When we released Create React App in 2016, there was no clear way to build a new React app. + +To create a React app, you had to install a bunch of tools and wire them up together yourself to support basic features like JSX, linting, and hot reloading. This was very tricky to do correctly, so the [community](https://github.com/react-boilerplate/react-boilerplate) [created](https://github.com/kriasoft/react-starter-kit) [boilerplates](https://github.com/petehunt/react-boilerplate) for [common](https://github.com/gaearon/react-hot-boilerplate) [setups](https://github.com/erikras/react-redux-universal-hot-example). However, boilerplates were difficult to update and fragmentation made it difficult for React to release new features. + +Create React App solved these problems by combining several tools into a single recommended configuration. This allowed apps a simple way to upgrade to new tooling features, and allowed the React team to deploy non-trivial tooling changes (Fast Refresh support, React Hooks lint rules) to the broadest possible audience. + +This model became so popular that there's an entire category of tools working this way today. + +## Deprecating Create React App {/*deprecating-create-react-app*/} + +Although Create React App makes it easy to get started, [there are several limitations](#limitations-of-build-tools) that make it difficult to build high performant production apps. In principle, we could solve these problems by essentially evolving it into a [framework](#why-we-recommend-frameworks). + +However, since Create React App currently has no active maintainers, and there are many existing frameworks that solve these problems already, we’ve decided to deprecate Create React App. + +Starting today, if you install a new app, you will see a deprecation warning: + + + + +create-react-app is deprecated. +{'\n\n'} +You can find a list of up-to-date React frameworks on react.dev +For more info see: react.dev/link/cra +{'\n\n'} +This error message will only be shown once per install. + + + + +We've also added a deprecation notice to the Create React App [website](https://create-react-app.dev/) and GitHub [repo](https://github.com/facebook/create-react-app). Create React App will continue working in maintenance mode, and we've published a new version of Create React App to work with React 19. + +## How to Migrate to a Framework {/*how-to-migrate-to-a-framework*/} +We recommend [creating new React apps](/learn/creating-a-react-app) with a framework. All the frameworks we recommend support client-side rendering ([CSR](https://developer.mozilla.org/en-US/docs/Glossary/CSR)) and single-page apps ([SPA](https://developer.mozilla.org/en-US/docs/Glossary/SPA)), and can be deployed to a CDN or static hosting service without a server. + +For existing apps, these guides will help you migrate to a client-only SPA: + +* [Next.js’ Create React App migration guide](https://nextjs.org/docs/app/building-your-application/upgrading/from-create-react-app) +* [React Router’s framework adoption guide](https://reactrouter.com/upgrading/component-routes). +* [Expo webpack to Expo Router migration guide](https://docs.expo.dev/router/migrate/from-expo-webpack/) + +## How to Migrate to a Build Tool {/*how-to-migrate-to-a-build-tool*/} + +If your app has unusual constraints, or you prefer to solve these problems by building your own framework, or you just want to learn how react works from scratch, you can roll your own custom setup with React using Vite, Parcel or Rsbuild. + +For existing apps, these guides will help you migrate to a build tool: + +* [Vite Create React App migration guide](https://www.robinwieruch.de/vite-create-react-app/) +* [Parcel Create React App migration guide](https://parceljs.org/migration/cra/) +* [Rsbuild Create React App migration guide](https://rsbuild.dev/guide/migration/cra) + +To help get started with Vite, Parcel or Rsbuild, we've added new docs for [Building a React App from Scratch](/learn/build-a-react-app-from-scratch). + + + +#### Do I need a framework? {/*do-i-need-a-framework*/} + +Most apps would benefit from a framework, but there are valid cases to build a React app from scratch. A good rule of thumb is if your app needs routing, you would probably benefit from a framework. + +Just like Svelte has Sveltekit, Vue has Nuxt, and Solid has SolidStart, [React recommends using a framework](#why-we-recommend-frameworks) that fully integrates routing into features like data-fetching and code-splitting out of the box. This avoids the pain of needing to write your own complex configurations and essentially build a framework yourself. + +However, you can always [build a React app from scratch](/learn/build-a-react-app-from-scratch) using a build tool like Vite, Parcel, or Rsbuild. + + + +Continue reading to learn more about the [limitations of build tools](#limitations-of-build-tools) and [why we recommend frameworks](#why-we-recommend-frameworks). + +## Limitations of Build Tools {/*limitations-of-build-tools*/} + +Create React App and build tools like it make it easy to get started building a React app. After running `npx create-react-app my-app`, you get a fully configured React app with a development server, linting, and a production build. + +For example, if you're building an internal admin tool, you can start with a landing page: + +```js +export default function App() { + return ( +
      +

      Welcome to the Admin Tool!

      +
      + ) +} +``` + +This allows you to immediately start coding in React with features like JSX, default linting rules, and a bundler to run in both development and production. However, this setup is missing the tools you need to build a real production app. + +Most production apps need solutions to problems like routing, data fetching, and code splitting. + +### Routing {/*routing*/} + +Create React App does not include a specific routing solution. If you're just getting started, one option is to use `useState` to switch between routes. But doing this means that you can't share links to your app - every link would go to the same page - and structuring your app becomes difficult over time: + +```js +import {useState} from 'react'; + +import Home from './Home'; +import Dashboard from './Dashboard'; + +export default function App() { + // ❌ Routing in state does not create URLs + const [route, setRoute] = useState('home'); + return ( +
      + {route === 'home' && } + {route === 'dashboard' && } +
      + ) +} +``` + +This is why most apps that use Create React App solve add routing with a routing library like [React Router](https://reactrouter.com/) or [Tanstack Router](https://tanstack.com/router/latest). With a routing library, you can add additional routes to the app, which provides opinions on the structure of your app, and allows you to start sharing links to routes. For example, with React Router you can define routes: + +```js +import {RouterProvider, createBrowserRouter} from 'react-router'; + +import Home from './Home'; +import Dashboard from './Dashboard'; + +// ✅ Each route has it's own URL +const router = createBrowserRouter([ + {path: '/', element: }, + {path: '/dashboard', element: } +]); + +export default function App() { + return ( + + ) +} +``` + +With this change, you can share a link to `/dashboard` and the app will navigate to the dashboard page . Once you have a routing library, you can add additional features like nested routes, route guards, and route transitions, which are difficult to implement without a routing library. + +There's a tradeoff being made here: the routing library adds complexity to the app, but it also adds features that are difficult to implement without it. + +### Data Fetching {/*data-fetching*/} + +Another common problem in Create React App is data fetching. Create React App does not include a specific data fetching solution. If you're just getting started, a common option is to use `fetch` in an effect to load data. + +But doing this means that the data is fetched after the component renders, which can cause network waterfalls. Network waterfalls are caused by fetching data when your app renders instead of in parallel while the code is downloading: + +```js +export default function Dashboard() { + const [data, setData] = useState(null); + + // ❌ Fetching data in a component causes network waterfalls + useEffect(() => { + fetch('/api/data') + .then(response => response.json()) + .then(data => setData(data)); + }, []); + + return ( +
      + {data.map(item =>
      {item.name}
      )} +
      + ) +} +``` + +Fetching in an effect means the user has to wait longer to see the content, even though the data could have been fetched earlier. To solve this, you can use a data fetching library like [React Query](https://react-query.tanstack.com/), [SWR](https://swr.vercel.app/), [Apollo](https://www.apollographql.com/docs/react), or [Relay](https://relay.dev/) which provide options to prefetch data so the request is started before the component renders. + +These libraries work best when integrated with your routing "loader" pattern to specify data dependencies at the route level, which allows the router to optimize your data fetches: + +```js +export async function loader() { + const response = await fetch(`/api/data`); + const data = await response.json(); + return data; +} + +// ✅ Fetching data in parallel while the code is downloading +export default function Dashboard({loaderData}) { + return ( +
      + {loaderData.map(item =>
      {item.name}
      )} +
      + ) +} +``` + +On initial load, the router can fetch the data immediately before the route is rendered. As the user navigates around the app, the router is able to fetch both the data and the route at the same time, parallelizing the fetches. This reduces the time it takes to see the content on the screen, and can improve the user experience. + +However, this requires correctly configuring the loaders in your app and trades off complexity for performance. + +### Code Splitting {/*code-splitting*/} + +Another common problem in Create React App is [code splitting](https://www.patterns.dev/vanilla/bundle-splitting). Create React App does not include a specific code splitting solution. If you're just getting started, you might not consider code splitting at all. + +This means your app is shipped as a single bundle: + +```txt +- bundle.js 75kb +``` + +But for ideal performance, you should "split" your code into separate bundles so the user only needs to download what they need. This decreases the time the user needs to wait to load your app, by only downloading the code they need to see the page they are on. + +```txt +- core.js 25kb +- home.js 25kb +- dashboard.js 25kb +``` + +One way to do code-splitting is with `React.lazy`. However, this means that the code is not fetched until the component renders, which can cause network waterfalls. A more optimal solution is to use a router feature that fetches the code in parallel while the code is downloading. For example, React Router provides a `lazy` option to specify that a route should be code split and optimize when it is loaded: + +```js +import Home from './Home'; +import Dashboard from './Dashboard'; + +// ✅ Routes are downloaded before rendering +const router = createBrowserRouter([ + {path: '/', lazy: () => import('./Home')}, + {path: '/dashboard', lazy: () => import('Dashboard')} +]); +``` + +Optimized code-splitting is tricky to get right, and it's easy to make mistakes that can cause the user to download more code than they need. It works best when integrated with your router and data loading solutions to maximize caching, parallelize fetches, and support ["import on interaction"](https://www.patterns.dev/vanilla/import-on-interaction) patterns. + +### And more... {/*and-more*/} + +These are just a few examples of the limitations of Create React App. + +Once you've integrated routing, data-fetching, and code splitting, you now also need to consider pending states, navigation interruptions, error messages to the user, and revalidation of the data. There are entire categories of problems that users need to solve like: + +
      +
        +
      • Accessibility
      • +
      • Asset loading
      • +
      • Authentication
      • +
      • Caching
      • +
      +
        +
      • Error handling
      • +
      • Mutating data
      • +
      • Navigations
      • +
      • Optimistic updates
      • +
      +
        +
      • Progressive enhancement
      • +
      • Server-side rendering
      • +
      • Static site generation
      • +
      • Streaming
      • +
      +
      + +All of these work together to create the most optimal [loading sequence](https://www.patterns.dev/vanilla/loading-sequence). + +Solving each of these problems individually in Create React App can be difficult as each problem is interconnected with the others and can require deep expertise in problem areas users may not be familiar with. In order to solve these problems, users end up building their own bespoke solutions on top of Create React App, which was the problem Create React App originally tried to solve. + +## Why we Recommend Frameworks {/*why-we-recommend-frameworks*/} + +Although you could solve all these pieces yourself in a build tool like Create React App, Vite, or Parcel, it is hard to do well. Just like when Create React App itself integrated several build tools together, you need a tool to integrate all of these features together to provide the best experience to users. + +This category of tools that integrates build tools, rendering, routing, data fetching, and code splitting are known as "frameworks" -- or if you prefer to call React itself a framework, you might call them "metaframeworks". + +Frameworks impose some opinions about structuring your app in order to provide a much better user experience, in the same way build tools impose some opinions to make tooling easier. This is why we started recommending frameworks like [Next.js](https://nextjs.org/), [React Router](https://reactrouter.com/), and [Expo](https://expo.dev/) for new projects. + +Frameworks provide the same getting started experience as Create React App, but also provide solutions to problems users need to solve anyway in real production apps. + + + +#### Server rendering is optional {/*server-rendering-is-optional*/} + +The frameworks we recommend all provide the option to create a [client-side rendered (CSR)](https://developer.mozilla.org/en-US/docs/Glossary/CSR) app. + +In some cases, CSR is the right choice for a page, but many times it's not. Even if most of your app is client-side, there are often individual pages that could benefit from server rendering features like [static-site generation (SSG)](https://developer.mozilla.org/en-US/docs/Glossary/SSG) or [server-side rendering (SSR)](https://developer.mozilla.org/en-US/docs/Glossary/SSR), for example a Terms of Service page, or documentation. + +Server rendering generally sends less JavaScript to the client, and a full HTML document which produces a faster [First Contentful Paint (FCP)](https://web.dev/articles/fcp) by reducing [Total Blocking Time (TBD)](https://web.dev/articles/tbt), which can also lower [Interaction to Next Paint (INP)](https://web.dev/articles/inp). This is why the [Chrome team has encouraged](https://web.dev/articles/rendering-on-the-web) developers to consider static or server-side render over a full client-side approach to achieve the best possible performance. + +There are tradeoffs to using a server, and it is not always the best option for every page. Generating pages on the server incurs additional cost and takes time to generate which can increase [Time to First Byte (TTFB)](https://web.dev/articles/ttfb). The best performing apps are able to pick the right rendering strategy on a per-page basis, based on the tradeoffs of each strategy. + +Frameworks provide the option to use a server on any page if you want to, but do not force you to use a server. This allows you to pick the right rendering strategy for each page in your app. + +#### What About Server Components {/*server-components*/} + +The frameworks we recommend also include support for React Server Components. + +Server Components help solve these problems by moving routing and data fetching to the server, and allowing code splitting to be done for client components based on the data you render, instead of just the route rendered, and reducing the amount of JavaScript shipped for the best possible [loading sequence](https://www.patterns.dev/vanilla/loading-sequence). + +Server Components do not require a server. They can be run at build time on your CI server to create a static-site generated app (SSG) app, at runtime on a web server for a server-side rendered (SSR) app. + +See [Introducing zero-bundle size React Server Components](/blog/2020/12/21/data-fetching-with-react-server-components) and [the docs](/reference/rsc/server-components) for more info. + + + + + +#### Server Rendering is not just for SEO {/*server-rendering-is-not-just-for-seo*/} + +A common misunderstanding is that server rendering is only for [SEO](https://developer.mozilla.org/en-US/docs/Glossary/SEO). + +While server rendering can improve SEO, it also improves performance by reducing the amount of JavaScript the user needs to download and parse before they can see the content on the screen. + +This is why the Chrome team [has encouraged](https://web.dev/articles/rendering-on-the-web) developers to consider static or server-side render over a full client-side approach to achieve the best possible performance. + + + +--- + +_Thank you to [Dan Abramov](https://bsky.app/profile/danabra.mov) for creating Create React App, and [Joe Haddad](https://github.com/Timer), [Ian Schmitz](https://github.com/ianschmitz), [Brody McKee](https://github.com/mrmckeb), and [many others](https://github.com/facebook/create-react-app/graphs/contributors) for maintaining Create React App over the years. Thank you to [Brooks Lybrand](https://bsky.app/profile/brookslybrand.bsky.social), [Dan Abramov](https://bsky.app/profile/danabra.mov), [Devon Govett](https://bsky.app/profile/devongovett.bsky.social), [Eli White](https://x.com/Eli_White), [Jack Herrington](https://bsky.app/profile/jherr.dev), [Joe Savona](https://x.com/en_JS), [Lauren Tan](https://bsky.app/profile/no.lol), [Lee Robinson](https://x.com/leeerob), [Mark Erikson](https://bsky.app/profile/acemarke.dev), [Ryan Florence](https://x.com/ryanflorence), [Sophie Alpert](https://bsky.app/profile/sophiebits.com), [Tanner Linsley](https://bsky.app/profile/tannerlinsley.com), and [Theo Browne](https://x.com/theo) for reviewing and providing feedback on this post._ + diff --git a/src/content/blog/index.md b/src/content/blog/index.md index 87b67b1e0..33e1c2bb5 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -4,7 +4,9 @@ title: React Blog -React チームからの公式な更新のお知らせはこのブログに掲載されます。リリースノートや非推奨化のお知らせなどの重要なことはすべて、まずこちらに掲載されます。Twitter の [@reactjs](https://twitter.com/reactjs) フォローすることもできますが、このブログさえ読んでいれば、重要なことを見逃す心配はありません。 +React チームからの公式な更新のお知らせはこのブログに掲載されます。リリースノートや非推奨化のお知らせなどの重要なことはすべて、まずこちらに掲載されます。 + +Bluesky の [@react.dev](https://bsky.app/profile/react.dev) や Twitter の [@reactjs](https://twitter.com/reactjs) アカウントをフォローすることもできますが、このブログさえ読んでいれば、重要なことを見逃す心配はありません。 @@ -14,6 +16,12 @@ React チームからの公式な更新のお知らせはこのブログに掲
      + + +Today, we’re deprecating Create React App for new apps, and encouraging existing apps to migrate to a framework, or to migrate to a build tool like Vite, Parcel, or RSBuild. We’re also providing docs for when a framework isn’t a good fit for your project, you want to build your own framework, or you just want to learn how React works by building a React app from scratch ... + + + React 19 アップグレードガイドでは、アプリを React 19 にアップグレードするためのステップバイステップガイドをお示ししました。この投稿では、React 19 の新機能と、それらをどのように採用するかについて概説します。 diff --git a/src/content/community/acknowledgements.md b/src/content/community/acknowledgements.md index 575223321..a58f44283 100644 --- a/src/content/community/acknowledgements.md +++ b/src/content/community/acknowledgements.md @@ -36,6 +36,8 @@ title: 謝辞 * [Joe Critchley](https://github.com/joecritch) * [Jeff Morrison](https://github.com/jeffmo) * [Luna Ruan](https://github.com/lunaruan) +* [Luna Wei](https://github.com/lunaleaps) +* [Noah Lemen](https://github.com/noahlemen) * [Kathryn Middleton](https://github.com/kmiddleton14) * [Keyan Zhang](https://github.com/keyz) * [Marco Salazar](https://github.com/salazarm) @@ -51,9 +53,10 @@ title: 謝辞 * [Samuel Susla](https://github.com/sammy-SC) * [Sander Spies](https://github.com/sanderspies) * [Sasha Aickin](https://github.com/aickin) -* [Sean Keegan](https://github.com/seanryankeegan) +* [Sathya Gunasekaran](https://github.com/gsathya) * [Sophia Shoemaker](https://github.com/mrscobbler) * [Sunil Pai](https://github.com/threepointone) +* [Tianyu Yao](https://github.com/) * [Tim Yung](https://github.com/yungsters) * [Xuan Huang](https://github.com/huxpro) diff --git a/src/content/community/conferences.md b/src/content/community/conferences.md index f4c40ca34..2422a09ce 100644 --- a/src/content/community/conferences.md +++ b/src/content/community/conferences.md @@ -10,23 +10,59 @@ title: React カンファレンス ## Upcoming Conferences {/*upcoming-conferences*/} -### React Day Berlin 2024 {/*react-day-berlin-2024*/} -December 13 & 16, 2024. In-person in Berlin, Germany + remote (hybrid event) +### React Paris 2025 {/*react-paris-2025*/} +March 20 - 21, 2025. In-person in Paris, France (hybrid event) -[Website](https://reactday.berlin/) - [Twitter](https://x.com/reactdayberlin) +[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 + +[Website](https://london.cityjsconf.org/) - [Twitter](https://x.com/cityjsconf) - [Bluesky](https://bsky.app/profile/cityjsconf.bsky.social) ### App.js Conf 2025 {/*appjs-conf-2025*/} May 28 - 30, 2025. In-person in Kraków, Poland + remote [Website](https://appjs.co) - [Twitter](https://twitter.com/appjsconf) +### CityJS Athens 2025 {/*cityjs-athens*/} +May 27 - 31, 2025. In-person in Athens, Greece + +[Website](https://athens.cityjsconf.org/) - [Twitter](https://x.com/cityjsconf) - [Bluesky](https://bsky.app/profile/cityjsconf.bsky.social) + ### React Summit 2025 {/*react-summit-2025*/} June 13 - 17, 2025. In-person in Amsterdam, Netherlands + remote (hybrid event) [Website](https://reactsummit.com/) - [Twitter](https://x.com/reactsummit) +### React Nexus 2025 {/*react-nexus-2025*/} +July 03 - 05, 2025. In-person in Bangalore, India + +[Website](https://reactnexus.com/) - [Twitter](https://x.com/ReactNexus) - [Bluesky](https://bsky.app/profile/reactnexus.com) - [Linkedin](https://www.linkedin.com/company/react-nexus) - [YouTube](https://www.youtube.com/reactify_in) + +### React Universe Conf 2025 {/*react-universe-conf-2025*/} +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 India 2025 {/*react-india-2025*/} +October 31 - November 01, 2025. In-person in Goa, India (hybrid event) + Oct 15 2025 - remote day + +[Website](https://www.reactindia.io) - [Twitter](https://twitter.com/react_india) - [Facebook](https://www.facebook.com/ReactJSIndia) - [Youtube](https://www.youtube.com/channel/UCaFbHCBkPvVv1bWs_jwYt3w) + + ## Past Conferences {/*past-conferences*/} +### React Day Berlin 2024 {/*react-day-berlin-2024*/} +December 13 & 16, 2024. In-person in Berlin, Germany + remote (hybrid event) + +[Website](https://reactday.berlin/) - [Twitter](https://x.com/reactdayberlin) + ### React Africa 2024 {/*react-africa-2024*/} November 29, 2024. In-person in Casablanca, Morocco (hybrid event) @@ -55,7 +91,7 @@ October 25, 2024. In-person in Verona, Italy + online (hybrid event) ### React Brussels 2024 {/*react-brussels-2024*/} October 18, 2024. In-person in Brussels, Belgium (hybrid event) -[Website](https://www.react.brussels/) - [Twitter](https://x.com/BrusselsReact) +[Website](https://www.react.brussels/) - [Twitter](https://x.com/BrusselsReact) - [YouTube](https://www.youtube.com/playlist?list=PL53Z0yyYnpWimQ0U75woee2zNUIFsiDC3) ### React India 2024 {/*react-india-2024*/} October 17 - 19, 2024. In-person in Goa, India (hybrid event) + Oct 15 2024 - remote day diff --git a/src/content/community/docs-contributors.md b/src/content/community/docs-contributors.md index 371b4149b..75a773400 100644 --- a/src/content/community/docs-contributors.md +++ b/src/content/community/docs-contributors.md @@ -11,7 +11,7 @@ React ドキュメントは [React チーム](/community/team)および[外部 ## Content {/*content*/} * [Rachel Nabors](https://twitter.com/RachelNabors): editing, writing, illustrating -* [Dan Abramov](https://twitter.com/dan_abramov): writing, curriculum design +* [Dan Abramov](https://bsky.app/profile/danabra.mov): writing, curriculum design * [Sylwia Vargas](https://twitter.com/SylwiaVargas): example code * [Rick Hanlon](https://twitter.com/rickhanlonii): writing * [David McCabe](https://twitter.com/mcc_abe): writing @@ -34,7 +34,7 @@ React ドキュメントは [React チーム](/community/team)および[外部 * [Jared Palmer](https://twitter.com/jaredpalmer): site development * [ThisDotLabs](https://www.thisdot.co/) ([Dane Grant](https://twitter.com/danecando), [Dustin Goodman](https://twitter.com/dustinsgoodman)): site development * [CodeSandbox](https://codesandbox.io/) ([Ives van Hoorne](https://twitter.com/CompuIves), [Alex Moldovan](https://twitter.com/alexnmoldovan), [Jasper De Moor](https://twitter.com/JasperDeMoor), [Danilo Woznica](https://twitter.com/danilowoz)): sandbox integration -* [Dan Abramov](https://twitter.com/dan_abramov): site development +* [Dan Abramov](https://bsky.app/profile/danabra.mov): site development * [Rick Hanlon](https://twitter.com/rickhanlonii): site development * [Harish Kumar](https://www.strek.in/): development and maintenance * [Luna Ruan](https://twitter.com/lunaruan): sandbox improvements diff --git a/src/content/community/meetups.md b/src/content/community/meetups.md index 544b2a1d7..43b50b3d7 100644 --- a/src/content/community/meetups.md +++ b/src/content/community/meetups.md @@ -57,6 +57,9 @@ title: React ミーティング * [React Advanced London](https://guild.host/react-advanced-london) * [React Native London](https://guild.host/RNLDN) +## Finland {/*finland*/} +* [Helsinki](https://www.meetabit.com/communities/react-helsinki) + ## France {/*france*/} * [Lille](https://www.meetup.com/ReactBeerLille/) * [Paris](https://www.meetup.com/ReactJS-Paris/) @@ -136,6 +139,9 @@ title: React ミーティング ## Spain {/*spain*/} * [Barcelona](https://www.meetup.com/ReactJS-Barcelona/) +## Sri Lanka {/*sri-lanka*/} +* [Colombo](https://www.javascriptcolombo.com/) + ## Sweden {/*sweden*/} * [Goteborg](https://www.meetup.com/ReactJS-Goteborg/) * [Stockholm](https://www.meetup.com/Stockholm-ReactJS-Meetup/) diff --git a/src/content/community/team.md b/src/content/community/team.md index 05c528721..10ebad961 100644 --- a/src/content/community/team.md +++ b/src/content/community/team.md @@ -22,10 +22,14 @@ React コアチームのメンバーは、コアコンポーネントの API、R Dan は Microsoft PowerPoint の中に偶然 Visual Basic を発見したことからプログラミングを始めました。[Sebastian](#sebastian-markbåge) のツイートを長文のブログ投稿に翻訳することが真の使命であると感じています。Fortnite では、ゲームが終わるまで茂みの中に隠れて勝利することがあります。 - + Eli のプログラミング経験は、ハッキングで中学校を停学処分になったことで始まりました。2017 年から React と React Native の開発に携わっています。お菓子を食べるのが好きで、特にアイスクリームとアップルパイがお気に入りです。Eli はよくパルクールや室内スカイダイビング、エアリアルシルクなど、風変わりな活動を試しています。 + + Hendrik の技術者としての歩みは、90 年代後半に Netscape Communicator で初めてウェブサイトを構築したことから始まりました。コンピュータサイエンスの学位を取得し、デジタル製作会社で働いた後、React Server Components バンドルラとライブラリを構築し、Next.js チームに加入しました。仕事以外での趣味はサイクリングと自宅の作業場でのもの作りです。 + + Jack は AutoHotkey を人に紹介されてから、思いつく限りの作業を自動化するスクリプトを書いてきました。そこで限界を感じてウェブアプリの開発に頭から飛び込んだ後は、それ一筋です。最近では Instagram のウェブプラットフォームに携わったのち、React チームにやってきました。好きなプログラミング言語は JSX です。 @@ -38,6 +42,10 @@ React コアチームのメンバーは、コアコンポーネントの API、R Joe は数学と哲学を専攻する予定でしたが、Matlab で物理シミュレーションを書いたことからコンピュータサイエンスに興味を持ちました。React に取り組む前は、Relay、RSocket.js、Skip プログラミング言語などに取り組んでいました。何かしらのリアクティブシステムを構築する傍らでは、ランニングをしたり、日本語を勉強したり、家族と過ごしたりしています。 + + Jordan のコーディングは、iPhone アプリの開発から始まり、for ループの意味を理解する前にビューコントローラーのスタック管理を行っていました。開発者に愛される技術に取り組むことが好きで、それが彼を自然と React に引き寄せました。仕事以外では、読書、カイトボード、ギター演奏を楽しんでいます。 + + Josh は大学で数学を専攻し、そこでプログラミングに出会いました。プロ開発者としての最初の仕事は、リアクティブプログラミングのお手本たる Microsoft Excel で保険料計算プログラムを書くことであり、きっとそれが今 React に取り組んでいる理由なのでしょう。その間 Josh はいくつかのスタートアップで IC、マネージャー、エグゼクティブも務めてきました。仕事以外では、料理で自分の限界に挑戦することが好きです。 @@ -46,20 +54,20 @@ React コアチームのメンバーは、コアコンポーネントの API、R Lauren のプログラミングキャリアは `` タグを初めて見たときにピークを迎えました。それ以来、彼女はその時の高揚感を追い続けています。大学ではコンピュータサイエンスではなく経済学を学んでいたため、コーディングは Excel で学びました。Lauren はチャットでお茶目なミームを投下したり、パートナとゲームを楽しんだり、韓国語を学んだり、犬の Zelda を可愛がったりするのが好きです。 - - Luna は 6 歳のときに父親から Python の基礎を学びました。それ以来、彼女を止めることは誰にもできません。典型的な Z 世代であらんと熱望する彼女のサクセスロードを形作るのは、環境保護活動、都会でのガーデニング、そして Voo-Doo'd(写真)と過ごす貴重な時間です。 - - Matt は偶然コーディングに出会い、独りでは作り出せないようなものをコミュニティで作ることに夢中になりました。React に参加する前は、YouTube、Google アシスタント、Fuchsia、Google Cloud AI、そして Evernote に取り組んでいました。開発者ツールの改善を行う傍らで、山を楽しんだり、ジャズを聴いたり、家族と時間を過ごしたりしています。 + + Mike は教授になることを夢見て大学院に進みましたが、研究費の応募書類を書いているよりも何かを開発することの方がより好きだと気付きました。Meta に入社して JavaScript インフラに携わり、最終的に React Compiler に取り組むことになりました。JavaScript か OCaml を触っていない時間は、太平洋岸北西部でハイキングやスキーを楽しんでいることが多いです。 + + Mofei はゲームでチートを行うのに役立つと気づいたことでプログラミングを始めました。彼女は学部・大学院ではオペレーティングシステムを専門にしていましたが、今では React いじりを楽しんでいます。仕事の外では、ボルダリングの問題をデバッグすることや、次回のバックパック旅行の計画を楽しんでいます。 - - Noah の UI プログラミングに対する興味に火が付いたのはニューヨーク大で音楽技術を学んでいる時でした。Meta では内部ツール、ブラウザ、ウェブパフォーマンスに関する業務を行い、現在は React に注力しています。仕事以外では、シンセサイザーをいじったり、猫と過ごしたりしています。 + + Pieter は建築学を学びましたが、就職できなかったため自分用のウェブサイトを作ったところ、そこから事態が発展していきました。Meta では、パフォーマンスや言語、そして現在は React の開発に取り組んでいます。プログラミングをしていない時は、道路から外れた山の中にいます。 @@ -70,10 +78,6 @@ React コアチームのメンバーは、コアコンポーネントの API、R Ruslan の UI プログラミングの経験は、子供のころにゲーム掲示板で HTML テンプレートを手でカスタマイズしたのが最初でした。その後いろいろあってコンピュータサイエンスを専攻することとなりました。好きなものは音楽、ゲーム、ネットミームです。特にネットミームです。 - - Sathya は学校ではドラゴン本(コンパイラの教科書)が大嫌いだったにも関わらず、どういうわけかキャリアを通じてコンパイラに取り組むことになりました。React コンポーネントをコンパイルしていないときは、コーヒーを飲んでいるかひたすらドーサを食べているかのどちらかです。 - - Sebastian の専攻は心理学でした。普段の彼はもの静かです。彼が何かを言ったとしても、数か月後まで他の人には理解できないことがよくあります。彼の姓の発音は本来 "mark-boa-geh" ですが、実用性を優先して "mark-beige" に落ち着きました。彼の React へのアプローチも実用主義的です。 @@ -90,10 +94,6 @@ React コアチームのメンバーは、コアコンポーネントの API、R Sophie は React がリリースされてから 4 日後、当時のプロジェクトを全部 React を使って書き直しました(今思えば少々無謀だったかもしれません)。彼女がプロジェクトのナンバーワンコミッタになった後、ほかの全員が Facebook から給料をもらっているのに自分だけがもらっていないのはなぜかと思い、成長期の React を主導するために正式にチームに参加しました。その仕事は数年前に辞めているのですが、なぜかまだチームのグループチャットで「価値を提供」しています。 - - Tianyu は、子供の頃からゲームが大好きだったことでコンピュータに興味を持ちました。その後、コンピュータサイエンスを専攻し、今でも League of Legends のような子供っぽいゲームを楽しんでいます。コンピュータの前にいないときは、2 匹の子猫と遊んだり、ハイキングやカヤックを楽しんだりしています。 - - Yuzhi は学校でコンピュータサイエンスを学びました。彼女は、実際に研究室に行かなくてもコードが生き生きと動く瞬間の喜びが好きでした。現在の彼女は React org のマネージャです。その前は、Relay のデータフェッチングフレームワークに取り組んでいました。余暇には、ガーデニングや家のリフォームを通じた生活の最適化にいそしんでいます。 diff --git a/src/content/community/versioning-policy.md b/src/content/community/versioning-policy.md index af504c019..dfafbb2d3 100644 --- a/src/content/community/versioning-policy.md +++ b/src/content/community/versioning-policy.md @@ -8,7 +8,7 @@ React のすべての安定版ビルドは広範なテストに通過してお -過去のリリースの一覧は [Versions](/versions) ページをご覧ください。 +このバージョニングポリシーでは `react` や `react-dom` のようなパッケージに対する我々の考え方を説明しています。過去のリリースの一覧は [Versions](/versions) ページをご覧ください。 ## 安定版リリース {/*stable-releases*/} @@ -24,6 +24,8 @@ React のすべての安定版ビルドは広範なテストに通過してお 最も一般的なタイプのリリースはマイナーリリースです。 +私たちは、ユーザが本番環境で古いバージョンの React を引き続き使用していることを認識しています。React のセキュリティ脆弱性を発見した場合、その脆弱性の影響を受けるすべてのメジャーバージョンに対して、バックポートされた修正を提供します。 + ### 破壊的な変更 {/*breaking-changes*/} 破壊的な変更は誰にとっても煩わしいため、メジャーリリースの数は最小限に抑えるようにしています。例えば、React 15 は 2016 年 4 月にリリースされ、React 16 は 2017 年 9 月にリリースされ、React 17 は 2020 年 10 月にリリースされました。 diff --git a/src/content/learn/add-react-to-an-existing-project.md b/src/content/learn/add-react-to-an-existing-project.md index 57fdc507d..51af6134e 100644 --- a/src/content/learn/add-react-to-an-existing-project.md +++ b/src/content/learn/add-react-to-an-existing-project.md @@ -21,8 +21,8 @@ title: 既存プロジェクトに React を追加する 以下の手順に従って設定することをお勧めします。 1. [React ベースのフレームワーク](/learn/start-a-new-react-project)のうちひとつを使い、アプリの **React 部分をビルド**します。 -2. フレームワークの設定で `/some-app` を ***base path* に指定**します(方法:[Next.js](https://nextjs.org/docs/api-reference/next.config.js/basepath)、[Gatsby](https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting/path-prefix/))。 -3. **サーバーまたはプロキシを設定**して、`/some-app/` 以下のすべてのリクエストを React アプリで処理するようにします。 +2. フレームワークの設定で `/some-app` を ***base path* に指定**します(方法:[Next.js](https://nextjs.org/docs/app/api-reference/config/next-config-js/basePath)、[Gatsby](https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting/path-prefix/))。 +3. **サーバまたはプロキシを設定**して、`/some-app/` 以下のすべてのリクエストを React アプリで処理するようにします。 こうすることで、アプリの React 部分がこれらのフレームワークに組み込まれた[ベストプラクティスを最大限に取り入れる](/learn/start-a-new-react-project#can-i-use-react-without-a-framework)ことができます。 @@ -45,7 +45,7 @@ title: 既存プロジェクトに React を追加する * **アプリが既に `import` 文を使ってファイル分割するよう設定されている場合**、その既存の設定を使用するようにしてみてください。JS コードで `
      ` と記述すると、構文エラーが発生するかどうかを確認してください。構文エラーが発生する場合は、[Babel を使用して JavaScript を変換](https://babeljs.io/setup)するようにし、JSX を使うために [Babel React プリセット](https://babeljs.io/docs/babel-preset-react) を有効にしてください。 -* **JavaScript モジュールをコンパイルする既存のセットアップがない場合**は、[Vite](https://vitejs.dev/) を使ってセットアップします。Vite コミュニティは、Rails、Django、Laravel をはじめ、[多くのバックエンドフレームワークとのインテグレーション](https://github.com/vitejs/awesome-vite#integrations-with-backends)をメンテナンスしています。あなたのバックエンドフレームワークがリストされていない場合は、[このガイドに従って](https://vitejs.dev/guide/backend-integration.html)手動で Vite ビルドをバックエンドと統合してください。 +* **JavaScript モジュールをコンパイルする既存のセットアップがない場合**は、[Vite](https://vite.dev/) を使ってセットアップします。Vite コミュニティは、Rails、Django、Laravel をはじめ、[多くのバックエンドフレームワークとのインテグレーション](https://github.com/vitejs/awesome-vite#integrations-with-backends)をメンテナンスしています。あなたのバックエンドフレームワークがリストされていない場合は、[このガイドに従って](https://vite.dev/guide/backend-integration.html)手動で Vite ビルドをバックエンドと統合してください。 セットアップがうまくいっているかどうかを確認するには、プロジェクトフォルダーで次のコマンドを実行します。 @@ -57,12 +57,13 @@ npm install react react-dom -```html index.html hidden +```html public/index.html hidden My app +
      ``` @@ -84,7 +85,7 @@ root.render(

      Hello, world

      ); -既存のプロジェクトにモジュラーな JavaScript 環境を組み込むことを最初は不安に感じるかもしれませんが、その価値はあると思います! 行き詰まったら、[コミュニティのリソース](/community)または [Vite Chat](https://chat.vitejs.dev/) を試してみてください。 +既存のプロジェクトにモジュラーな JavaScript 環境を組み込むことを最初は不安に感じるかもしれませんが、その価値はあると思います! 行き詰まったら、[コミュニティのリソース](/community)または [Vite Chat](https://chat.vite.dev/) を試してみてください。 @@ -119,7 +120,7 @@ root.render(

      Hello, world

      ); -```html index.html +```html public/index.html My app diff --git a/src/content/learn/build-a-react-app-from-scratch.md b/src/content/learn/build-a-react-app-from-scratch.md new file mode 100644 index 000000000..b00205388 --- /dev/null +++ b/src/content/learn/build-a-react-app-from-scratch.md @@ -0,0 +1,143 @@ +--- +title: ゼロからの React アプリ構築 +--- + + + +あなたのアプリが既存のフレームワークではうまく対応できない制約を有している場合や、自分自身でフレームワークを構築したい場合、または React アプリの基本を学びたい場合は、ゼロから React アプリを構築することも可能です。 + + + + + +#### まずはフレームワーク使用の検討を {/*consider-using-a-framework*/} + +React の始め方としてゼロからスタートするのは簡単ですが、このアプローチを選ぶ際の重要なトレードオフとして、これがその場限りの独自フレームワークを構築しているのと変わらないのだ、ということを認識してください。アプリの要件が進化するにつれ、推奨フレームワークならすでにうまく開発もサポートもしているような、よりフレームワーク的な問題について、自前で解決する必要が出てくるかもしれません。 + +たとえば、将来的にアプリがサーバサイドレンダリング (SSR)、静的サイト生成 (SSG)、または React Server Components (RSC) のサポートを必要とする場合、それらを自前で実装しなければなりません。同様に、フレームワークレベルでの統合を必要とする将来の React 機能を使用したい場合、それらも自分で実装しなければなりません。 + +私たちが推奨するフレームワークは、よりパフォーマンスの良いアプリを構築するのにも役立ちます。たとえば、ネットワークリクエストのウォーターフォールを減らしたり排除したりすることで、より良いユーザ体験を提供します。小さなプロジェクトを構築している間は優先度が低いかもしれませんが、アプリにユーザが増えていけばパフォーマンスを向上させたいと思うことでしょう。 + +またこのアプローチでは、ルーティングやデータフェッチ、その他の機能の開発のされ方があなたの事情に特有のものになるため、サポートを受けるのも難しくなります。これらの問題に自分で取り組むことに自信がある場合、または将来的にもこれらの機能が必要になることはないと確信している場合にのみ、このオプションを選ぶようにすべきです。 + +推奨フレームワークのリストについては、[React アプリの作成](/learn/creating-a-react-app)をご覧ください。 + + + + +## ステップ 1:ビルドツールのインストール {/*step-1-install-a-build-tool*/} + +最初のステップは、`vite`、`parcel`、または `rsbuild` のようなビルドツールをインストールすることです。これらのビルドツールは、ソースコードをパッケージ化して実行する機能、ローカル開発用の開発サーバ、およびアプリを本番サーバにデプロイするためのビルドコマンドを提供します。 + +### Vite {/*vite*/} + +[Vite](https://vite.dev/) は、モダンなウェブプロジェクトのために素早くかつスリムな開発体験を提供することを目指したビルドツールです。 + + +{`npm create vite@latest my-app -- --template react`} + + +Vite はデフォルトで適切な設定がされた、使い方に規約がある (opinionated) ツールです。Vite には、ファストリフレッシュ、JSX、Babel/SWC、その他の一般的な機能をサポートする豊富なプラグインのエコシステムがあります。Vite の [React プラグイン](https://vite.dev/plugins/#vitejs-plugin-react)や [React SWC プラグイン](https://vite.dev/plugins/#vitejs-plugin-react-swc)、[React SSR のサンプルプロジェクト](https://vite.dev/guide/ssr.html#example-projects) を参照して始めてみてください。 + +Vite は、[推奨フレームワーク](/learn/creating-a-react-app) のひとつである [React Router](https://reactrouter.com/start/framework/installation) でもビルドツールとして使用されています。 + +### Parcel {/*parcel*/} + +[Parcel](https://parceljs.org/) は、素晴らしい初期開発体験とスケーラブルなアーキテクチャの両方を備えており、プロジェクトを始めたばかりの状態から大規模な本番アプリケーションにまで成長させることができます。 + + +{`npm install --save-dev parcel`} + + +Parcel は、ファストリフレッシュ、JSX、TypeScript、Flow、スタイリングをデフォルトでサポートしています。[Parcel の React レシピ](https://parceljs.org/recipes/react/#getting-started)を参照して始めてみてください。 + +### Rsbuild {/*rsbuild*/} + +[Rsbuild](https://rsbuild.dev/) は、Rspack を基にしたビルドツールで、React アプリケーションのためのシームレスな開発体験を提供します。慎重に調整されたデフォルト設定とパフォーマンス最適化が最初から利用できます。 + + +{`npx create-rsbuild --template react`} + + +Rsbuild には、ファストリフレッシュ、JSX、TypeScript、スタイリングなどの React 機能のサポートが組み込まれています。[Rsbuild の React ガイド](https://rsbuild.dev/guide/framework/react)を参照して始めてみてください。 + + + +#### React Native 用の Metro {/*react-native*/} + +React Native をゼロから始める場合は、React Native 用の JavaScript バンドラである [Metro](https://metrobundler.dev/) を使用する必要があります。Metro は iOS や Android などのプラットフォーム向けのバンドル機能をサポートしていますが、上記で紹介したツールと比較すると多くの機能が不足しています。プロジェクトが React Native のサポートを必要としているのでない限り、Vite、Parcel、または Rsbuild から始めることをお勧めします。 + + + +## ステップ 2:一般的なアプリケーションパターンの構築 {/*step-2-build-common-application-patterns*/} + +上記のビルドツールを使うとクライアントのみのシングルページアプリ (SPA) から始まりますが、それ以上のもの、つまりルーティング、データフェッチ、スタイリングといった一般的な機能に対するソリューションは含まれていません。 + +React エコシステムには、これらの問題に対するツールがたくさん存在します。手始めとして、ここでは広く使用されているものをいくつか紹介していますが、他のツールがあなたにとってより適している場合は自由に選んでください。 + +### ルーティング {/*routing*/} + +ルーティング (routing) は、ユーザが特定の URL にアクセスしたときにどのコンテンツやページを表示するかを決定するものです。ある URL をアプリの異なる部分にマッピングするために、ルータの設定が必要です。また、ネストされたルート、ルートパラメータ、クエリパラメータを処理する必要があります。ルータはコード内で設定することも、コンポーネントのフォルダやファイル構造に基づいて定義することもできます。 + +ルータは現代のアプリケーションの中核をなす部分であり、通常はデータフェッチ(ページ全体のデータの高速なプリフェッチを含む)、コード分割(クライアントのバンドルサイズを最小化する)、およびページのレンダー方法(各ページがどのように生成されるかを決定する)と統合されています。 + +以下のライブラリの使用をお勧めします。 + +- [React Router](https://reactrouter.com/start/framework/custom) +- [Tanstack Router](https://tanstack.com/router/latest) + + +### データフェッチ {/*data-fetching*/} + +サーバやその他のデータソースからデータを取得することは、ほとんどのアプリケーションにおいて重要な作業です。これを適切に行うには、ローディング状態の管理、エラー状態の管理、および取得したデータのキャッシュ管理が必要であり、複雑になりがちです。 + +この目的に特化したデータフェッチライブラリは、データの取得とキャッシュに関する難しい作業を行ってくれるため、あなたはアプリが必要とするデータとその表示方法に集中できます。これらのライブラリは通常、コンポーネント内で直接使用されますが、ルーティングのローダに統合して高速な事前取得とパフォーマンスの向上を図ることもでき、サーバレンダーにも利用できます。 + +コンポーネント内で直接データを取得すると、ネットワークリクエストのウォーターフォールに伴う遅延が発生し、読み込み時間が遅くなる可能性があることに注意してください。可能な限り、ルータローダやサーバで、データを事前フェッチすることをお勧めします! これによりページの表示とページデータの取得をまとめて同時に行うことができます。 + +ほとんどのデータをバックエンドや REST スタイルの API から取得している場合、以下のライブラリの使用をお勧めします。 + +- [React Query](https://react-query.tanstack.com/) +- [SWR](https://swr.vercel.app/) +- [RTK Query](https://redux-toolkit.js.org/rtk-query/overview) + +GraphQL API からデータを取得する場合、以下の使用をお勧めします。 + +- [Apollo](https://www.apollographql.com/docs/react) +- [Relay](https://relay.dev/) + + +### コード分割 {/*code-splitting*/} + +コード分割 (code splitting) とは、オンデマンドで読み込める小さな複数のバンドルへとアプリを分割するための作業です。アプリのコードサイズは、新しい機能や依存ライブラリを追加するたびに増加します。実際に使用する前にアプリ全体のコードをすべて送信する必要がある場合、読み込みが遅くなることがあります。キャッシュ、機能や依存ライブラリの削減、一部コードのサーバ側実行といった方法で読み込みの遅さを軽減することもできますが、これらは過度に使用すると機能性を犠牲にしてしまう不完全な解決策です。 + +また、アプリが使っている独自フレームワークにコード分割を任せていると、コード分割がまったく行われていない場合より却って読み込みが遅くなるという状況に遭遇することがあります。例えば、チャートの[遅延読み込み](/reference/react/lazy)を使えば、チャートのコードをアプリの他の部分から分離し、チャートのレンダーに必要なコードだけ送信を遅らせることができます。[Parcel は React.lazy を使用したコード分割をサポートしています](https://parceljs.org/recipes/react/#code-splitting)。ところが、チャートのコード自身が初回レンダー後にデータを読み込む場合、2 回の待機が発生することになります。これがウォーターフォールです。チャートデータとそれを表示するためのコードを同時にフェッチするのではなく、各ステップが順番に完了するのを待たなければならないという状況です。 + +ルートごとにコードを分割するだけでなく、バンドルやデータフェッチと統合することで、アプリの初期読み込み時間とアプリの最大可視コンテンツのレンダー時間 ([Largest Contentful Paint](https://web.dev/articles/lcp)) を短縮できます。 + +コード分割の手順については、ビルドツールのドキュメントを参照してください。 +- [Vite のビルド最適化](https://v3.vitejs.dev/guide/features.html#build-optimizations) +- [Parcel のコード分割](https://parceljs.org/features/code-splitting/) +- [Rsbuild のコード分割](https://rsbuild.dev/guide/optimization/code-splitting) + +### アプリケーションパフォーマンスの向上 {/*improving-application-performance*/} + +あなたが選択したビルドツールは、シングルページアプリ (SPA) のみをサポートしています。このためサーバサイドレンダリング (SSR)、静的サイト生成 (SSG)、あるいは React Server Components (RSC) などの他の[レンダーパターン](https://www.patterns.dev/vanilla/rendering-patterns)は自分で実装する必要があります。最初はこれらの機能が必要でなくても、将来的には SSR、SSG、または RSC の恩恵を受けるルート(ページ)があるかもしれません。 + +* **シングルページアプリ (SPA)** は、単一の HTML ページを読み込み、ユーザがアプリを操作した際にページを動的に更新します。SPA は始めやすいですが、初期読み込み時間が遅くなることがあります。SPA はほとんどのビルドツールにおけるデフォルトのアーキテクチャです。 + +* **ストリーミングサーバサイドレンダリング (SSR)** は、サーバでページをレンダーし、完全にレンダーされたページをクライアントに送信します。SSR はパフォーマンスを向上できますが、シングルページアプリよりも設定とメンテナンスが複雑になることがあります。ストリーミングを追加すると、SSR の構築とメンテナンスは非常に複雑になります。[Vite の SSR ガイド](https://vite.dev/guide/ssr)を参照してください。 + +* **静的サイト生成 (SSG)** は、ビルド時にアプリの静的 HTML ファイルを生成します。SSG はパフォーマンスを向上させることができますが、サーバサイドレンダリングよりも設定とメンテナンスが複雑になることがあります。[Vite の SSG ガイド](https://vite.dev/guide/ssr.html#pre-rendering-ssg)を参照してください。 + +* **React Server Components (RSC)** は、ビルド時専用コンポーネント、サーバ専用コンポーネント、そしてインタラクティブなコンポーネントを、単一の React ツリーで混在させることができます。RSC はパフォーマンスを向上させることができますが、現在のところ、設定とメンテナンスには深い専門知識が必要です。[Parcel の RSC の例](https://github.com/parcel-bundler/rsc-examples)を参照してください。 + +あなたのレンダー戦略を、ルータと統合する必要があります。それによりあなたのフレームワークで構築されたアプリが、ルートごとにレンダー戦略を選択できるようにするのです。これにより、アプリ全体を書き直すことなく、異なるレンダー戦略を利用できます。たとえば、アプリの最初のページでは静的な生成 (SSG) が有益かもしれませんが、コンテンツフィードを持つページはサーバサイドレンダリングが最適かもしれません。 + +適切なルートに適切なレンダー戦略を使用することで、コンテンツの最初のバイトが読み込まれるまでの時間 ([Time to First Byte](https://web.dev/articles/ttfb))、最初のコンテンツが表示されるまでの時間 ([First Contentful Paint](https://web.dev/articles/fcp))、およびアプリの最大の可視コンテンツが表示されるまでの時間 ([Largest Contentful Paint](https://web.dev/articles/lcp)) を短縮できるのです。 + +### さらに... {/*and-more*/} + +これらは、新しいアプリをゼロから構築する際に考慮すべき機能のほんの一例です。あなたが直面するであろう多くの問題は、それぞれが他の問題と相互に関連しており、不慣れな領域での深い専門知識を必要とする場合もあるため、解決が難しいことがあります。 + +これらの問題を自分で解決したくない場合は、これらの機能をデフォルトで利用できるフレームワークで[始めることができます](/learn/creating-a-react-app)。 diff --git a/src/content/learn/creating-a-react-app.md b/src/content/learn/creating-a-react-app.md new file mode 100644 index 000000000..509deca01 --- /dev/null +++ b/src/content/learn/creating-a-react-app.md @@ -0,0 +1,113 @@ +--- +title: React アプリの作成 +--- + + + +React を使って新しいアプリやウェブサイトを作成したい場合は、フレームワークを使って始めることをおすすめします。 + + + +あなたのアプリが既存のフレームワークではうまく対応できない制約を有している場合や、自分自身でフレームワークを構築したい場合、または React アプリの基本を学びたい場合は、[React アプリをゼロから構築する](/learn/build-a-react-app-from-scratch)ことも可能です。 + +## フルスタックフレームワーク {/*full-stack-frameworks*/} + +これらの推奨フレームワークは、アプリを本番環境でデプロイしスケールするために必要な、すべての機能をサポートしています。最新の React 機能を統合し、React のアーキテクチャを活用しています。 + + + +#### フルスタックフレームワークは必ずしもサーバを必要としない {/*react-frameworks-do-not-require-a-server*/} + +このページのすべてのフレームワークは、クライアントサイドレンダリング (client-side rendering; [CSR](https://developer.mozilla.org/en-US/docs/Glossary/CSR))、シングルページアプリケーション (single-page app; [SPA](https://developer.mozilla.org/en-US/docs/Glossary/SPA)) および静的サイト生成 (static-site generation; [SSG](https://developer.mozilla.org/en-US/docs/Glossary/SSG)) をサポートしています。これらのアプリは、サーバ機能なしで [CDN](https://developer.mozilla.org/en-US/docs/Glossary/CDN) や静的ホスティングサービスにデプロイできます。さらに、これらのフレームワークは、ユースケースに応じてサーバサイドレンダリングをルートごとに追加することを可能にします。 + +これにより、クライアントのみのアプリから始めておき、後で要件が変化した場合に、アプリを書き直すことなく個々のルートでサーバ機能を使用することを選択できます。レンダー戦略の設定については、フレームワークのドキュメントを参照してください。 + + + +### Next.js (App Router) {/*nextjs-app-router*/} + +**[Next.js の App Router](https://nextjs.org/docs) は、React のアーキテクチャを最大限に活用してフルスタック React アプリを実現する React フレームワークです**。 + + +npx create-next-app@latest + + +Next.js は [Vercel](https://vercel.com/) によってメンテナンスされています。Next.js アプリを Node.js やサーバレスホスティング、または独自のサーバに[デプロイできます](https://nextjs.org/docs/app/building-your-application/deploying)。Next.js はまた、サーバを必要としない[静的エクスポート](https://nextjs.org/docs/app/building-your-application/deploying/static-exports)をサポートしています。Vercel はさらにオプトインの有料クラウドサービスも提供しています。 + +### React Router (v7) {/*react-router-v7*/} + +**[React Router](https://reactrouter.com/start/framework/installation) は、React 用の最も人気のあるルーティングライブラリであり、Vite と組み合わせてフルスタック React フレームワークを作成できます**。標準の Web API を重視しており、さまざまな JavaScript ランタイムやプラットフォーム向けに[そのままデプロイできるテンプレート](https://github.com/remix-run/react-router-templates)をいくつか提供しています。 + +新しい React Router フレームワークプロジェクトを作成するには、以下のコマンドを実行します。 + + +npx create-react-router@latest + + +React Router は [Shopify](https://www.shopify.com) によってメンテナンスされています。 + +### Expo (ネイティブアプリ用) {/*expo*/} + +**[Expo](https://expo.dev/) は、真にネイティブな UI を持つユニバーサルな Android、iOS、および Web アプリを作成できる React フレームワークです**。[React Native](https://reactnative.dev/) 用の SDK を提供することでネイティブ部分を使いやすくしています。新しい Expo プロジェクトを作成するには、以下のコマンドを実行します。 + + +npx create-expo-app@latest + + +Expo を初めて使用する場合は、[Expo チュートリアル](https://docs.expo.dev/tutorial/introduction/)をチェックしてください。 + +Expo は [Expo(社名)](https://expo.dev/about) によってメンテナンスされています。Expo を使ったアプリ構築は無料であり、Google や Apple のアプリストアにも制限なく申請できます。また Expo ではオプトインの有料クラウドサービスも提供しています。 + + +## その他のフレームワーク {/*other-frameworks*/} + +私たちのフルスタック React ビジョンに向けて取り組んでいる他の新進のフレームワークも存在します。 + +- [TanStack Start (Beta)](https://tanstack.com/): TanStack Start は、TanStack Router を活用したフルスタック React フレームワークです。Nitro や Vite などのツールを使用して、フルドキュメント SSR、ストリーミング、サーバ関数、バンドル機能などを提供します。 +- [RedwoodJS](https://redwoodjs.com/): Redwood は、多くのプリインストールされたパッケージと設定を備えたフルスタック React フレームワークで、フルスタックウェブアプリケーションを簡単に構築できます。 + + + +#### React チームのフルスタックアーキテクチャビジョンに含まれる機能 {/*which-features-make-up-the-react-teams-full-stack-architecture-vision*/} + +Next.js の App Router バンドラは、公式の [React Server Components 仕様](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md)を完全に実装しています。これにより単一の React ツリー内で、バンドル時専用コンポーネント、サーバ専用コンポーネント、インタラクティブなコンポーネントを混在させることができます。 + +例えば、データベースやファイルから読み込みを行う React コンポーネントを非同期 (`async`) 関数として記述できます。そしてそのデータをインタラクティブなコンポーネントに渡すこともできます。 + +```js +// This component runs *only* on the server (or during the build). +async function Talks({ confId }) { + // 1. You're on the server, so you can talk to your data layer. API endpoint not required. + const talks = await db.Talks.findAll({ confId }); + + // 2. Add any amount of rendering logic. It won't make your JavaScript bundle larger. + const videos = talks.map(talk => talk.video); + + // 3. Pass the data down to the components that will run in the browser. + return ; +} +``` + +Next.js の App Router は、[サスペンス (Suspense) を使用したデータフェッチ](/blog/2022/03/29/react-v18#suspense-in-data-frameworks)を統合しています。これにより、React ツリー内で直接、UI の様々な場所に表示されるロード中状態(スケルトンプレースホルダなど)を指定できるようになります。 + +```js +}> + + +``` + +サーバコンポーネントとサスペンスは、Next.js の機能ではなく React の機能です。しかしフレームワークレベルでこれらを採用するには、合意形成とかなりの実装の手間が必要です。現時点では、Next.js の App Router が最も完全な実装です。React チームはバンドラの開発者と協力して、次世代のフレームワークでこれらの機能を実装しやすくすることを目指しています。 + + + +## ゼロから構築を始める {/*start-from-scratch*/} + +あなたのアプリが既存のフレームワークではうまく対応できない制約を有している場合や、自分自身でフレームワークを構築したい場合、または React アプリの基本を学びたい場合には、ゼロから React プロジェクトを始めるための他の選択肢があります。 + +ゼロから始めることでより柔軟性が得られますが、ルーティング、データフェッチ、その他の一般的な使用パターンにどのツールを使用するかを選択する必要があります。これは、既存のフレームワークを使用する代わりに自分自身でフレームワークを構築するようなものです。[おすすめのフルスタックフレームワーク](#full-stack-frameworks)には、これらの問題に対する組み込みの解決策があります。 + +独自のソリューションを構築したい場合は、[ゼロからの React アプリ構築](/learn/build-a-react-app-from-scratch)ガイドを参照し、[Vite](https://vite.dev/)、[Parcel](https://parceljs.org/)、または [RSbuild](https://rsbuild.dev/) のようなビルドツールを使って新しい React プロジェクトをセットアップする方法を確認してください。 + +----- + +_このページに掲載されることに興味のあるフレームワークの作者の方は、[こちらからお知らせください](https://github.com/reactjs/react.dev/issues/new?assignees=&labels=type%3A+framework&projects=&template=3-framework.yml&title=%5BFramework%5D%3A+)_。 diff --git a/src/content/learn/installation.md b/src/content/learn/installation.md index dc77e377e..cea3f00f3 100644 --- a/src/content/learn/installation.md +++ b/src/content/learn/installation.md @@ -8,15 +8,6 @@ React は当初より、段階的に導入できるように設計されてい - - -* [新しい React プロジェクトを始める方法](/learn/start-a-new-react-project) -* [既存プロジェクトに React を追加する方法](/learn/add-react-to-an-existing-project) -* [エディタの設定方法](/learn/editor-setup) -* [React Developer Tools のインストール方法](/learn/react-developer-tools) - - - ## React を試してみる {/*try-react*/} React を試すために何かをインストールする必要はありません。このサンドボックスを編集してみてください! @@ -39,17 +30,28 @@ export default function App() { React ドキュメントのほとんどのページには、このようなサンドボックスが含まれています。React のドキュメント外にも、React をサポートするオンラインサンドボックスがたくさんあります。例えば、[CodeSandbox](https://codesandbox.io/s/new)、[StackBlitz](https://stackblitz.com/fork/react) や [CodePen](https://codepen.io/pen?template=QWYVwWN) が挙げられます。 -### ローカルで React を試す {/*try-react-locally*/} - あなたのコンピュータのローカル環境で React を試すには、[この HTML ページをダウンロードしてください](https://gist.githubusercontent.com/gaearon/0275b1e1518599bbeafcde4722e79ed1/raw/db72dcbf3384ee1708c4a07d3be79860db04bff0/example.html)。そしてエディタとブラウザで開いてください! -## 新しい React プロジェクトを開始する {/*start-a-new-react-project*/} +## React アプリの新規作成 {/*creating-a-react-app*/} + +新しい React アプリを立ち上げたい場合は、推奨されるフレームワークを用いて[新しい React アプリを作成](/learn/creating-a-react-app)します。 + +## ゼロからの React アプリ構築 {/*build-a-react-app-from-scratch*/} -アプリやウェブサイトを React でフルに構築したい場合は、[新しい React プロジェクトを始めましょう](/learn/start-a-new-react-project)。 +あなたのプロジェクトにフレームワークが適さない場合、自分自身でフレームワークを構築したい場合、あるいは React を基本から学びたい場合は、[ゼロから React アプリを構築する](/learn/build-a-react-app-from-scratch)ことも可能です。 ## 既存のプロジェクトに React を追加する {/*add-react-to-an-existing-project*/} -既存のアプリやウェブサイトで React を試してみたい場合は、[既存のプロジェクトに React を追加してください](/learn/add-react-to-an-existing-project)。 +既存のアプリやウェブサイトで React を試してみたい場合は、[既存のプロジェクトに React を追加](/learn/add-react-to-an-existing-project)することもできます。 + + + + +#### Create React App を使うべき? {/*should-i-use-create-react-app*/} + +いいえ、Create React App は非推奨となっています。詳細は [Create React App のサポート終了](/blog/2025/02/14/sunsetting-create-react-app)を参照してください。 + + ## 次のステップ {/*next-steps*/} diff --git a/src/content/learn/manipulating-the-dom-with-refs.md b/src/content/learn/manipulating-the-dom-with-refs.md index 53535f956..45809ac77 100644 --- a/src/content/learn/manipulating-the-dom-with-refs.md +++ b/src/content/learn/manipulating-the-dom-with-refs.md @@ -647,7 +647,7 @@ DOM 要素を手動で削除した後、`setState` を使用して再度表示 - ref は一般的な概念だが、ほとんどの場合、DOM 要素を保持するために使用する。 - `
      ` のように渡すことで、React に DOM ノードを `myRef.current` に入れるよう指示する。 - 通常、フォーカス、スクロール、または DOM 要素の測定などの非破壊的なアクションに ref を使用する。 -- コンポーネントはデフォルトでは内部の DOM ノードを公開しない。`forwardRef` を使用して特定のノードに 2 番目の `ref` 引数を渡すことで、DOM ノードの公開を明示的に許可する。 +- コンポーネントはデフォルトでは内部の DOM ノードを公開しない。props として `ref` を用いることで、DOM ノードの公開を明示的に許可する。 - React によって管理される DOM ノードの変更を避ける。 - React によって管理される DOM ノードをどうしても変更する場合は、React が更新する理由のない部分のみ変更する。 @@ -1049,7 +1049,7 @@ img { -`SearchInput` のような独自コンポーネントから DOM ノードを公開するためには、`forwardRef` が必要です。 +`SearchInput` のような独自コンポーネントから DOM ノードを公開するためには、props としての `ref` の受け渡しが必要です。 @@ -1134,18 +1134,14 @@ export default function SearchButton({ onClick }) { ``` ```js src/SearchInput.js -import { forwardRef } from 'react'; - -export default forwardRef( - function SearchInput(props, ref) { - return ( - - ); - } -); +export default function SearchInput({ ref }) { + return ( + + ); +} ``` ```css diff --git a/src/content/learn/passing-data-deeply-with-context.md b/src/content/learn/passing-data-deeply-with-context.md index d045771af..e1ddd8bad 100644 --- a/src/content/learn/passing-data-deeply-with-context.md +++ b/src/content/learn/passing-data-deeply-with-context.md @@ -468,15 +468,15 @@ import { LevelContext } from './LevelContext.js'; export default function Section({ level, children }) { return (
      - + {children} - +
      ); } ``` -これにより、「この `
      ` の下にあるコンポーネントが `LevelContext` の値を要求した場合、この `level` を渡せ」と React に伝えていることになります。コンポーネントは、UI ツリー内の上側で、最も近い `` の値を使用します。 +これにより、「この `
      ` の下にあるコンポーネントが `LevelContext` の値を要求した場合、この `level` を渡せ」と React に伝えていることになります。コンポーネントは、UI ツリー内の上側で、最も近い `` の値を使用します。 @@ -514,9 +514,9 @@ import { LevelContext } from './LevelContext.js'; export default function Section({ level, children }) { return (
      - + {children} - +
      ); } @@ -567,7 +567,7 @@ export const LevelContext = createContext(1); 元のコードと見た目の結果は同じですが、`level` を props として個々の `Heading` コンポーネントに渡さずに済んでいます! 代わりに、見出しは最も近い `Section` に値を要求して、自分の見出しレベルを自分で「判断」しているのです。 1. `
      ` に props として `level` を渡す。 -2. `Section` は子要素を `` でラップする。 +2. `Section` は子要素を `` でラップする。 3. `Heading` は `useContext(LevelContext)` とすることで、上にある最も近い `LevelContext` の値を要求する。 ## 同一コンポーネントでコンテクストを使用しつつ提供 {/*using-and-providing-context-from-the-same-component*/} @@ -595,9 +595,9 @@ export default function Section({ children }) { const level = useContext(LevelContext); return (
      - + {children} - +
      ); } @@ -643,9 +643,9 @@ export default function Section({ children }) { const level = useContext(LevelContext); return (
      - + {children} - +
      ); } @@ -776,9 +776,9 @@ export default function Section({ children, isFancy }) { 'section ' + (isFancy ? 'fancy' : '') }> - + {children} - +
      ); } @@ -868,7 +868,7 @@ CSS では、`color` や `background-color` といった異なるプロパティ * コンテクストを使うには: 1. `export const MyContext = createContext(defaultValue)` を使用して作成およびエクスポートする。 2. フックに `useContext(MyContext)` のようにコンテクストを渡せば、どんな深い子コンポーネントからも値が読み取れる。 - 3. コンテクストの値を提供するには子要素を `` でラップする。 + 3. コンテクストの値を提供するには子要素を `` でラップする。 * コンテクストは中間コンポーネントを貫通する。 * コンテクストを使えば、「周囲に適応する」コンポーネントが書ける。 * コンテクストを使用する前に、props を渡すか、`children` として JSX を渡す方法を検討してみる。 @@ -1022,7 +1022,7 @@ li { すべてのコンポーネントの props から `imageSize` を削除します。 -`Context.js` で `ImageSizeContext` を作成してエクスポートします。次に、List を `` でラップすることで下に値を渡します。`PlaceImage` で `useContext(ImageSizeContext)` を使ってそれを読み取ります。 +`Context.js` で `ImageSizeContext` を作成してエクスポートします。次に、List を `` でラップすることで下に値を渡します。`PlaceImage` で `useContext(ImageSizeContext)` を使ってそれを読み取ります。 @@ -1036,7 +1036,7 @@ export default function App() { const [isLarge, setIsLarge] = useState(false); const imageSize = isLarge ? 150 : 100; return ( -
      -
      +
      ) } diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index d2b979b4d..36c02eeb9 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -311,7 +311,7 @@ export default defineConfig({ ### Webpack {/*usage-with-webpack*/} -コミュニティによる Webpack ローダは[こちらで利用可能](https://github.com/SukkaW/react-compiler-webpack)です。 +コミュニティによる webpack ローダは[こちらで利用可能](https://github.com/SukkaW/react-compiler-webpack)です。 ### Expo {/*usage-with-expo*/} diff --git a/src/content/learn/react-developer-tools.md b/src/content/learn/react-developer-tools.md index 5694d46f9..ef3b1a576 100644 --- a/src/content/learn/react-developer-tools.md +++ b/src/content/learn/react-developer-tools.md @@ -54,7 +54,7 @@ react-devtools ## モバイル (React Native) {/*mobile-react-native*/} -[React Native](https://reactnative.dev/) で作成するアプリの調査を行う場合は、React Developer Tools と密に統合された組み込みデバッガである [React Native DevTools](https://reactnative.dev/docs/debugging/react-native-devtools) を使用できます。要素のハイライトや選択を含むすべての機能が、ブラウザ版の機能拡張と同様に動作します。 +[React Native](https://reactnative.dev/) で作成するアプリの調査を行う場合は、React Developer Tools と密に統合された組み込みデバッガである [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) を使用できます。要素のハイライトや選択を含むすべての機能が、ブラウザ版の機能拡張と同様に動作します。 [React Native のデバッグについてさらに読む](https://reactnative.dev/docs/debugging) diff --git a/src/content/learn/setup.md b/src/content/learn/setup.md new file mode 100644 index 000000000..70e91dd8a --- /dev/null +++ b/src/content/learn/setup.md @@ -0,0 +1,28 @@ +--- +title: セットアップ +--- + + +React はエディタ、TypeScript、ブラウザ拡張機能、コンパイラといったツールと連携します。このセクションでは環境セットアップの方法を説明します。 + + + +## エディタのセットアップ {/*editor-setup*/} + +[推奨エディタ](/learn/editor-setup)を確認し、React での作業に適したセットアップ方法を学びましょう。 + +## TypeScript の使用 {/*using-typescript*/} + +TypeScript は JavaScript のコードベースに型定義を追加する一般的な方法です。[React プロジェクトに TypeScript を組み込む方法を学びましょう](/learn/typescript)。 + +## React Developer Tools {/*react-developer-tools*/} + +React Developer Tools は React コンポーネントの調査を行い、props や state を編集し、パフォーマンスの問題を特定できるブラウザ拡張機能です。インストール方法は[こちら](learn/react-developer-tools)で確認できます。 + +## React Compiler {/*react-compiler*/} + +React Compiler は React アプリを自動的に最適化するツールです。[詳細はこちら](/learn/react-compiler)。 + +## 次のステップ {/*next-steps*/} + +[クイックスタート](/learn)ガイドに進んで、日常的に遭遇する最も重要な React の概念についてのツアーを始めましょう。 \ No newline at end of file diff --git a/src/content/learn/start-a-new-react-project.md b/src/content/learn/start-a-new-react-project.md deleted file mode 100644 index c35416975..000000000 --- a/src/content/learn/start-a-new-react-project.md +++ /dev/null @@ -1,130 +0,0 @@ ---- -title: React プロジェクトを始める ---- - - - -React だけで新しいアプリやウェブサイトを作りたい場合は、コミュニティで人気のある React フレームワークから、ひとつを選ぶことをおすすめします。 - - - - -フレームワークなしで React を使うことも可能ですが、ほとんどのアプリやサイトにおいては、コード分割、ルーティング、データ取得、HTML 生成といった問題に対処するための開発が必要であることが分かっています。これらは React に限らずあらゆる UI ライブラリに共通の問題です。 - -フレームワークを使ってスタートすることで React での開発を素早く立ち上げ、後で実質的に独自フレームワークのようなものを作ってしまわずに済むようになるでしょう。 - - - -#### フレームワークなしで React を使うことは可能? {/*can-i-use-react-without-a-framework*/} - -React をフレームワークなしで使うことも確かに可能です。[既存のページに React を追加する](/learn/add-react-to-an-existing-project#using-react-for-a-part-of-your-existing-page)場合はそのようにします。**しかし、新しいアプリやサイトをフルで React を使って構築する場合は、フレームワークを使用することをお勧めします。** - -理由は次のとおりです。 - -もし最初にルーティングやデータ取得が必要ない場合でも、後になってそれらのためにライブラリを追加する必要が出てくる可能性が高いでしょう。新しい機能が増えるたびに JavaScript バンドルは大きくなっていき、個々のルートごとにコードを分割する方法を考える必要があります。データ取得の要件が複雑になるにつれて、サーバ・クライアント間のネットワークウォーターフォールが原因となり、アプリは非常に遅く感じるようになるでしょう。低速なネットワーク環境やロースペックなデバイスのユーザが増えると、コンテンツをできるだけ早く表示するため、サーバ上であるいはビルド時に、コンポーネントから HTML を生成する必要が生じることがあるでしょう。後になってセットアップを変更し、サーバ上であるいはビルド時にあなたのコードの一部が実行されるようにすることは、非常に複雑な作業です。 - -**これらの問題は React に固有のものではありません。まさにこれが、Svelte には SvelteKit、Vue には Nuxt といったフレームワークが存在する理由です**。これらの問題を自力で解決するには、ルータやデータ取得ライブラリをバンドラに結合する作業を自分で行う必要があります。最初のセットアップをひとまず動作させることは難しくありませんが、時間が経ってアプリが成長してもなお素早く読み込めるサイトを作るためには、数々の細々とした問題に対処する必要が出てきます。アプリに必要な最小限のコードを 1 回のクライアント・サーバ間の往復で送信しつつ、並行してページ表示に必要なデータも送信したい、と思い始めるでしょう。ページが段階的に読み込まれ、JavaScript コードが実行すらされないうちから操作可能になるプログレッシブ・エンハンスメントのサポートが欲しくなるでしょう。どこにでもホストでき JavaScript が無効になっていても動作する、マーケティングページのための完全に静的な HTML ファイルが入ったフォルダを生成したい、と考え始めるでしょう。これらの機能を自分で構築するには、大変な労力が必要です。 - -**このページで紹介する React フレームワークは、これらの問題をデフォルトで解決しているため、あなたが余計な作業をする必要はありません**。これらのフレームワークを使用することで、非常にスリムに始めて、ニーズに応じてアプリをスケーリングできます。各 React フレームワークにはコミュニティがあるため、質問に対する回答を見つけたり、ツールのアップグレードをしたりすることもより簡単に行えます。フレームワークはあなたのコードに構造を与えるので、あなたや他の人が複数のプロジェクト間でコンテクストやスキルを保持するのにも役立ちます。逆に、カスタムセットアップを行った場合、サポートされなくなった依存関係バージョンにハマる可能性が高まり、いずれ実質的には独自フレームワークのようなものを作成する羽目に陥ります。ただしそのようなフレームワークにはコミュニティもアップグレードパスもなく、仮に過去に作成されていたものに近かったとしても、行き当たりばったりで設計されたものに過ぎないわけですが。 - -以下のフレームワークではうまく対処できない特殊な制約がある場合や、これらの問題に自分自身で対処したいという場合は、React で自分独自のカスタムセットアップを行うことも可能です。npm から `react` と `react-dom` を入手し、[Vite](https://vitejs.dev/) や [Parcel](https://parceljs.org/) のようなバンドラを使ってカスタムビルドプロセスをセットアップし、ルーティング、静的ファイル生成、サーバーサイドレンダリングなどのための各種ツールを必要に応じて追加していってください。 - - - -## 本番環境対応の React フレームワーク {/*production-grade-react-frameworks*/} - -以下に挙げるフレームワークは、アプリを本番環境でデプロイしスケールさせるために必要なすべての機能を備えており、我々の[フルスタックアーキテクチャ](#which-features-make-up-the-react-teams-full-stack-architecture-vision)の実現に向けて開発されています。ここでお勧めするフレームワークはすべてオープンソースであり、助けになる活発なコミュニティがあり、自分自身のサーバにもホスティングプロバイダにもデプロイできます。このリストに掲載を希望するフレームワークの作者は[お知らせください](https://github.com/reactjs/react.dev/issues/new?assignees=&labels=type%3A+framework&projects=&template=3-framework.yml&title=%5BFramework%5D%3A+)。 - -### Next.js {/*nextjs-pages-router*/} - -**[Next.js の Pages Router](https://nextjs.org/) はフルスタックの React フレームワークです**。ほぼ静的なブログサイトから複雑でダイナミックなアプリまで、どんな規模の React アプリでも作成できる万能フレームワークです。Next.js プロジェクトを新規に作るには、ターミナルで次のコマンドを実行してください。 - - -npx create-next-app@latest - - -Next.js を初めて使う場合は、[Next.js の学習コース](https://nextjs.org/learn)を参照してください。 - -Next.js は [Vercel](https://vercel.com/) によってメンテナンスされています。Next.js アプリは Node.js やサーバレスホスティングサービス、または自分自身のサーバーに[デプロイする](https://nextjs.org/docs/app/building-your-application/deploying)ことができます。Next.js はサーバを必要としない[静的なエクスポート](https://nextjs.org/docs/pages/building-your-application/deploying/static-exports)もサポートしています。 - -### Remix {/*remix*/} - -**[Remix](https://remix.run/) は、ネスト状のルーティングを備えたフルスタック React フレームワークです**。複雑なアプリを階層的に分割し、並列に読み込み、ユーザアクションに応じてリフレッシュすることができます。Remix プロジェクトを新規に作成するには、次のコマンドを実行します。 - - -npx create-remix - - -Remix を初めて使う場合は、Remix の[ブログ作成チュートリアル](https://remix.run/docs/en/main/tutorials/blog)(短い)や [アプリ作成チュートリアル](https://remix.run/docs/en/main/tutorials/jokes)(長い)を参照してください。 - -Remix は [Shopify](https://www.shopify.com/) によってメンテナンスされています。Remix アプリをデプロイするには、デプロイ先を[選択する必要があります](https://remix.run/docs/en/main/guides/deployment)。Remix アプリは、[アダプタ](https://remix.run/docs/en/main/other-api/adapter)を使用するか自分で書くことで、あらゆる Node.js またはサーバーレスホスティングにデプロイできます。 - -### Gatsby {/*gatsby*/} - -**[Gatsby](https://www.gatsbyjs.com/) は、CMS ベースで高速なサイトを作成するための React フレームワークです**。豊富なプラグインのエコシステムと GraphQL データレイヤーにより、コンテンツ、API、サービスの統合が簡素化されます。Gatsby プロジェクトを新規に作成するには、次のコマンドを実行します。 - - -npx create-gatsby - - -Gatsby を初めて使う場合は、[Gatsby チュートリアル](https://www.gatsbyjs.com/docs/tutorial/)を参照してください。 - -Gatsby は [Netlify](https://www.netlify.com/) によってメンテナンスされています。[完全に静的な Gatsby サイト](https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting) は、どんな静的なホスティングにもデプロイ可能です。サーバーサイド専用の機能を使用する場合は、ホスティングプロバイダが Gatsby に対応しているかどうか確認してください。 - -### Expo(ネイティブアプリ向け) {/*expo*/} - -**[Expo](https://expo.dev/) は、Android、iOS、およびウェブ向けに、真にネイティブな UI を持ったユニバーサルアプリを作成できる React フレームワークです**。[React Native](https://reactnative.dev/) 用の SDK を提供し、ネイティブなパーツの使用を簡素化します。Expo プロジェクトを新規に作成するには、次のコマンドを実行します。 - - -npx create-expo-app - - -Expo を初めて使う場合は、[Expo チュートリアル](https://docs.expo.dev/tutorial/introduction/)を参照してください。 - -Expo は [Expo(社名)](https://expo.dev/about) によってメンテナンスされています。Expo を使用してアプリをビルドすることは無料であり、Google や Apple のアプリストアに制限なくアップロードすることができます。また Expo では有料のクラウドサービスも提供しています。 - -## 超最先端の React フレームワーク {/*bleeding-edge-react-frameworks*/} - -我々が React の進化について探求する中で、React をフレームワークと(特にルーティング、バンドル作成、サーバテクノロジーと)より密接に統合することが、React ユーザがよりよいアプリを構築する手助けをするための最大の機会となるということに気づきました。Next.js チームは、[React Server Components](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components) のようなフレームワークに依存しない最先端の React 機能に関して、私たちと共同で研究、開発、統合、テストを行うことに同意しました。 - -これらの機能は、本番環境で使える段階へと日々近づいており、他のバンドラやフレームワーク開発者とも統合について話し合っています。私たちの希望は、このページにリストされているすべてのフレームワークが、1 年か 2 年のうちにこれらの機能を完全にサポートするようになることです。(あなたがフレームワーク作者で、これらの機能を実験するため我々と協力することに興味がある場合、ぜひご連絡ください!) - -### Next.js (App Router) {/*nextjs-app-router*/} - -**[Next.js の App Router](https://nextjs.org/docs) は、React チームのフルスタックアーキテクチャビジョンを実現するために再設計された Next.js の API です**。サーバ上で、あるいはビルド時に非同期コンポーネントからデータのフェッチが行えるようになります。 - -Next.js は [Vercel](https://vercel.com/) によってメンテナンスされています。[Next.js アプリのデプロイ](https://nextjs.org/docs/app/building-your-application/deploying)はあらゆる Next.js やサーバレスホスティングサービス上で行えます。Next.js は、サーバ不要の[静的エクスポート](https://nextjs.org/docs/app/building-your-application/deploying/static-exports)もサポートしています。 - - - -#### React チームのフルスタックアーキテクチャビジョンに含まれる機能 {/*which-features-make-up-the-react-teams-full-stack-architecture-vision*/} - -Next.js の App Router バンドラは、公式の [React Server Components 仕様](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md)を完全に実装しています。これにより単一の React ツリー内で、バンドル時専用コンポーネント、サーバ専用コンポーネント、インタラクティブなコンポーネントを混在させることができます。 - -例えば、データベースやファイルから読み込みを行う React コンポーネントを非同期 (`async`) 関数として記述できます。そしてそのデータをインタラクティブなコンポーネントに渡すこともできます: - -```js -// This component runs *only* on the server (or during the build). -async function Talks({ confId }) { - // 1. You're on the server, so you can talk to your data layer. API endpoint not required. - const talks = await db.Talks.findAll({ confId }); - - // 2. Add any amount of rendering logic. It won't make your JavaScript bundle larger. - const videos = talks.map(talk => talk.video); - - // 3. Pass the data down to the components that will run in the browser. - return ; -} -``` - -Next.js の App Router は、[サスペンス (suspense) を使用したデータフェッチ](/blog/2022/03/29/react-v18#suspense-in-data-frameworks)を統合しています。これにより、React ツリー内で直接、UI の様々な場所に表示されるロード中状態(スケルトンプレースホルダなど)を指定できるようになります: - -```js -}> - - -``` - -サーバコンポーネントとサスペンスは、Next.js の機能ではなく React の機能です。しかしフレームワークレベルでこれらを採用するには、合意形成とかなりの実装の手間が必要です。現時点では、Next.js の App Router が最も完全な実装です。React チームはバンドラの開発者と協力して、次世代のフレームワークでこれらの機能を実装しやすくすることを目指しています。 - - diff --git a/src/content/learn/state-a-components-memory.md b/src/content/learn/state-a-components-memory.md index 04e744704..3478ff014 100644 --- a/src/content/learn/state-a-components-memory.md +++ b/src/content/learn/state-a-components-memory.md @@ -1452,7 +1452,7 @@ export default function FeedbackForm() { #### 不要な state を削除 {/*remove-unnecessary-state*/} -この例では、ボタンがクリックされると、ユーザの名前を尋ねて、挨拶を表示するアラートが表示されるはずです。名前を保持するために state を使用しようとしましたが、何らかの理由で常に "Hello, !" と表示されます。 +この例では、ボタンがクリックされると、ユーザの名前を尋ねて、挨拶を表示するアラートが表示されるはずです。名前を保持するために state を使用しようとしましたが、なぜか最初は "Hello, !" と表示され、その後も "Hello, [name]!" という形で、ひとつ前の入力値が表示されてしまいます。 このコードを修正するには、不要な state 変数を削除してください([この問題が発生した理由](/learn/state-as-a-snapshot)については後で説明します)。 diff --git a/src/content/reference/react-dom/client/createRoot.md b/src/content/reference/react-dom/client/createRoot.md index e6f2c0774..e0c9c233c 100644 --- a/src/content/reference/react-dom/client/createRoot.md +++ b/src/content/reference/react-dom/client/createRoot.md @@ -144,7 +144,7 @@ root.render(); -```html index.html +```html public/index.html My app @@ -344,775 +344,127 @@ export default function App({counter}) { `render` を複数回呼び出すことは滅多にありません。通常、コンポーネントは代わりに [state の更新](/reference/react/useState)を行います。 -### キャッチされないエラーに対するダイアログを表示 {/*show-a-dialog-for-uncaught-errors*/} - -デフォルトでは React は、キャッチされなかったエラーをコンソールにログとして表示します。独自のエラーレポーティングを実装するには、省略可能なルートオプションである `onUncaughtError` を指定します。 - -```js [[1, 6, "onUncaughtError"], [2, 6, "error", 1], [3, 6, "errorInfo"], [4, 10, "componentStack"]] -import { createRoot } from 'react-dom/client'; +### 本番環境でのエラーのロギング {/*error-logging-in-production*/} -const root = createRoot( - document.getElementById('root'), - { - onUncaughtError: (error, errorInfo) => { - console.error( - 'Uncaught error', - error, - errorInfo.componentStack - ); - } - } -); -root.render(); -``` - -onUncaughtError オプションに指定するのは、以下の 2 つの引数を付けて呼ばれる関数です。 - -1. スローされた error。 -2. errorInfo オブジェクト。エラーの componentStack を含んでいる。 +デフォルトでは、React はすべてのエラーをコンソールに記録します。独自のエラーレポートの仕組みを実装するには、省略可能なルートオプションとして `onUncaughtError`、`onCaughtError`、`onRecoverableError` のエラーハンドラを提供することができます。 -エラーダイアログを表示するために `onUncaughtError` ルートオプションを用いることが可能です。 - - - -```html index.html hidden - - - - My app - - - - - -
      - - -``` - -```css src/styles.css active -label, button { display: block; margin-bottom: 20px; } -html, body { min-height: 300px; } - -#error-dialog { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-color: white; - padding: 15px; - opacity: 0.9; - text-wrap: wrap; - overflow: scroll; -} - -.text-red { - color: red; -} - -.-mb-20 { - margin-bottom: -20px; -} - -.mb-0 { - margin-bottom: 0; -} - -.mb-10 { - margin-bottom: 10px; -} - -pre { - text-wrap: wrap; -} - -pre.nowrap { - text-wrap: nowrap; -} - -.hidden { - display: none; -} -``` - -```js src/reportError.js hidden -function reportError({ title, error, componentStack, dismissable }) { - const errorDialog = document.getElementById("error-dialog"); - const errorTitle = document.getElementById("error-title"); - const errorMessage = document.getElementById("error-message"); - const errorBody = document.getElementById("error-body"); - const errorComponentStack = document.getElementById("error-component-stack"); - const errorStack = document.getElementById("error-stack"); - const errorClose = document.getElementById("error-close"); - const errorCause = document.getElementById("error-cause"); - const errorCauseMessage = document.getElementById("error-cause-message"); - const errorCauseStack = document.getElementById("error-cause-stack"); - const errorNotDismissible = document.getElementById("error-not-dismissible"); - - // Set the title - errorTitle.innerText = title; - - // Display error message and body - const [heading, body] = error.message.split(/\n(.*)/s); - errorMessage.innerText = heading; - if (body) { - errorBody.innerText = body; - } else { - errorBody.innerText = ''; - } - - // Display component stack - errorComponentStack.innerText = componentStack; - - // Display the call stack - // Since we already displayed the message, strip it, and the first Error: line. - errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1]; - - // Display the cause, if available - if (error.cause) { - errorCauseMessage.innerText = error.cause.message; - errorCauseStack.innerText = error.cause.stack; - errorCause.classList.remove('hidden'); - } else { - errorCause.classList.add('hidden'); - } - // Display the close button, if dismissible - if (dismissable) { - errorNotDismissible.classList.add('hidden'); - errorClose.classList.remove("hidden"); - } else { - errorNotDismissible.classList.remove('hidden'); - errorClose.classList.add("hidden"); - } - - // Show the dialog - errorDialog.classList.remove("hidden"); -} - -export function reportCaughtError({error, cause, componentStack}) { - reportError({ title: "Caught Error", error, componentStack, dismissable: true}); -} - -export function reportUncaughtError({error, cause, componentStack}) { - reportError({ title: "Uncaught Error", error, componentStack, dismissable: false }); -} - -export function reportRecoverableError({error, cause, componentStack}) { - reportError({ title: "Recoverable Error", error, componentStack, dismissable: true }); -} -``` - -```js src/index.js active +```js [[1, 6, "onCaughtError"], [2, 6, "error", 1], [3, 6, "errorInfo"], [4, 10, "componentStack", 15]] import { createRoot } from "react-dom/client"; -import App from "./App.js"; -import {reportUncaughtError} from "./reportError"; -import "./styles.css"; +import { reportCaughtError } from "./reportError"; const container = document.getElementById("root"); const root = createRoot(container, { - onUncaughtError: (error, errorInfo) => { - if (error.message !== 'Known error') { - reportUncaughtError({ + onCaughtError: (error, errorInfo) => { + if (error.message !== "Known error") { + reportCaughtError({ error, - componentStack: errorInfo.componentStack + componentStack: errorInfo.componentStack, }); } - } + }, }); -root.render(); -``` - -```js src/App.js -import { useState } from 'react'; - -export default function App() { - const [throwError, setThrowError] = useState(false); - - if (throwError) { - foo.bar = 'baz'; - } - - return ( -
      - This error shows the error dialog: - -
      - ); -} -``` - -
      - - -### エラーバウンダリでキャッチしたエラーを表示 {/*displaying-error-boundary-errors*/} - -デフォルトでは、React はエラーバウンダリによってキャッチされたすべてのエラーを `console.error` に記録します。この動作をオーバーライドするには、省略可能なルートオプションである `onCaughtError` を指定して、[エラーバウンダリ](/reference/react/Component#catching-rendering-errors-with-an-error-boundary)によってキャッチされたエラーを処理するようにします。 - -```js [[1, 6, "onCaughtError"], [2, 6, "error", 1], [3, 6, "errorInfo"], [4, 10, "componentStack"]] -import { createRoot } from 'react-dom/client'; - -const root = createRoot( - document.getElementById('root'), - { - onCaughtError: (error, errorInfo) => { - console.error( - 'Caught error', - error, - errorInfo.componentStack - ); - } - } -); -root.render(); ``` -onCaughtError オプションに指定するのは、以下の 2 つの引数を付けて呼ばれる関数です。 +onCaughtError は以下の 2 つの引数で呼びされる関数です。 -1. バウンダリによってキャッチされた error。 -2. errorInfo オブジェクト。当該エラーの componentStack を含んでいる。 +1. スローされた error。 +2. errorInfo オブジェクト。エラーの componentStack を含んでいる。 -`onCaughtError` ルートオプションを用いて、エラーダイアログを表示したり、既知のエラーをログから除外したりできます。 +`onUncaughtError` と `onRecoverableError` を組み合わせて、独自のエラーレポーティングのシステムを実装できます。 -```html index.html hidden - - - - My app - - - - - -
      - - -``` - -```css src/styles.css active -label, button { display: block; margin-bottom: 20px; } -html, body { min-height: 300px; } - -#error-dialog { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-color: white; - padding: 15px; - opacity: 0.9; - text-wrap: wrap; - overflow: scroll; -} - -.text-red { - color: red; -} - -.-mb-20 { - margin-bottom: -20px; -} - -.mb-0 { - margin-bottom: 0; -} - -.mb-10 { - margin-bottom: 10px; -} - -pre { - text-wrap: wrap; +```js src/reportError.js +function reportError({ type, error, errorInfo }) { + // The specific implementation is up to you. + // `console.error()` is only used for demonstration purposes. + console.error(type, error, "Component Stack: "); + console.error("Component Stack: ", errorInfo.componentStack); } -pre.nowrap { - text-wrap: nowrap; -} - -.hidden { - display: none; -} -``` - -```js src/reportError.js hidden -function reportError({ title, error, componentStack, dismissable }) { - const errorDialog = document.getElementById("error-dialog"); - const errorTitle = document.getElementById("error-title"); - const errorMessage = document.getElementById("error-message"); - const errorBody = document.getElementById("error-body"); - const errorComponentStack = document.getElementById("error-component-stack"); - const errorStack = document.getElementById("error-stack"); - const errorClose = document.getElementById("error-close"); - const errorCause = document.getElementById("error-cause"); - const errorCauseMessage = document.getElementById("error-cause-message"); - const errorCauseStack = document.getElementById("error-cause-stack"); - const errorNotDismissible = document.getElementById("error-not-dismissible"); - - // Set the title - errorTitle.innerText = title; - - // Display error message and body - const [heading, body] = error.message.split(/\n(.*)/s); - errorMessage.innerText = heading; - if (body) { - errorBody.innerText = body; - } else { - errorBody.innerText = ''; - } - - // Display component stack - errorComponentStack.innerText = componentStack; - - // Display the call stack - // Since we already displayed the message, strip it, and the first Error: line. - errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1]; - - // Display the cause, if available - if (error.cause) { - errorCauseMessage.innerText = error.cause.message; - errorCauseStack.innerText = error.cause.stack; - errorCause.classList.remove('hidden'); - } else { - errorCause.classList.add('hidden'); +export function onCaughtErrorProd(error, errorInfo) { + if (error.message !== "Known error") { + reportError({ type: "Caught", error, errorInfo }); } - // Display the close button, if dismissible - if (dismissable) { - errorNotDismissible.classList.add('hidden'); - errorClose.classList.remove("hidden"); - } else { - errorNotDismissible.classList.remove('hidden'); - errorClose.classList.add("hidden"); - } - - // Show the dialog - errorDialog.classList.remove("hidden"); } -export function reportCaughtError({error, cause, componentStack}) { - reportError({ title: "Caught Error", error, componentStack, dismissable: true}); +export function onUncaughtErrorProd(error, errorInfo) { + reportError({ type: "Uncaught", error, errorInfo }); } -export function reportUncaughtError({error, cause, componentStack}) { - reportError({ title: "Uncaught Error", error, componentStack, dismissable: false }); -} - -export function reportRecoverableError({error, cause, componentStack}) { - reportError({ title: "Recoverable Error", error, componentStack, dismissable: true }); +export function onRecoverableErrorProd(error, errorInfo) { + reportError({ type: "Recoverable", error, errorInfo }); } ``` ```js src/index.js active import { createRoot } from "react-dom/client"; import App from "./App.js"; -import {reportCaughtError} from "./reportError"; -import "./styles.css"; +import { + onCaughtErrorProd, + onRecoverableErrorProd, + onUncaughtErrorProd, +} from "./reportError"; const container = document.getElementById("root"); const root = createRoot(container, { - onCaughtError: (error, errorInfo) => { - if (error.message !== 'Known error') { - reportCaughtError({ - error, - componentStack: errorInfo.componentStack, - }); - } - } + // Keep in mind to remove these options in development to leverage + // React's default handlers or implement your own overlay for development. + // The handlers are only specfied unconditionally here for demonstration purposes. + onCaughtError: onCaughtErrorProd, + onRecoverableError: onRecoverableErrorProd, + onUncaughtError: onUncaughtErrorProd, }); root.render(); ``` ```js src/App.js -import { useState } from 'react'; -import { ErrorBoundary } from "react-error-boundary"; +import { Component, useState } from "react"; -export default function App() { - const [error, setError] = useState(null); - - function handleUnknown() { - setError("unknown"); - } - - function handleKnown() { - setError("known"); - } - - return ( - <> - { - setError(null); - }} - > - {error != null && } - This error will not show the error dialog: - - This error will show the error dialog: - - - - - ); +function Boom() { + foo.bar = "baz"; } -function fallbackRender({ resetErrorBoundary }) { - return ( -
      -

      Error Boundary

      -

      Something went wrong.

      - -
      - ); -} +class ErrorBoundary extends Component { + state = { hasError: false }; -function Throw({error}) { - if (error === "known") { - throw new Error('Known error') - } else { - foo.bar = 'baz'; + static getDerivedStateFromError(error) { + return { hasError: true }; } -} -``` -```json package.json hidden -{ - "dependencies": { - "react": "19.0.0-rc-3edc000d-20240926", - "react-dom": "19.0.0-rc-3edc000d-20240926", - "react-scripts": "^5.0.0", - "react-error-boundary": "4.0.3" - }, - "main": "/index.js" -} -``` - -
      - -### 復帰可能なエラーに対するダイアログを表示 {/*displaying-a-dialog-for-recoverable-errors*/} - -React はレンダー中にスローされたエラーから復帰するためにコンポーネントを自動的に再度レンダーすることがあります。成功すると、コンソールに復帰可能なエラーについてログを残し、開発者に通知します。この動作をオーバーライドするには、省略可能なルートオプションである `onRecoverableError` を指定します。 - -```js [[1, 6, "onRecoverableError"], [2, 6, "error", 1], [3, 10, "error.cause"], [4, 6, "errorInfo"], [5, 11, "componentStack"]] -import { createRoot } from 'react-dom/client'; - -const root = createRoot( - document.getElementById('root'), - { - onRecoverableError: (error, errorInfo) => { - console.error( - 'Recoverable error', - error, - error.cause, - errorInfo.componentStack, - ); + render() { + if (this.state.hasError) { + return

      Something went wrong.

      ; } + return this.props.children; } -); -root.render(); -``` - -onRecoverableError オプションに指定するのは、以下の 2 つの引数を付けて呼ばれる関数です。 - -1. React たスローした error。一部のエラーは元のエラーを error.cause として含んでいる。 -2. errorInfo オブジェクト。エラーの componentStack を含んでいる。 - -`onRecoverableError` を用いてエラーダイアログを表示することができます。 - - - -```html index.html hidden - - - - My app - - - - - -
      - - -``` - -```css src/styles.css active -label, button { display: block; margin-bottom: 20px; } -html, body { min-height: 300px; } - -#error-dialog { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-color: white; - padding: 15px; - opacity: 0.9; - text-wrap: wrap; - overflow: scroll; -} - -.text-red { - color: red; -} - -.-mb-20 { - margin-bottom: -20px; } -.mb-0 { - margin-bottom: 0; -} - -.mb-10 { - margin-bottom: 10px; -} - -pre { - text-wrap: wrap; -} - -pre.nowrap { - text-wrap: nowrap; -} - -.hidden { - display: none; -} -``` - -```js src/reportError.js hidden -function reportError({ title, error, componentStack, dismissable }) { - const errorDialog = document.getElementById("error-dialog"); - const errorTitle = document.getElementById("error-title"); - const errorMessage = document.getElementById("error-message"); - const errorBody = document.getElementById("error-body"); - const errorComponentStack = document.getElementById("error-component-stack"); - const errorStack = document.getElementById("error-stack"); - const errorClose = document.getElementById("error-close"); - const errorCause = document.getElementById("error-cause"); - const errorCauseMessage = document.getElementById("error-cause-message"); - const errorCauseStack = document.getElementById("error-cause-stack"); - const errorNotDismissible = document.getElementById("error-not-dismissible"); - - // Set the title - errorTitle.innerText = title; - - // Display error message and body - const [heading, body] = error.message.split(/\n(.*)/s); - errorMessage.innerText = heading; - if (body) { - errorBody.innerText = body; - } else { - errorBody.innerText = ''; - } - - // Display component stack - errorComponentStack.innerText = componentStack; - - // Display the call stack - // Since we already displayed the message, strip it, and the first Error: line. - errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1]; - - // Display the cause, if available - if (error.cause) { - errorCauseMessage.innerText = error.cause.message; - errorCauseStack.innerText = error.cause.stack; - errorCause.classList.remove('hidden'); - } else { - errorCause.classList.add('hidden'); - } - // Display the close button, if dismissible - if (dismissable) { - errorNotDismissible.classList.add('hidden'); - errorClose.classList.remove("hidden"); - } else { - errorNotDismissible.classList.remove('hidden'); - errorClose.classList.add("hidden"); - } - - // Show the dialog - errorDialog.classList.remove("hidden"); -} - -export function reportCaughtError({error, cause, componentStack}) { - reportError({ title: "Caught Error", error, componentStack, dismissable: true}); -} - -export function reportUncaughtError({error, cause, componentStack}) { - reportError({ title: "Uncaught Error", error, componentStack, dismissable: false }); -} - -export function reportRecoverableError({error, cause, componentStack}) { - reportError({ title: "Recoverable Error", error, componentStack, dismissable: true }); -} -``` - -```js src/index.js active -import { createRoot } from "react-dom/client"; -import App from "./App.js"; -import {reportRecoverableError} from "./reportError"; -import "./styles.css"; - -const container = document.getElementById("root"); -const root = createRoot(container, { - onRecoverableError: (error, errorInfo) => { - reportRecoverableError({ - error, - cause: error.cause, - componentStack: errorInfo.componentStack, - }); - } -}); -root.render(); -``` - -```js src/App.js -import { useState } from 'react'; -import { ErrorBoundary } from "react-error-boundary"; - -// 🚩 Bug: Never do this. This will force an error. -let errorThrown = false; export default function App() { + const [triggerUncaughtError, settriggerUncaughtError] = useState(false); + const [triggerCaughtError, setTriggerCaughtError] = useState(false); + return ( <> - - {!errorThrown && } -

      This component threw an error, but recovered during a second render.

      -

      Since it recovered, no Error Boundary was shown, but onRecoverableError was used to show an error dialog.

      -
      - + + {triggerUncaughtError && } + + {triggerCaughtError && ( + + + + )} ); } - -function fallbackRender() { - return ( -
      -

      Error Boundary

      -

      Something went wrong.

      -
      - ); -} - -function Throw({error}) { - // Simulate an external value changing during concurrent render. - errorThrown = true; - foo.bar = 'baz'; -} -``` - -```json package.json hidden -{ - "dependencies": { - "react": "19.0.0-rc-3edc000d-20240926", - "react-dom": "19.0.0-rc-3edc000d-20240926", - "react-scripts": "^5.0.0", - "react-error-boundary": "4.0.3" - }, - "main": "/index.js" -} ```
      - ---- ## トラブルシューティング {/*troubleshooting*/} ### ルートを作成したが何も表示されない {/*ive-created-a-root-but-nothing-is-displayed*/} diff --git a/src/content/reference/react-dom/client/hydrateRoot.md b/src/content/reference/react-dom/client/hydrateRoot.md index aa126b296..eb8e81427 100644 --- a/src/content/reference/react-dom/client/hydrateRoot.md +++ b/src/content/reference/react-dom/client/hydrateRoot.md @@ -270,7 +270,7 @@ export default function App() {
      -これは単一レベルの深さまでしか機能せず、避難ハッチとしての使用を意図しています。過度に使用しないでください。これを使用してもテキストコンテンツ以外の場合は React は違いを修正しようとはしないため、将来の更新まで一貫性が保たれない可能性があります。 +これは単一レベルの深さまでしか機能せず、避難ハッチとしての使用を意図しています。過度に使用しないでください。これを使用しても React はテキストコンテンツの不一致を修正しようとは**しません**。 --- @@ -374,555 +374,125 @@ export default function App({counter}) { ハイドレーションされたルートで [`root.render`](#root-render) を呼び出すことは滅多にありません。通常、代わりにコンポーネントの中で [state を更新](/reference/react/useState) します。 -### キャッチされないエラーに対するダイアログを表示 {/*show-a-dialog-for-uncaught-errors*/} +### 本番環境でのエラーのロギング {/*error-logging-in-production*/} -デフォルトでは React は、キャッチされなかったエラーをコンソールにログとして表示します。独自のエラーレポーティングを実装するには、省略可能なルートオプションである `onUncaughtError` を指定します。 +デフォルトでは、React はすべてのエラーをコンソールに記録します。独自のエラーレポートの仕組みを実装するには、省略可能なルートオプションとして `onUncaughtError`、`onCaughtError`、`onRecoverableError` のエラーハンドラを提供することができます。 -```js [[1, 7, "onUncaughtError"], [2, 7, "error", 1], [3, 7, "errorInfo"], [4, 11, "componentStack"]] -import { hydrateRoot } from 'react-dom/client'; +```js [[1, 6, "onCaughtError"], [2, 6, "error", 1], [3, 6, "errorInfo"], [4, 10, "componentStack", 15]] +import { hydrateRoot } from "react-dom/client"; +import { reportCaughtError } from "./reportError"; -const root = hydrateRoot( - document.getElementById('root'), - , - { - onUncaughtError: (error, errorInfo) => { - console.error( - 'Uncaught error', +const container = document.getElementById("root"); +const root = hydrateRoot(container, { + onCaughtError: (error, errorInfo) => { + if (error.message !== "Known error") { + reportCaughtError({ error, - errorInfo.componentStack - ); + componentStack: errorInfo.componentStack, + }); } - } -); -root.render(); + }, +}); ``` -onUncaughtError オプションに指定するのは、以下の 2 つの引数を付けて呼ばれる関数です。 +onCaughtError は以下の 2 つの引数で呼びされる関数です。 1. スローされた error。 2. errorInfo オブジェクト。エラーの componentStack を含んでいる。 -エラーダイアログを表示するために `onUncaughtError` ルートオプションを用いることが可能です。 +`onUncaughtError` と `onRecoverableError` を組み合わせて、独自のエラーレポーティングのシステムを実装できます。 -```html index.html hidden - - - - My app - - - - - -
      This error shows the error dialog:
      - - -``` - -```css src/styles.css active -label, button { display: block; margin-bottom: 20px; } -html, body { min-height: 300px; } - -#error-dialog { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-color: white; - padding: 15px; - opacity: 0.9; - text-wrap: wrap; - overflow: scroll; -} - -.text-red { - color: red; -} - -.-mb-20 { - margin-bottom: -20px; -} - -.mb-0 { - margin-bottom: 0; -} - -.mb-10 { - margin-bottom: 10px; +```js src/reportError.js +function reportError({ type, error, errorInfo }) { + // The specific implementation is up to you. + // `console.error()` is only used for demonstration purposes. + console.error(type, error, "Component Stack: "); + console.error("Component Stack: ", errorInfo.componentStack); } -pre { - text-wrap: wrap; -} - -pre.nowrap { - text-wrap: nowrap; -} - -.hidden { - display: none; -} -``` - -```js src/reportError.js hidden -function reportError({ title, error, componentStack, dismissable }) { - const errorDialog = document.getElementById("error-dialog"); - const errorTitle = document.getElementById("error-title"); - const errorMessage = document.getElementById("error-message"); - const errorBody = document.getElementById("error-body"); - const errorComponentStack = document.getElementById("error-component-stack"); - const errorStack = document.getElementById("error-stack"); - const errorClose = document.getElementById("error-close"); - const errorCause = document.getElementById("error-cause"); - const errorCauseMessage = document.getElementById("error-cause-message"); - const errorCauseStack = document.getElementById("error-cause-stack"); - const errorNotDismissible = document.getElementById("error-not-dismissible"); - - // Set the title - errorTitle.innerText = title; - - // Display error message and body - const [heading, body] = error.message.split(/\n(.*)/s); - errorMessage.innerText = heading; - if (body) { - errorBody.innerText = body; - } else { - errorBody.innerText = ''; - } - - // Display component stack - errorComponentStack.innerText = componentStack; - - // Display the call stack - // Since we already displayed the message, strip it, and the first Error: line. - errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1]; - - // Display the cause, if available - if (error.cause) { - errorCauseMessage.innerText = error.cause.message; - errorCauseStack.innerText = error.cause.stack; - errorCause.classList.remove('hidden'); - } else { - errorCause.classList.add('hidden'); - } - // Display the close button, if dismissible - if (dismissable) { - errorNotDismissible.classList.add('hidden'); - errorClose.classList.remove("hidden"); - } else { - errorNotDismissible.classList.remove('hidden'); - errorClose.classList.add("hidden"); +export function onCaughtErrorProd(error, errorInfo) { + if (error.message !== "Known error") { + reportError({ type: "Caught", error, errorInfo }); } - - // Show the dialog - errorDialog.classList.remove("hidden"); -} - -export function reportCaughtError({error, cause, componentStack}) { - reportError({ title: "Caught Error", error, componentStack, dismissable: true}); } -export function reportUncaughtError({error, cause, componentStack}) { - reportError({ title: "Uncaught Error", error, componentStack, dismissable: false }); +export function onUncaughtErrorProd(error, errorInfo) { + reportError({ type: "Uncaught", error, errorInfo }); } -export function reportRecoverableError({error, cause, componentStack}) { - reportError({ title: "Recoverable Error", error, componentStack, dismissable: true }); +export function onRecoverableErrorProd(error, errorInfo) { + reportError({ type: "Recoverable", error, errorInfo }); } ``` ```js src/index.js active import { hydrateRoot } from "react-dom/client"; import App from "./App.js"; -import {reportUncaughtError} from "./reportError"; -import "./styles.css"; -import {renderToString} from 'react-dom/server'; +import { + onCaughtErrorProd, + onRecoverableErrorProd, + onUncaughtErrorProd, +} from "./reportError"; const container = document.getElementById("root"); -const root = hydrateRoot(container, , { - onUncaughtError: (error, errorInfo) => { - if (error.message !== 'Known error') { - reportUncaughtError({ - error, - componentStack: errorInfo.componentStack - }); - } - } +hydrateRoot(container, , { + // Keep in mind to remove these options in development to leverage + // React's default handlers or implement your own overlay for development. + // The handlers are only specfied unconditionally here for demonstration purposes. + onCaughtError: onCaughtErrorProd, + onRecoverableError: onRecoverableErrorProd, + onUncaughtError: onUncaughtErrorProd, }); ``` ```js src/App.js -import { useState } from 'react'; - -export default function App() { - const [throwError, setThrowError] = useState(false); - - if (throwError) { - foo.bar = 'baz'; - } - - return ( -
      - This error shows the error dialog: - -
      - ); -} -``` - -
      - - -### エラーバウンダリでキャッチしたエラーを表示 {/*displaying-error-boundary-errors*/} - -デフォルトでは、React はエラーバウンダリによってキャッチされたすべてのエラーを `console.error` に記録します。この動作をオーバーライドするには、省略可能なルートオプションである `onCaughtError` を指定して、[エラーバウンダリ](/reference/react/Component#catching-rendering-errors-with-an-error-boundary)によってキャッチされたエラーを処理するようにします。 - -```js [[1, 7, "onCaughtError"], [2, 7, "error", 1], [3, 7, "errorInfo"], [4, 11, "componentStack"]] -import { hydrateRoot } from 'react-dom/client'; - -const root = hydrateRoot( - document.getElementById('root'), - , - { - onCaughtError: (error, errorInfo) => { - console.error( - 'Caught error', - error, - errorInfo.componentStack - ); - } - } -); -root.render(); -``` - -onCaughtError オプションに指定するのは、以下の 2 つの引数を付けて呼ばれる関数です。 - -1. バウンダリによってキャッチされた error。 -2. errorInfo オブジェクト。当該エラーの componentStack を含んでいる。 - -`onCaughtError` ルートオプションを用いて、エラーダイアログを表示したり、既知のエラーをログから除外したりできます。 - - - -```html index.html hidden - - - - My app - - - - - -
      This error will not show the error dialog:This error will show the error dialog:
      - - -``` - -```css src/styles.css active -label, button { display: block; margin-bottom: 20px; } -html, body { min-height: 300px; } - -#error-dialog { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-color: white; - padding: 15px; - opacity: 0.9; - text-wrap: wrap; - overflow: scroll; -} - -.text-red { - color: red; -} - -.-mb-20 { - margin-bottom: -20px; -} +import { Component, useState } from "react"; -.mb-0 { - margin-bottom: 0; +function Boom() { + foo.bar = "baz"; } -.mb-10 { - margin-bottom: 10px; -} - -pre { - text-wrap: wrap; -} - -pre.nowrap { - text-wrap: nowrap; -} - -.hidden { - display: none; -} -``` +class ErrorBoundary extends Component { + state = { hasError: false }; -```js src/reportError.js hidden -function reportError({ title, error, componentStack, dismissable }) { - const errorDialog = document.getElementById("error-dialog"); - const errorTitle = document.getElementById("error-title"); - const errorMessage = document.getElementById("error-message"); - const errorBody = document.getElementById("error-body"); - const errorComponentStack = document.getElementById("error-component-stack"); - const errorStack = document.getElementById("error-stack"); - const errorClose = document.getElementById("error-close"); - const errorCause = document.getElementById("error-cause"); - const errorCauseMessage = document.getElementById("error-cause-message"); - const errorCauseStack = document.getElementById("error-cause-stack"); - const errorNotDismissible = document.getElementById("error-not-dismissible"); - - // Set the title - errorTitle.innerText = title; - - // Display error message and body - const [heading, body] = error.message.split(/\n(.*)/s); - errorMessage.innerText = heading; - if (body) { - errorBody.innerText = body; - } else { - errorBody.innerText = ''; + static getDerivedStateFromError(error) { + return { hasError: true }; } - // Display component stack - errorComponentStack.innerText = componentStack; - - // Display the call stack - // Since we already displayed the message, strip it, and the first Error: line. - errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1]; - - // Display the cause, if available - if (error.cause) { - errorCauseMessage.innerText = error.cause.message; - errorCauseStack.innerText = error.cause.stack; - errorCause.classList.remove('hidden'); - } else { - errorCause.classList.add('hidden'); - } - // Display the close button, if dismissible - if (dismissable) { - errorNotDismissible.classList.add('hidden'); - errorClose.classList.remove("hidden"); - } else { - errorNotDismissible.classList.remove('hidden'); - errorClose.classList.add("hidden"); - } - - // Show the dialog - errorDialog.classList.remove("hidden"); -} - -export function reportCaughtError({error, cause, componentStack}) { - reportError({ title: "Caught Error", error, componentStack, dismissable: true}); -} - -export function reportUncaughtError({error, cause, componentStack}) { - reportError({ title: "Uncaught Error", error, componentStack, dismissable: false }); -} - -export function reportRecoverableError({error, cause, componentStack}) { - reportError({ title: "Recoverable Error", error, componentStack, dismissable: true }); -} -``` - -```js src/index.js active -import { hydrateRoot } from "react-dom/client"; -import App from "./App.js"; -import {reportCaughtError} from "./reportError"; -import "./styles.css"; - -const container = document.getElementById("root"); -const root = hydrateRoot(container, , { - onCaughtError: (error, errorInfo) => { - if (error.message !== 'Known error') { - reportCaughtError({ - error, - componentStack: errorInfo.componentStack - }); + render() { + if (this.state.hasError) { + return

      Something went wrong.

      ; } + return this.props.children; } -}); -``` - -```js src/App.js -import { useState } from 'react'; -import { ErrorBoundary } from "react-error-boundary"; +} export default function App() { - const [error, setError] = useState(null); - - function handleUnknown() { - setError("unknown"); - } + const [triggerUncaughtError, settriggerUncaughtError] = useState(false); + const [triggerCaughtError, setTriggerCaughtError] = useState(false); - function handleKnown() { - setError("known"); - } - return ( <> - { - setError(null); - }} - > - {error != null && } - This error will not show the error dialog: - - This error will show the error dialog: - - - + + {triggerUncaughtError && } + + {triggerCaughtError && ( + + + + )} ); } - -function fallbackRender({ resetErrorBoundary }) { - return ( -
      -

      Error Boundary

      -

      Something went wrong.

      - -
      - ); -} - -function Throw({error}) { - if (error === "known") { - throw new Error('Known error') - } else { - foo.bar = 'baz'; - } -} ``` -```json package.json hidden -{ - "dependencies": { - "react": "19.0.0-rc-3edc000d-20240926", - "react-dom": "19.0.0-rc-3edc000d-20240926", - "react-scripts": "^5.0.0", - "react-error-boundary": "4.0.3" - }, - "main": "/index.js" -} -``` - -
      - -### 復帰可能なハイドレーション不一致エラーに対するダイアログを表示 {/*show-a-dialog-for-recoverable-hydration-mismatch-errors*/} - -React がハイドレーション時に不一致を検出した場合、自動的にクライアント側でレンダーの復帰をを試みます。デフォルトでは、ハイドレーション不一致に関するエラーは `console.error` に記録されます。この動作をオーバーライドするには、省略可能なルートオプションである `onRecoverableError` を指定します。 - -```js [[1, 7, "onRecoverableError"], [2, 7, "error", 1], [3, 11, "error.cause", 1], [4, 7, "errorInfo"], [5, 12, "componentStack"]] -import { hydrateRoot } from 'react-dom/client'; - -const root = hydrateRoot( - document.getElementById('root'), - , - { - onRecoverableError: (error, errorInfo) => { - console.error( - 'Caught error', - error, - error.cause, - errorInfo.componentStack - ); - } - } -); -``` - -onRecoverableError オプションに指定するのは、以下の 2 つの引数を付けて呼ばれる関数です。 - -1. React たスローした error。一部のエラーは元のエラーを error.cause として含んでいる。 -2. errorInfo オブジェクト。エラーの componentStack を含んでいる。 - -`onRecoverableError` を用いてハイドレーション不一致に関するエラーダイアログを表示することができます。 - - - -```html index.html hidden +```html public/index.html hidden @@ -930,229 +500,15 @@ const root = hydrateRoot( - - -
      Server
      +
      Server content before hydration.
      ``` - -```css src/styles.css active -label, button { display: block; margin-bottom: 20px; } -html, body { min-height: 300px; } - -#error-dialog { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-color: white; - padding: 15px; - opacity: 0.9; - text-wrap: wrap; - overflow: scroll; -} - -.text-red { - color: red; -} - -.-mb-20 { - margin-bottom: -20px; -} - -.mb-0 { - margin-bottom: 0; -} - -.mb-10 { - margin-bottom: 10px; -} - -pre { - text-wrap: wrap; -} - -pre.nowrap { - text-wrap: nowrap; -} - -.hidden { - display: none; -} -``` - -```js src/reportError.js hidden -function reportError({ title, error, componentStack, dismissable }) { - const errorDialog = document.getElementById("error-dialog"); - const errorTitle = document.getElementById("error-title"); - const errorMessage = document.getElementById("error-message"); - const errorBody = document.getElementById("error-body"); - const errorComponentStack = document.getElementById("error-component-stack"); - const errorStack = document.getElementById("error-stack"); - const errorClose = document.getElementById("error-close"); - const errorCause = document.getElementById("error-cause"); - const errorCauseMessage = document.getElementById("error-cause-message"); - const errorCauseStack = document.getElementById("error-cause-stack"); - const errorNotDismissible = document.getElementById("error-not-dismissible"); - - // Set the title - errorTitle.innerText = title; - - // Display error message and body - const [heading, body] = error.message.split(/\n(.*)/s); - errorMessage.innerText = heading; - if (body) { - errorBody.innerText = body; - } else { - errorBody.innerText = ''; - } - - // Display component stack - errorComponentStack.innerText = componentStack; - - // Display the call stack - // Since we already displayed the message, strip it, and the first Error: line. - errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1]; - - // Display the cause, if available - if (error.cause) { - errorCauseMessage.innerText = error.cause.message; - errorCauseStack.innerText = error.cause.stack; - errorCause.classList.remove('hidden'); - } else { - errorCause.classList.add('hidden'); - } - // Display the close button, if dismissible - if (dismissable) { - errorNotDismissible.classList.add('hidden'); - errorClose.classList.remove("hidden"); - } else { - errorNotDismissible.classList.remove('hidden'); - errorClose.classList.add("hidden"); - } - - // Show the dialog - errorDialog.classList.remove("hidden"); -} - -export function reportCaughtError({error, cause, componentStack}) { - reportError({ title: "Caught Error", error, componentStack, dismissable: true}); -} - -export function reportUncaughtError({error, cause, componentStack}) { - reportError({ title: "Uncaught Error", error, componentStack, dismissable: false }); -} - -export function reportRecoverableError({error, cause, componentStack}) { - reportError({ title: "Recoverable Error", error, componentStack, dismissable: true }); -} -``` - -```js src/index.js active -import { hydrateRoot } from "react-dom/client"; -import App from "./App.js"; -import {reportRecoverableError} from "./reportError"; -import "./styles.css"; - -const container = document.getElementById("root"); -const root = hydrateRoot(container, , { - onRecoverableError: (error, errorInfo) => { - reportRecoverableError({ - error, - cause: error.cause, - componentStack: errorInfo.componentStack - }); - } -}); -``` - -```js src/App.js -import { useState } from 'react'; -import { ErrorBoundary } from "react-error-boundary"; - -export default function App() { - const [error, setError] = useState(null); - - function handleUnknown() { - setError("unknown"); - } - - function handleKnown() { - setError("known"); - } - - return ( - {typeof window !== 'undefined' ? 'Client' : 'Server'} - ); -} - -function fallbackRender({ resetErrorBoundary }) { - return ( -
      -

      Error Boundary

      -

      Something went wrong.

      - -
      - ); -} - -function Throw({error}) { - if (error === "known") { - throw new Error('Known error') - } else { - foo.bar = 'baz'; - } -} -``` - -```json package.json hidden -{ - "dependencies": { - "react": "19.0.0-rc-3edc000d-20240926", - "react-dom": "19.0.0-rc-3edc000d-20240926", - "react-scripts": "^5.0.0", - "react-error-boundary": "4.0.3" - }, - "main": "/index.js" -} -``` -
      -## Troubleshooting {/*troubleshooting*/} +## トラブルシューティング {/*troubleshooting*/} ### "You passed a second argument to root.render" というエラーが出る {/*im-getting-an-error-you-passed-a-second-argument-to-root-render*/} diff --git a/src/content/reference/react-dom/components/form.md b/src/content/reference/react-dom/components/form.md index 4c3437513..8f3daa6c7 100644 --- a/src/content/reference/react-dom/components/form.md +++ b/src/content/reference/react-dom/components/form.md @@ -214,7 +214,7 @@ export default function App() { ]); async function sendMessage(formData) { const sentMessage = await deliverMessage(formData.get("message")); - setMessages([...messages, { text: sentMessage }]); + setMessages((messages) => [...messages, { text: sentMessage }]); } return ; } diff --git a/src/content/reference/react-dom/components/input.md b/src/content/reference/react-dom/components/input.md index 39f8b410f..44ee0ac61 100644 --- a/src/content/reference/react-dom/components/input.md +++ b/src/content/reference/react-dom/components/input.md @@ -297,7 +297,7 @@ input { margin: 5px; } -デフォルトでは、`
      ` 内の*あらゆる* `