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..ff2caa1bf --- /dev/null +++ b/.github/workflows/discord_notify.yml @@ -0,0 +1,21 @@ +name: Discord Notify + +on: + pull_request_target: + types: [ labeled ] + +jobs: + notify: + if: ${{ github.event.label.name == 'React Core Team' }} + 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 }} \ No newline at end of file diff --git a/README.md b/README.md index 9a1ed59fe..dcd3e85bf 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This repo contains the source code and documentation powering [de.react.dev](htt ### Prerequisites 1. Git -1. Node: any 12.x version starting with v12.0.0 or greater +1. Node: any version starting with v16.8.0 or greater 1. Yarn: See [Yarn website for installation instructions](https://yarnpkg.com/lang/en/docs/install/) 1. A fork of the repo (for any contributions) 1. A clone of the [de.react.dev repo](https://github.com/reactjs/de.react.dev) on your local machine 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 ad9b9baa4..07e6136e6 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" }, @@ -33,12 +33,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" }, @@ -54,13 +54,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", @@ -68,6 +69,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", @@ -78,7 +80,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", @@ -94,7 +95,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" }, @@ -109,5 +110,6 @@ "lint-staged": { "*.{js,ts,jsx,tsx,css}": "yarn prettier", "src/**/*.md": "yarn fix-headings" - } + }, + "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/lauren.jpg b/public/images/team/lauren.jpg index cb08b9725..26d46bd2f 100644 Binary files a/public/images/team/lauren.jpg and b/public/images/team/lauren.jpg 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 c0addc751..ae536fd4e 100644 --- a/src/components/MDX/CodeBlock/CodeBlock.tsx +++ b/src/components/MDX/CodeBlock/CodeBlock.tsx @@ -291,7 +291,7 @@ function getSyntaxHighlight(theme: any): HighlightStyle { function getLineDecorators( code: string, - meta: string + meta?: string ): Array<{ line: number; className: string; @@ -311,7 +311,7 @@ function getLineDecorators( function getInlineDecorators( code: string, - meta: string + meta?: string ): Array<{ step: number; line: number; 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 0e22c7921..f24fac598 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..a49aa728e 100644 --- a/src/components/MDX/TeamMember.tsx +++ b/src/components/MDX/TeamMember.tsx @@ -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 b38853494..b0bc9f558 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 has been a long year. As it comes to an end we wanted to share a special Holiday Update on our research into zero-bundle-size React Server Components. --- -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 42843cc42..bed24396d 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: The React team is excited to share a few updates. We’ve started work on the React 18 release, which will be our next major version. We’ve created a Working Group to prepare the community for gradual adoption of new features in React 18. We’ve published a React 18 Alpha so that library authors can try it and provide feedback... --- -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 1806c757f..c9e75ff7b 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 @@ This was our first year planning a conference ourselves, and we have a lot of pe First, thanks to all of our speakers [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), and [Xuan Huang (黄玄)](https://twitter.com/Huxpro). -Thanks to everyone who helped provide feedback on talks including [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), and [Tim Yung](https://twitter.com/yungsters). +Thanks to everyone who helped provide feedback on talks including [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), and [Tim Yung](https://twitter.com/yungsters). Thanks to [Lauren Tan](https://twitter.com/potetotes) for setting up the conference Discord and serving as our Discord admin. 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 134990991..80fcb78e6 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 was years in the making, and with it brought valuable lessons for the React team. Its release was the result of many years of research and exploring many paths. Some of those paths were successful; many more were dead-ends that led to new insights. One lesson we’ve learned is that it’s frustrating for the community to wait for new features without having insight into these paths that we’re exploring. --- -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) --- 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 c4da2b61f..f971ddafa 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: Today we are thrilled to launch react.dev, the new home for React and its documentation. In this post, we would like to give you a tour of the new site. --- -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 @@ We think there's never been a better time to learn React. ## Who worked on this? {/*who-worked-on-this*/} -On the React team, [Rachel Nabors](https://twitter.com/rachelnabors/) led the project (and provided the illustrations), and [Dan Abramov](https://twitter.com/dan_abramov) designed the curriculum. They co-authored most of the content together as well. +On the React team, [Rachel Nabors](https://twitter.com/rachelnabors/) led the project (and provided the illustrations), and [Dan Abramov](https://bsky.app/profile/danabra.mov) designed the curriculum. They co-authored most of the content together as well. Of course, no project this large happens in isolation. We have a lot of people to thank! 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 aeb677f31..1bc78149d 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 @@ The Transition Tracing API lets you detect when [React Transitions](/reference/r * * * In addition to this update, our team has made recent guest appearances on community podcasts and livestreams to speak more on our work and answer questions. -* [Dan Abramov](https://twitter.com/dan_abramov) and [Joe Savona](https://twitter.com/en_JS) were interviewed by [Kent C. Dodds on his YouTube channel](https://www.youtube.com/watch?v=h7tur48JSaw), where they discussed concerns around React Server Components. -* [Dan Abramov](https://twitter.com/dan_abramov) and [Joe Savona](https://twitter.com/en_JS) were guests on the [JSParty podcast](https://jsparty.fm/267) and shared their thoughts about the future of React. +* [Dan Abramov](https://bsky.app/profile/danabra.mov) and [Joe Savona](https://twitter.com/en_JS) were interviewed by [Kent C. Dodds on his YouTube channel](https://www.youtube.com/watch?v=h7tur48JSaw), where they discussed concerns around React Server Components. +* [Dan Abramov](https://bsky.app/profile/danabra.mov) and [Joe Savona](https://twitter.com/en_JS) were guests on the [JSParty podcast](https://jsparty.fm/267) and shared their thoughts about the future of React. -Thanks to [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), and [Sophie Alpert](https://twitter.com/sophiebits) for reviewing this post. +Thanks to [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), and [Sophie Alpert](https://twitter.com/sophiebits) for reviewing this post. Thanks for reading, and see you in the next update! diff --git a/src/content/blog/2023/05/03/react-canaries.md b/src/content/blog/2023/05/03/react-canaries.md index 19d9960b0..c2e1a823e 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: We'd like to offer the React community an option to adopt individual new features as soon as their design is close to final, before they're released in a stable version--similar to how Meta has long used bleeding-edge versions of React internally. We are introducing a new officially supported [Canary release channel](/community/versioning-policy#canary-channel). It lets curated setups like frameworks decouple adoption of individual React features from the React release schedule. --- -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 fee21f4ec..ffe761624 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: In React Labs posts, we write about projects in active research and development. We’ve made significant progress since our last update, and we’d like to share our progress. --- -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 fd160e943..fbc4e378c 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 @@ -113,7 +113,7 @@ This will run the following codemods from `react-codemod`: - [`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`](TODO) +- [`prop-types-typescript`](https://codemod.com/registry/react-prop-types-typescript) This does not include the TypeScript changes. See [TypeScript changes](#typescript-changes) below. 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 bc77f4bbb..7cb7d42ee 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 @@ Next in the keynote, [Josh Story](https://twitter.com/joshcstory) and [Andrew Cl - [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) Finally, we ended the keynote with [Joe Savona](https://twitter.com/en_JS), [Sathya Gunasekaran](https://twitter.com/_gsathya), and [Mofei Zhang](https://twitter.com/zmofei) announcing that the React Compiler is now [Open Source](https://github.com/facebook/react/pull/29061), and sharing an experimental version of the React Compiler to try out. diff --git a/src/content/blog/2024/12/05/react-19.md b/src/content/blog/2024/12/05/react-19.md index 9f212209b..62a6ce464 100644 --- a/src/content/blog/2024/12/05/react-19.md +++ b/src/content/blog/2024/12/05/react-19.md @@ -17,7 +17,7 @@ Additions since this post was originally shared with the React 19 RC in April: - **Pre-warming for suspended trees**: see [Improvements to Suspense](/blog/2024/04/25/react-19-upgrade-guide#improvements-to-suspense). - **React DOM static APIs**: see [New React DOM Static APIs](#new-react-dom-static-apis). -_The date for this post has been update to reflect the stable release date._ +_The date for this post has been updated to reflect the stable release date._ @@ -362,7 +362,7 @@ React 19 includes all of the React Server Components features included from the #### How do I build support for Server Components? {/*how-do-i-build-support-for-server-components*/} -While React Server Components in React 19 are stable and will not break between major versions, the underlying APIs used to implement a React Server Components bundler or framework do not follow semver and may break between minors in React 19.x. +While React Server Components in React 19 are stable and will not break between minor versions, the underlying APIs used to implement a React Server Components bundler or framework do not follow semver and may break between minors in React 19.x. To support React Server Components as a bundler or framework, we recommend pinning to a specific React version, or using the Canary release. We will continue working with bundlers and frameworks to stabilize the APIs used to implement React Server Components in the future. @@ -807,4 +807,4 @@ Thanks to [Joey Arhar](https://github.com/josepharhar) for driving the design an #### How to upgrade {/*how-to-upgrade*/} See the [React 19 Upgrade Guide](/blog/2024/04/25/react-19-upgrade-guide) for step-by-step instructions and a full list of breaking and notable changes. -_Note: this post was originally published 04/25/2024 and has been updated to 12/05/2024 with the stable release._ \ No newline at end of file +_Note: this post was originally published 04/25/2024 and has been updated to 12/05/2024 with the stable release._ diff --git a/src/content/community/conferences.md b/src/content/community/conferences.md index aaa761218..6d84dfe3f 100644 --- a/src/content/community/conferences.md +++ b/src/content/community/conferences.md @@ -10,62 +10,89 @@ Do you know of a local React.js conference? Add it here! (Please keep the list c ## Upcoming Conferences {/*upcoming-conferences*/} -### React Universe Conf 2024 {/*react-universe-conf-2024*/} -September 5-6, 2024. Wrocław, Poland. +### React Paris 2025 {/*react-paris-2025*/} +March 20 - 21, 2024. In-person in Paris, France (hybrid event) -[Website](https://www.reactuniverseconf.com/) - [Twitter](https://twitter.com/react_native_eu) - [LinkedIn](https://www.linkedin.com/events/reactuniverseconf7163919537074118657/) +[Website](https://react.paris/) - [Twitter](https://x.com/BeJS_) -### React Alicante 2024 {/*react-alicante-2024*/} -September 19-21, 2024. Alicante, Spain. +### App.js Conf 2025 {/*appjs-conf-2025*/} +May 28 - 30, 2025. In-person in Kraków, Poland + remote -[Website](https://reactalicante.es/) - [Twitter](https://twitter.com/ReactAlicante) - [YouTube](https://www.youtube.com/channel/UCaSdUaITU1Cz6PvC97A7e0w) +[Website](https://appjs.co) - [Twitter](https://twitter.com/appjsconf) -### RenderCon Kenya 2024 {/*rendercon-kenya-2024*/} -October 04 - 05, 2024. Nairobi, Kenya +### React Summit 2025 {/*react-summit-2025*/} +June 13 - 17, 2025. In-person in Amsterdam, Netherlands + remote (hybrid event) -[Website](https://rendercon.org/) - [Twitter](https://twitter.com/renderconke) - [LinkedIn](https://www.linkedin.com/company/renderconke/) - [YouTube](https://www.youtube.com/channel/UC0bCcG8gHUL4njDOpQGcMIA) +[Website](https://reactsummit.com/) - [Twitter](https://x.com/reactsummit) -### React India 2024 {/*react-india-2024*/} -October 17 - 19, 2024. In-person in Goa, India (hybrid event) + Oct 15 2024 - remote day +### 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) -### 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) +## Past Conferences {/*past-conferences*/} -### reactjsday 2024 {/*reactjsday-2024*/} -October 25, 2024. In-person in Verona, Italy + online (hybrid event) +### React Day Berlin 2024 {/*react-day-berlin-2024*/} +December 13 & 16, 2024. In-person in Berlin, Germany + remote (hybrid event) -[Website](https://2024.reactjsday.it/) - [Twitter](https://x.com/reactjsday) - [Facebook](https://www.facebook.com/GrUSP/) - [YouTube](https://www.youtube.com/c/grusp) +[Website](https://reactday.berlin/) - [Twitter](https://x.com/reactdayberlin) -### React Advanced London 2024 {/*react-advanced-london-2024*/} -October 25 & 28, 2024. In-person in London, UK + online (hybrid event) +### React Africa 2024 {/*react-africa-2024*/} +November 29, 2024. In-person in Casablanca, Morocco (hybrid event) -[Website](https://reactadvanced.com/) - [Twitter](https://x.com/reactadvanced) +[Website](https://react-africa.com/) - [Twitter](https://x.com/BeJS_) + +### React Summit US 2024 {/*react-summit-us-2024*/} +November 19 & 22, 2024. In-person in New York, USA + online (hybrid event) + +[Website](https://reactsummit.us/) - [Twitter](https://twitter.com/reactsummit) - [Videos](https://portal.gitnation.org/) ### React Native London Conf 2024 {/*react-native-london-2024*/} November 14 & 15, 2024. In-person in London, UK [Website](https://reactnativelondon.co.uk/) - [Twitter](https://x.com/RNLConf) -### React Summit US 2024 {/*react-summit-us-2024*/} -November 19 & 22, 2024. In-person in New York, USA + online (hybrid event) +### React Advanced London 2024 {/*react-advanced-london-2024*/} +October 25 & 28, 2024. In-person in London, UK + online (hybrid event) -[Website](https://reactsummit.us/) - [Twitter](https://twitter.com/reactsummit) - [Videos](https://portal.gitnation.org/) +[Website](https://reactadvanced.com/) - [Twitter](https://x.com/reactadvanced) -### React Africa 2024 {/*react-africa-2024*/} -November 29, 2024. In-person in Casablanca, Morocco (hybrid event) +### reactjsday 2024 {/*reactjsday-2024*/} +October 25, 2024. In-person in Verona, Italy + online (hybrid event) -[Website](https://react-africa.com/) - [Twitter](https://x.com/BeJS_) +[Website](https://2024.reactjsday.it/) - [Twitter](https://x.com/reactjsday) - [Facebook](https://www.facebook.com/GrUSP/) - [YouTube](https://www.youtube.com/c/grusp) -### React Day Berlin 2024 {/*react-day-berlin-2024*/} -December 13 & 16, 2024. In-person in Berlin, Germany + remote (hybrid event) +### React Brussels 2024 {/*react-brussels-2024*/} +October 18, 2024. In-person in Brussels, Belgium (hybrid event) -[Website](https://reactday.berlin/) - [Twitter](https://x.com/reactdayberlin) +[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 + +[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) + +### RenderCon Kenya 2024 {/*rendercon-kenya-2024*/} +October 04 - 05, 2024. Nairobi, Kenya + +[Website](https://rendercon.org/) - [Twitter](https://twitter.com/renderconke) - [LinkedIn](https://www.linkedin.com/company/renderconke/) - [YouTube](https://www.youtube.com/channel/UC0bCcG8gHUL4njDOpQGcMIA) + +### React Alicante 2024 {/*react-alicante-2024*/} +September 19-21, 2024. Alicante, Spain. + +[Website](https://reactalicante.es/) - [Twitter](https://twitter.com/ReactAlicante) - [YouTube](https://www.youtube.com/channel/UCaSdUaITU1Cz6PvC97A7e0w) + +### React Universe Conf 2024 {/*react-universe-conf-2024*/} +September 5-6, 2024. Wrocław, Poland. + +[Website](https://www.reactuniverseconf.com/) - [Twitter](https://twitter.com/react_native_eu) - [LinkedIn](https://www.linkedin.com/events/reactuniverseconf7163919537074118657/) -## Past Conferences {/*past-conferences*/} ### React Rally 2024 🐙 {/*react-rally-2024*/} August 12-13, 2024. Park City, UT, USA diff --git a/src/content/community/docs-contributors.md b/src/content/community/docs-contributors.md index 0f9d002d6..27b32a18f 100644 --- a/src/content/community/docs-contributors.md +++ b/src/content/community/docs-contributors.md @@ -11,7 +11,7 @@ React documentation is written and maintained by the [React team](/community/tea ## 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 documentation is written and maintained by the [React team](/community/tea * [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/team.md b/src/content/community/team.md index b11925407..94f31f09f 100644 --- a/src/content/community/team.md +++ b/src/content/community/team.md @@ -43,7 +43,7 @@ Current members of the React team are listed in alphabetical order below. - Lauren's programming career peaked when she first discovered the `` tag. She’s been chasing that high ever since. She studied Finance instead of CS in college, so she learned to code using Excel instead of Java. Lauren enjoys dropping cheeky memes in chat, playing video games with her partner, and petting her dog Zelda. + Lauren's programming career peaked when she first discovered the `` tag. She’s been chasing that high ever since. She studied Finance instead of CS in college, so she learned to code using Excel. Lauren enjoys dropping cheeky memes in chat, playing video games with her partner, learning Korean, and petting her dog Zelda. 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 a99154584..64900f738 100644 --- a/src/content/learn/add-react-to-an-existing-project.md +++ b/src/content/learn/add-react-to-an-existing-project.md @@ -22,7 +22,7 @@ Routen, die mit `example.com/deine-app/` beginnen, vollständig mit React implem In diesem Fall empfehlen wir dir folgende Schritte: 1. **Erstelle den Teil der App, die mit React umgesetzt werden soll**, indem du eines der [auf React basierenden Frameworks](/learn/start-a-new-react-project) verwendest. -2. **Definiere `/deine-app` als *base path*** in der Konfiguration deines Frameworks ( [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/)). +2. **Definiere `/deine-app` als *base path*** in der Konfiguration deines Frameworks ( [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. **Konfiguriere deinen Server oder Proxy** so, dass alle Anfragen an `/deine-app/` von der React-Anwendung verarbeitet werden. Damit ist sichergestellt, dass der React Teil der Anwendung von den [bewährten Praktiken](/learn/start-a-new-react-project#can-i-use-react-without-a-framework) profitieren kann, die in diese Frameworks eingebaut sind. @@ -58,12 +58,13 @@ Füge danach diese Zeilen am Anfang deiner primären JavaScript-Datei (vermutlic -```html index.html hidden +```html public/index.html hidden Meine App +
      ``` @@ -121,7 +122,7 @@ Das ermöglicht dir das HTML-Element mit [`document.getElementById`](https://dev -```html index.html +```html public/index.html Meine App diff --git a/src/content/learn/index.md b/src/content/learn/index.md index 405cb8f22..e6f29671b 100644 --- a/src/content/learn/index.md +++ b/src/content/learn/index.md @@ -4,7 +4,7 @@ title: Schnelleinstieg -Willkommen bei der React Dokumentation! Diese Seite gibt dir eine Einführung in die wichtigsten React-Konzepte, die du täglich verwenden wirst. +Willkommen bei der React-Dokumentation! Diese Seite gibt dir eine Einführung in 80% der React-Konzepte, die du täglich verwenden wirst. diff --git a/src/content/learn/manipulating-the-dom-with-refs.md b/src/content/learn/manipulating-the-dom-with-refs.md index 6d20232fb..e366ea7cc 100644 --- a/src/content/learn/manipulating-the-dom-with-refs.md +++ b/src/content/learn/manipulating-the-dom-with-refs.md @@ -343,75 +343,39 @@ Read more about [how this helps find bugs](/reference/react/StrictMode#fixing-bu ## Accessing another component's DOM nodes {/*accessing-another-components-dom-nodes*/} -When you put a ref on a built-in component that outputs a browser element like ``, React will set that ref's `current` property to the corresponding DOM node (such as the actual `` in the browser). + +Refs are an escape hatch. Manually manipulating _another_ component's DOM nodes can make your code fragile. + -However, if you try to put a ref on **your own** component, like ``, by default you will get `null`. Here is an example demonstrating it. Notice how clicking the button **does not** focus the input: +You can pass refs from parent component to child components [just like any other prop](/learn/passing-props-to-a-component). - - -```js +```js {3-4,9} import { useRef } from 'react'; -function MyInput(props) { - return ; +function MyInput({ ref }) { + return ; } -export default function MyForm() { +function MyForm() { const inputRef = useRef(null); - - function handleClick() { - inputRef.current.focus(); - } - - return ( - <> - - - - ); + return } ``` - - -To help you notice the issue, React also prints an error to the console: - - - -Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()? - - - -This happens because by default React does not let a component access the DOM nodes of other components. Not even for its own children! This is intentional. Refs are an escape hatch that should be used sparingly. Manually manipulating _another_ component's DOM nodes makes your code even more fragile. - -Instead, components that _want_ to expose their DOM nodes have to **opt in** to that behavior. A component can specify that it "forwards" its ref to one of its children. Here's how `MyInput` can use the `forwardRef` API: - -```js -const MyInput = forwardRef((props, ref) => { - return ; -}); -``` - -This is how it works: - -1. `` tells React to put the corresponding DOM node into `inputRef.current`. However, it's up to the `MyInput` component to opt into that--by default, it doesn't. -2. The `MyInput` component is declared using `forwardRef`. **This opts it into receiving the `inputRef` from above as the second `ref` argument** which is declared after `props`. -3. `MyInput` itself passes the `ref` it received to the `` inside of it. +In the above example, a ref is created in the parent component, `MyForm`, and is passed to the child component, `MyInput`. `MyInput` then passes the ref to ``. Because `` is a [built-in component](/reference/react-dom/components/common) React sets the `.current` property of the ref to the `` DOM element. -Now clicking the button to focus the input works: +The `inputRef` created in `MyForm` now points to the `` DOM element returned by `MyInput`. A click handler created in `MyForm` can access `inputRef` and call `focus()` to set the focus on ``. ```js -import { forwardRef, useRef } from 'react'; +import { useRef } from 'react'; -const MyInput = forwardRef((props, ref) => { - return ; -}); +function MyInput({ ref }) { + return ; +} -export default function Form() { +export default function MyForm() { const inputRef = useRef(null); function handleClick() { @@ -431,24 +395,18 @@ export default function Form() { -In design systems, it is a common pattern for low-level components like buttons, inputs, and so on, to forward their refs to their DOM nodes. On the other hand, high-level components like forms, lists, or page sections usually won't expose their DOM nodes to avoid accidental dependencies on the DOM structure. - #### Exposing a subset of the API with an imperative handle {/*exposing-a-subset-of-the-api-with-an-imperative-handle*/} -In the above example, `MyInput` exposes the original DOM input element. This lets the parent component call `focus()` on it. However, this also lets the parent component do something else--for example, change its CSS styles. In uncommon cases, you may want to restrict the exposed functionality. You can do that with `useImperativeHandle`: +In the above example, the ref passed to `MyInput` is passed on to the original DOM input element. This lets the parent component call `focus()` on it. However, this also lets the parent component do something else--for example, change its CSS styles. In uncommon cases, you may want to restrict the exposed functionality. You can do that with [`useImperativeHandle`](/reference/react/useImperativeHandle): ```js -import { - forwardRef, - useRef, - useImperativeHandle -} from 'react'; +import { useRef, useImperativeHandle } from "react"; -const MyInput = forwardRef((props, ref) => { +function MyInput({ ref }) { const realInputRef = useRef(null); useImperativeHandle(ref, () => ({ // Only expose focus and nothing else @@ -456,8 +414,8 @@ const MyInput = forwardRef((props, ref) => { realInputRef.current.focus(); }, })); - return ; -}); + return ; +}; export default function Form() { const inputRef = useRef(null); @@ -469,9 +427,7 @@ export default function Form() { return ( <> - + ); } @@ -479,7 +435,7 @@ export default function Form() { -Here, `realInputRef` inside `MyInput` holds the actual input DOM node. However, `useImperativeHandle` instructs React to provide your own special object as the value of a ref to the parent component. So `inputRef.current` inside the `Form` component will only have the `focus` method. In this case, the ref "handle" is not the DOM node, but the custom object you create inside `useImperativeHandle` call. +Here, `realInputRef` inside `MyInput` holds the actual input DOM node. However, [`useImperativeHandle`](/reference/react/useImperativeHandle) instructs React to provide your own special object as the value of a ref to the parent component. So `inputRef.current` inside the `Form` component will only have the `focus` method. In this case, the ref "handle" is not the DOM node, but the custom object you create inside [`useImperativeHandle`](/reference/react/useImperativeHandle) call. @@ -591,7 +547,7 @@ export default function TodoList() { const newTodo = { id: nextId++, text: text }; flushSync(() => { setText(''); - setTodos([ ...todos, newTodo]); + setTodos([ ...todos, newTodo]); }); listRef.current.lastChild.scrollIntoView({ behavior: 'smooth', diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 5362d69e1..0ae499472 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -347,7 +347,7 @@ React Compiler can verify many of the Rules of React statically, and will safely ### How do I know my components have been optimized? {/*how-do-i-know-my-components-have-been-optimized*/} -[React Devtools](/learn/react-developer-tools) (v5.0+) has built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler. +[React DevTools](/learn/react-developer-tools) (v5.0+) and [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) have built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler. ### Something is not working after compilation {/*something-is-not-working-after-compilation*/} If you have eslint-plugin-react-compiler installed, the compiler will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. **You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized. diff --git a/src/content/learn/react-developer-tools.md b/src/content/learn/react-developer-tools.md index 243dab73c..6c03432d1 100644 --- a/src/content/learn/react-developer-tools.md +++ b/src/content/learn/react-developer-tools.md @@ -54,7 +54,7 @@ Lade deine Webseite jetzt im Browser neu, um die Developer-Tools zu sehen. ## Mobile (React Native) {/*mobile-react-native*/} -Um mit [React Native](https://reactnative.dev/) erstellte Anwendungen zu überprüfen, kannst du [React Native DevTools](https://reactnative.dev/docs/debugging/react-native-devtools) verwenden, der eingebaute Debugger, der die React Developer Tools tief integriert. Alle Funktionen sind identisch mit denen der Browser-Erweiterung, einschließlich der Hervorhebung und Auswahl nativer Elemente. +Um mit [React Native](https://reactnative.dev/) erstellte Anwendungen zu überprüfen, kannst du [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) verwenden, der eingebaute Debugger, der die React Developer Tools tief integriert. Alle Funktionen sind identisch mit denen der Browser-Erweiterung, einschließlich der Hervorhebung und Auswahl nativer Elemente. [Erfahren Sie mehr über Debugging in React Native](https://reactnative.dev/docs/debugging) diff --git a/src/content/reference/react-dom/client/createRoot.md b/src/content/reference/react-dom/client/createRoot.md index a2bef6bf2..54e7a7f1d 100644 --- a/src/content/reference/react-dom/client/createRoot.md +++ b/src/content/reference/react-dom/client/createRoot.md @@ -144,7 +144,7 @@ Usually, you only need to run this code once at startup. It will: -```html index.html +```html public/index.html My app @@ -375,7 +375,7 @@ You can use the `onUncaughtError` root option to display error dialogs: -```html index.html hidden +```html public/index.html hidden @@ -606,7 +606,7 @@ You can use the `onCaughtError` root option to display error dialogs or filter k -```html index.html hidden +```html public/index.html hidden @@ -885,7 +885,7 @@ You can use the `onRecoverableError` root option to display error dialogs: -```html index.html hidden +```html public/index.html hidden diff --git a/src/content/reference/react-dom/client/hydrateRoot.md b/src/content/reference/react-dom/client/hydrateRoot.md index c54b6fe11..b1eeca30c 100644 --- a/src/content/reference/react-dom/client/hydrateRoot.md +++ b/src/content/reference/react-dom/client/hydrateRoot.md @@ -406,7 +406,7 @@ You can use the `onUncaughtError` root option to display error dialogs: -```html index.html hidden +```html public/index.html hidden @@ -641,7 +641,7 @@ You can use the `onCaughtError` root option to display error dialogs or filter k -```html index.html hidden +```html public/index.html hidden @@ -922,7 +922,7 @@ You can use the `onRecoverableError` root option to display error dialogs for hy -```html index.html hidden +```html public/index.html hidden diff --git a/src/content/reference/react-dom/components/form.md b/src/content/reference/react-dom/components/form.md index 047b65aa7..b3c849e72 100644 --- a/src/content/reference/react-dom/components/form.md +++ b/src/content/reference/react-dom/components/form.md @@ -50,7 +50,7 @@ To create interactive controls for submitting information, render the [built-in ### Handle form submission on the client {/*handle-form-submission-on-the-client*/} -Pass a function to the `action` prop of form to run the function when the form is submitted. [`formData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) will be passed to the function as an argument so you can access the data submitted by the form. This differs from the conventional [HTML action](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#action), which only accepts URLs. +Pass a function to the `action` prop of form to run the function when the form is submitted. [`formData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) will be passed to the function as an argument so you can access the data submitted by the form. This differs from the conventional [HTML action](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#action), which only accepts URLs. After the `action` function succeeds, all uncontrolled field elements in the form are reset. @@ -117,7 +117,7 @@ function AddToCart({productId}) { } ``` -When `
      ` is rendered by a [Server Component](/reference/rsc/use-client), and a [Server Function](/reference/rsc/server-function) is passed to the ``'s `action` prop, the form is [progressively enhanced](https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement). +When `` is rendered by a [Server Component](/reference/rsc/use-client), and a [Server Function](/reference/rsc/server-functions) is passed to the ``'s `action` prop, the form is [progressively enhanced](https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement). ### Display a pending state during form submission {/*display-a-pending-state-during-form-submission*/} To display a pending state when a form is being submitted, you can call the `useFormStatus` Hook in a component rendered in a `` and read the `pending` property returned. diff --git a/src/content/reference/react-dom/components/link.md b/src/content/reference/react-dom/components/link.md index 77da89d47..41236eb3d 100644 --- a/src/content/reference/react-dom/components/link.md +++ b/src/content/reference/react-dom/components/link.md @@ -151,9 +151,7 @@ export default function SiteMapPage() { ### Controlling stylesheet precedence {/*controlling-stylesheet-precedence*/} -Stylesheets can conflict with each other, and when they do, the browser goes with the one that comes later in the document. React lets you control the order of stylesheets with the `precedence` prop. In this example, two components render stylesheets, and the one with the higher precedence goes later in the document even though the component that renders it comes earlier. - -{/*FIXME: this doesn't appear to actually work -- I guess precedence isn't implemented yet?*/} +Stylesheets can conflict with each other, and when they do, the browser goes with the one that comes later in the document. React lets you control the order of stylesheets with the `precedence` prop. In this example, three components render stylesheets, and the ones with the same precedence are grouped together in the ``. @@ -165,23 +163,30 @@ export default function HomePage() { + ... ); } function FirstComponent() { - return ; + return ; } function SecondComponent() { - return ; + return ; +} + +function ThirdComponent() { + return ; } ``` +Note the `precedence` values themselves are arbitrary and their naming is up to you. React will infer that precedence values it discovers first are "lower" and precedence values it discovers later are "higher". + ### Deduplicated stylesheet rendering {/*deduplicated-stylesheet-rendering*/} If you render the same stylesheet from multiple components, React will place only a single `` in the document head. diff --git a/src/content/reference/react-dom/components/style.md b/src/content/reference/react-dom/components/style.md index 6e7e730b5..2e1dde99a 100644 --- a/src/content/reference/react-dom/components/style.md +++ b/src/content/reference/react-dom/components/style.md @@ -62,7 +62,11 @@ This special treatment comes with two caveats: If a component depends on certain CSS styles in order to be displayed correctly, you can render an inline stylesheet within the component. -If you supply an `href` and `precedence` prop, your component will suspend while the stylesheet is loading. (Even with inline stylesheets, there may be a loading time due to fonts and images that the stylesheet refers to.) The `href` prop should uniquely identify the stylesheet, because React will de-duplicate stylesheets that have the same `href`. +The `href` prop should uniquely identify the stylesheet, because React will de-duplicate stylesheets that have the same `href`. +If you supply a `precedence` prop, React will reorder inline stylesheets based on the order these values appear in the component tree. + +Inline stylesheets will not trigger Suspense boundaries while they're loading. +Even if they load async resources like fonts or images. diff --git a/src/content/reference/react-dom/createPortal.md b/src/content/reference/react-dom/createPortal.md index 0107c20d3..c04510f80 100644 --- a/src/content/reference/react-dom/createPortal.md +++ b/src/content/reference/react-dom/createPortal.md @@ -252,7 +252,7 @@ Portals can be useful if your React root is only part of a static or server-rend -```html index.html +```html public/index.html My app diff --git a/src/content/reference/react-dom/hooks/useFormStatus.md b/src/content/reference/react-dom/hooks/useFormStatus.md index 0eb8c5d79..0fc83e3e1 100644 --- a/src/content/reference/react-dom/hooks/useFormStatus.md +++ b/src/content/reference/react-dom/hooks/useFormStatus.md @@ -1,6 +1,5 @@ --- title: useFormStatus -canary: true --- diff --git a/src/content/reference/react-dom/static/prerenderToNodeStream.md b/src/content/reference/react-dom/static/prerenderToNodeStream.md index 259a3b5d8..039987497 100644 --- a/src/content/reference/react-dom/static/prerenderToNodeStream.md +++ b/src/content/reference/react-dom/static/prerenderToNodeStream.md @@ -4,7 +4,7 @@ title: prerenderToNodeStream -`prerender` renders a React tree to a static HTML string using a [Node.js Stream.](https://nodejs.org/api/stream.html). +`prerenderToNodeStream` renders a React tree to a static HTML string using a [Node.js Stream.](https://nodejs.org/api/stream.html). ```js const {prelude} = await prerenderToNodeStream(reactNode, options?) @@ -292,4 +292,4 @@ Suspense-enabled data fetching without the use of an opinionated framework is no The `prerenderToNodeStream` response waits for the entire app to finish rendering, including waiting for all suspense boundaries to resolve, before resolving. It is designed for static site generation (SSG) ahead of time and does not support streaming more content as it loads. To stream content as it loads, use a streaming server render API like [renderToPipeableStream](/reference/react-dom/server/renderToPipeableStream). - \ No newline at end of file + diff --git a/src/content/reference/react/Suspense.md b/src/content/reference/react/Suspense.md index dc22c907a..4fce69d69 100644 --- a/src/content/reference/react/Suspense.md +++ b/src/content/reference/react/Suspense.md @@ -207,7 +207,7 @@ async function getAlbums() { **Only Suspense-enabled data sources will activate the Suspense component.** They include: -- Data fetching with Suspense-enabled frameworks like [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/) and [Next.js](https://nextjs.org/docs/getting-started/react-essentials) +- Data fetching with Suspense-enabled frameworks like [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/) and [Next.js](https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming#streaming-with-suspense) - Lazy-loading component code with [`lazy`](/reference/react/lazy) - Reading the value of a cached Promise with [`use`](/reference/react/use) diff --git a/src/content/reference/react/act.md b/src/content/reference/react/act.md index c01f3cd69..eff3f891f 100644 --- a/src/content/reference/react/act.md +++ b/src/content/reference/react/act.md @@ -70,13 +70,13 @@ function Counter() { } useEffect(() => { - document.title = `You clicked ${this.state.count} times`; + document.title = `You clicked ${count} times`; }, [count]); return (
      -

      You clicked {this.state.count} times

      -
      diff --git a/src/content/reference/react/createContext.md b/src/content/reference/react/createContext.md index a653633c1..03b09f8af 100644 --- a/src/content/reference/react/createContext.md +++ b/src/content/reference/react/createContext.md @@ -84,7 +84,7 @@ function Button() { } ``` -Although this older way still works, but **newly written code should read context with [`useContext()`](/reference/react/useContext) instead:** +Although this older way still works, **newly written code should read context with [`useContext()`](/reference/react/useContext) instead:** ```js function Button() { diff --git a/src/content/reference/react/startTransition.md b/src/content/reference/react/startTransition.md index 5956bb070..fba28f6d1 100644 --- a/src/content/reference/react/startTransition.md +++ b/src/content/reference/react/startTransition.md @@ -41,7 +41,7 @@ function TabContainer() { #### Parameters {/*parameters*/} -* `action`: A function that updates some state by calling one or more [`set` functions](/reference/react/useState#setstate). React calls `action` immediately with no parameters and marks all state updates scheduled synchronously during the `action` function call as Transitions. Any async calls awaited in the `action` will be included in the transition, but currently require wrapping any `set` functions after the `await` in an additional `startTransition` (see [Troubleshooting](#react-doesnt-treat-my-state-update-after-await-as-a-transition)). State updates marked as Transitions will be [non-blocking](#marking-a-state-update-as-a-non-blocking-transition) and [will not display unwanted loading indicators.](#preventing-unwanted-loading-indicators). +* `action`: A function that updates some state by calling one or more [`set` functions](/reference/react/useState#setstate). React calls `action` immediately with no parameters and marks all state updates scheduled synchronously during the `action` function call as Transitions. Any async calls awaited in the `action` will be included in the transition, but currently require wrapping any `set` functions after the `await` in an additional `startTransition` (see [Troubleshooting](/reference/react/useTransition#react-doesnt-treat-my-state-update-after-await-as-a-transition)). State updates marked as Transitions will be [non-blocking](#marking-a-state-update-as-a-non-blocking-transition) and [will not display unwanted loading indicators.](/reference/react/useTransition#preventing-unwanted-loading-indicators). #### Returns {/*returns*/} @@ -53,9 +53,9 @@ function TabContainer() { * You can wrap an update into a Transition only if you have access to the `set` function of that state. If you want to start a Transition in response to some prop or a custom Hook return value, try [`useDeferredValue`](/reference/react/useDeferredValue) instead. -* The function you pass to the of `startTransition` is called immediately, marking all state updates that happen while it executes as Transitions. If you try to perform state updates in a `setTimeout`, for example, they won't be marked as Transitions. +* The function you pass to `startTransition` is called immediately, marking all state updates that happen while it executes as Transitions. If you try to perform state updates in a `setTimeout`, for example, they won't be marked as Transitions. -* You must wrap any state updates after any async requests in another `startTransition` to mark them as Transitions. This is a known limitation that we will fix in the future (see [Troubleshooting](#react-doesnt-treat-my-state-update-after-await-as-a-transition)). +* You must wrap any state updates after any async requests in another `startTransition` to mark them as Transitions. This is a known limitation that we will fix in the future (see [Troubleshooting](/reference/react/useTransition#react-doesnt-treat-my-state-update-after-await-as-a-transition)). * A state update marked as a Transition will be interrupted by other state updates. For example, if you update a chart component inside a Transition, but then start typing into an input while the chart is in the middle of a re-render, React will restart the rendering work on the chart component after handling the input state update. diff --git a/src/content/reference/react/use.md b/src/content/reference/react/use.md index 48b21fa61..557a71cad 100644 --- a/src/content/reference/react/use.md +++ b/src/content/reference/react/use.md @@ -397,6 +397,17 @@ root.render( ); ``` +```json package.json hidden +{ + "dependencies": { + "react": "19.0.0", + "react-dom": "19.0.0", + "react-scripts": "^5.0.0", + "react-error-boundary": "4.0.3" + }, + "main": "/index.js" +} +```
      #### Providing an alternative value with `Promise.catch` {/*providing-an-alternative-value-with-promise-catch*/} diff --git a/src/content/reference/react/useId.md b/src/content/reference/react/useId.md index c97120eba..c6be96fde 100644 --- a/src/content/reference/react/useId.md +++ b/src/content/reference/react/useId.md @@ -226,7 +226,7 @@ If you render multiple independent React applications on a single page, pass `id -```html index.html +```html public/index.html My app diff --git a/src/content/reference/react/useImperativeHandle.md b/src/content/reference/react/useImperativeHandle.md index abd93cd4c..92f6e2cda 100644 --- a/src/content/reference/react/useImperativeHandle.md +++ b/src/content/reference/react/useImperativeHandle.md @@ -23,9 +23,9 @@ useImperativeHandle(ref, createHandle, dependencies?) Call `useImperativeHandle` at the top level of your component to customize the ref handle it exposes: ```js -import { forwardRef, useImperativeHandle } from 'react'; +import { useImperativeHandle } from 'react'; -const MyInput = forwardRef(function MyInput(props, ref) { +function MyInput({ ref }) { useImperativeHandle(ref, () => { return { // ... your methods ... @@ -38,12 +38,18 @@ const MyInput = forwardRef(function MyInput(props, ref) { #### Parameters {/*parameters*/} -* `ref`: The `ref` you received as the second argument from the [`forwardRef` render function.](/reference/react/forwardRef#render-function) +* `ref`: The `ref` you received as a prop to the `MyInput` component. * `createHandle`: A function that takes no arguments and returns the ref handle you want to expose. That ref handle can have any type. Usually, you will return an object with the methods you want to expose. * **optional** `dependencies`: The list of all reactive values referenced inside of the `createHandle` code. Reactive values include props, state, and all the variables and functions declared directly inside your component body. If your linter is [configured for React](/learn/editor-setup#linting), it will verify that every reactive value is correctly specified as a dependency. The list of dependencies must have a constant number of items and be written inline like `[dep1, dep2, dep3]`. React will compare each dependency with its previous value using the [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) comparison. If a re-render resulted in a change to some dependency, or if you omitted this argument, your `createHandle` function will re-execute, and the newly created handle will be assigned to the ref. + + +Starting with React 19, [`ref` is available a prop.](/blog/2024/12/05/react-19#ref-as-a-prop) In React 18 and earlier, it was necessary to get the `ref` from [`forwardRef`.](/reference/react/forwardRef) + + + #### Returns {/*returns*/} `useImperativeHandle` returns `undefined`. @@ -54,40 +60,38 @@ const MyInput = forwardRef(function MyInput(props, ref) { ### Exposing a custom ref handle to the parent component {/*exposing-a-custom-ref-handle-to-the-parent-component*/} -By default, components don't expose their DOM nodes to parent components. For example, if you want the parent component of `MyInput` to [have access](/learn/manipulating-the-dom-with-refs) to the `` DOM node, you have to opt in with [`forwardRef`:](/reference/react/forwardRef) - -```js {4} -import { forwardRef } from 'react'; +To expose a DOM node to the parent element, pass in the `ref` prop to the node. -const MyInput = forwardRef(function MyInput(props, ref) { - return ; -}); +```js {2} +function MyInput({ ref }) { + return ; +}; ``` -With the code above, [a ref to `MyInput` will receive the `` DOM node.](/reference/react/forwardRef#exposing-a-dom-node-to-the-parent-component) However, you can expose a custom value instead. To customize the exposed handle, call `useImperativeHandle` at the top level of your component: +With the code above, [a ref to `MyInput` will receive the `` DOM node.](/learn/manipulating-the-dom-with-refs) However, you can expose a custom value instead. To customize the exposed handle, call `useImperativeHandle` at the top level of your component: ```js {4-8} -import { forwardRef, useImperativeHandle } from 'react'; +import { useImperativeHandle } from 'react'; -const MyInput = forwardRef(function MyInput(props, ref) { +function MyInput({ ref }) { useImperativeHandle(ref, () => { return { // ... your methods ... }; }, []); - return ; -}); + return ; +}; ``` -Note that in the code above, the `ref` is no longer forwarded to the ``. +Note that in the code above, the `ref` is no longer passed to the ``. For example, suppose you don't want to expose the entire `` DOM node, but you want to expose two of its methods: `focus` and `scrollIntoView`. To do this, keep the real browser DOM in a separate ref. Then use `useImperativeHandle` to expose a handle with only the methods that you want the parent component to call: ```js {7-14} -import { forwardRef, useRef, useImperativeHandle } from 'react'; +import { useRef, useImperativeHandle } from 'react'; -const MyInput = forwardRef(function MyInput(props, ref) { +function MyInput({ ref }) { const inputRef = useRef(null); useImperativeHandle(ref, () => { @@ -101,8 +105,8 @@ const MyInput = forwardRef(function MyInput(props, ref) { }; }, []); - return ; -}); + return ; +}; ``` Now, if the parent component gets a ref to `MyInput`, it will be able to call the `focus` and `scrollIntoView` methods on it. However, it will not have full access to the underlying `` DOM node. @@ -134,9 +138,9 @@ export default function Form() { ``` ```js src/MyInput.js -import { forwardRef, useRef, useImperativeHandle } from 'react'; +import { useRef, useImperativeHandle } from 'react'; -const MyInput = forwardRef(function MyInput(props, ref) { +function MyInput({ ref, ...props }) { const inputRef = useRef(null); useImperativeHandle(ref, () => { @@ -151,7 +155,7 @@ const MyInput = forwardRef(function MyInput(props, ref) { }, []); return ; -}); +}; export default MyInput; ``` @@ -195,11 +199,11 @@ export default function Page() { ``` ```js src/Post.js -import { forwardRef, useRef, useImperativeHandle } from 'react'; +import { useRef, useImperativeHandle } from 'react'; import CommentList from './CommentList.js'; import AddComment from './AddComment.js'; -const Post = forwardRef((props, ref) => { +function Post({ ref }) { const commentsRef = useRef(null); const addCommentRef = useRef(null); @@ -221,16 +225,16 @@ const Post = forwardRef((props, ref) => { ); -}); +}; export default Post; ``` ```js src/CommentList.js -import { forwardRef, useRef, useImperativeHandle } from 'react'; +import { useRef, useImperativeHandle } from 'react'; -const CommentList = forwardRef(function CommentList(props, ref) { +function CommentList({ ref }) { const divRef = useRef(null); useImperativeHandle(ref, () => { @@ -252,17 +256,17 @@ const CommentList = forwardRef(function CommentList(props, ref) { {comments} ); -}); +} export default CommentList; ``` ```js src/AddComment.js -import { forwardRef, useRef, useImperativeHandle } from 'react'; +import { useRef, useImperativeHandle } from 'react'; -const AddComment = forwardRef(function AddComment(props, ref) { +function AddComment({ ref }) { return ; -}); +} export default AddComment; ``` diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index 33193ee3b..6bfaba8ee 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -1101,11 +1101,10 @@ function ChatRoom({ roomId }) { }, [roomId]); // ✅ Only changes when roomId changes useEffect(() => { - const options = createOptions(); const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); - }, [options]); // ✅ Only changes when createOptions changes + }, [options]); // ✅ Only changes when options changes // ... ``` diff --git a/src/content/reference/react/useRef.md b/src/content/reference/react/useRef.md index 14cd9b2ec..8ab53aef3 100644 --- a/src/content/reference/react/useRef.md +++ b/src/content/reference/react/useRef.md @@ -448,16 +448,16 @@ button { display: block; margin-bottom: 20px; } #### Exposing a ref to your own component {/*exposing-a-ref-to-your-own-component*/} -Sometimes, you may want to let the parent component manipulate the DOM inside of your component. For example, maybe you're writing a `MyInput` component, but you want the parent to be able to focus the input (which the parent has no access to). You can use a combination of `useRef` to hold the input and [`forwardRef`](/reference/react/forwardRef) to expose it to the parent component. Read a [detailed walkthrough](/learn/manipulating-the-dom-with-refs#accessing-another-components-dom-nodes) here. +Sometimes, you may want to let the parent component manipulate the DOM inside of your component. For example, maybe you're writing a `MyInput` component, but you want the parent to be able to focus the input (which the parent has no access to). You can create a `ref` in the parent and pass the `ref` as prop to the child component. Read a [detailed walkthrough](/learn/manipulating-the-dom-with-refs#accessing-another-components-dom-nodes) here. ```js -import { forwardRef, useRef } from 'react'; +import { useRef } from 'react'; -const MyInput = forwardRef((props, ref) => { - return ; -}); +function MyInput({ ref }) { + return ; +}; export default function Form() { const inputRef = useRef(null); @@ -554,7 +554,7 @@ You might get an error in the console: -Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()? +TypeError: Cannot read properties of null @@ -573,12 +573,10 @@ export default function MyInput({ value, onChange }) { } ``` -And then wrap it in [`forwardRef`](/reference/react/forwardRef) like this: - -```js {3,8} -import { forwardRef } from 'react'; +And then add `ref` to the list of props your component accepts and pass `ref` as a prop to the relevent child [built-in component](/reference/react-dom/components/common) like this: -const MyInput = forwardRef(({ value, onChange }, ref) => { +```js {1,6} +function MyInput({ value, onChange, ref }) { return ( { ref={ref} /> ); -}); +}; export default MyInput; ``` diff --git a/src/content/reference/react/useTransition.md b/src/content/reference/react/useTransition.md index 7c019bc16..6b7c511e7 100644 --- a/src/content/reference/react/useTransition.md +++ b/src/content/reference/react/useTransition.md @@ -48,7 +48,7 @@ function TabContainer() { ### `startTransition(action)` {/*starttransition*/} -The `startTransition` function returned by `useTransition` lets you mark a updates as a Transition. +The `startTransition` function returned by `useTransition` lets you mark an update as a Transition. ```js {6,8} function TabContainer() { @@ -305,12 +305,12 @@ export async function updateQuantity(newQuantity) { -This is a basic example to demonstrate how Actions work, but this example does not handle requests completing out of order. When updating the quantity multiple times, it's possible for the previous requests to finish after later requests causing the quantity to update out of order. This is a known limitation that we will fix in the future (see [Troubleshooting](#my-state-updates-in-async-transitions-are-out-of-order) below). +This is a basic example to demonstrate how Actions work, but this example does not handle requests completing out of order. When updating the quantity multiple times, it's possible for the previous requests to finish after later requests causing the quantity to update out of order. This is a known limitation that we will fix in the future (see [Troubleshooting](#my-state-updates-in-transitions-are-out-of-order) below). For common use cases, React provides built-in abstractions such as: - [`useActionState`](/reference/react/useActionState) - [`` actions](/reference/react-dom/components/form) -- [Server Actions](/reference/rsc/server-actions) +- [Server Functions](/reference/rsc/server-functions) These solutions handle request ordering for you. When using Transitions to build your own custom hooks or libraries that manage async state transitions, you have greater control over the request ordering, but you must handle it yourself. @@ -340,7 +340,7 @@ Update the quantity multiple times quickly. Notice that the pending "Total" stat ``` ```js src/App.js -import { useState, useTransition } from "react"; +import { useState } from "react"; import { updateQuantity } from "./api"; import Item from "./Item"; import Total from "./Total"; diff --git a/src/content/reference/rsc/server-components.md b/src/content/reference/rsc/server-components.md index 636b190c7..b58b7dea7 100644 --- a/src/content/reference/rsc/server-components.md +++ b/src/content/reference/rsc/server-components.md @@ -4,7 +4,7 @@ title: Server Components -Sever Components are for use in [React Server Components](/learn/start-a-new-react-project#bleeding-edge-react-frameworks). +Server Components are for use in [React Server Components](/learn/start-a-new-react-project#bleeding-edge-react-frameworks). @@ -22,7 +22,7 @@ This separate environment is the "server" in React Server Components. Server Com #### How do I build support for Server Components? {/*how-do-i-build-support-for-server-components*/} -While React Server Components in React 19 are stable and will not break between major versions, the underlying APIs used to implement a React Server Components bundler or framework do not follow semver and may break between minors in React 19.x. +While React Server Components in React 19 are stable and will not break between minor versions, the underlying APIs used to implement a React Server Components bundler or framework do not follow semver and may break between minors in React 19.x. To support React Server Components as a bundler or framework, we recommend pinning to a specific React version, or using the Canary release. We will continue working with bundlers and frameworks to stabilize the APIs used to implement React Server Components in the future. diff --git a/src/content/reference/rsc/server-functions.md b/src/content/reference/rsc/server-functions.md index adce77284..b079e322e 100644 --- a/src/content/reference/rsc/server-functions.md +++ b/src/content/reference/rsc/server-functions.md @@ -22,7 +22,7 @@ Server Functions allow Client Components to call async functions executed on the #### How do I build support for Server Functions? {/*how-do-i-build-support-for-server-functions*/} -While Server Functions in React 19 are stable and will not break between major versions, the underlying APIs used to implement Server Functions in a React Server Components bundler or framework do not follow semver and may break between minors in React 19.x. +While Server Functions in React 19 are stable and will not break between minor versions, the underlying APIs used to implement Server Functions in a React Server Components bundler or framework do not follow semver and may break between minors in React 19.x. To support Server Functions as a bundler or framework, we recommend pinning to a specific React version, or using the Canary release. We will continue working with bundlers and frameworks to stabilize the APIs used to implement Server Functions in the future. @@ -82,7 +82,7 @@ export async function createNote() { ``` -When the bundler builds the `EmptyNote` Client Component, it will create a reference to the `createNoteAction` function in the bundle. When the `button` is clicked, React will send a request to the server to execute the `createNoteAction` function using the reference provided: +When the bundler builds the `EmptyNote` Client Component, it will create a reference to the `createNote` function in the bundle. When the `button` is clicked, React will send a request to the server to execute the `createNote` function using the reference provided: ```js [[1, 2, "createNote"], [1, 5, "createNote"], [1, 7, "createNote"]] "use client"; @@ -90,7 +90,7 @@ import {createNote} from './actions'; function EmptyNote() { console.log(createNote); - // {$$typeof: Symbol.for("react.server.reference"), $$id: 'createNoteAction'} + // {$$typeof: Symbol.for("react.server.reference"), $$id: 'createNote'}