CoolFace
Datasetpublic

enigmare/v2-crawler

sourceHugging Faceupdated 28d agoView on Hugging Face
1likes904downloads
react_dev.jsonl52 linesDownload Raw Back to documentation
1{"id":"doc-thinking_in_react_react-64c5c2d5","source":"documentation","title":"Thinking in React – React","url":"https://react.dev/learn/thinking-in-react","text":"Example:\n```javascript\n[  { category: \"Fruits\", price: \"$1\", stocked: true, name: \"Apple\" },  { category: \"Fruits\", price: \"$1\", stocked: true, name: \"Dragonfruit\" },  { category: \"Fruits\", price: \"$2\", stocked: false, name: \"Passionfruit\" },  { category: \"Vegetables\", price: \"$2\", stocked: true, name: \"Spinach\" },  { category: \"Vegetables\", price: \"$4\", stocked: false, name: \"Pumpkin\" },  { category: \"Vegetables\", price: \"$1\", stocked: true, name: \"Peas\" }]\n```\n\nExample:\n```text\nfunction ProductCategoryRow({ category }) {\n  return (\n    <tr>\n      <th colSpan=\"2\">\n        {category}\n      </th>\n    </tr>\n  );\n}\n\nfunction ProductRow({ product }) {\n  const name = product.stocked ? product.name :\n    <span style={{ color: 'red' }}>\n      {product.name}\n    </span>;\n\n  return (\n    <tr>\n      <td>{name}</td>\n      <td>{product.price}</td>\n    </tr>\n  );\n}\n\nfunction ProductTable({ products }) {\n  const rows = [];\n  let lastCategory = null;\n\n  products.forEach((product) => {\n    if (product.category !== lastCategory) {\n      rows.push(\n        <ProductCategoryRow\n          category={product.category}\n          key={product.category} />\n      );\n    }\n    rows.push(\n      <ProductRow\n        product={product}\n        key={product.name} />\n    );\n    lastCategory = product.category;\n  });\n\n  return (\n    <table>\n      <thead>\n        <tr>\n          <th>Name</th>\n          <th>Price</th>\n        </tr>\n      </thead>\n      <tbody>{rows}</tbody>\n    </table>\n  );\n}\n\nfunction SearchBar() {\n  return (\n    <form>\n      <input type=\"text\" placeholder=\"Search...\" />\n      <label>\n        <input type=\"checkbox\" />\n        {' '}\n        Only show products in stock\n      </label>\n    </form>\n  );\n}\n\nfunction FilterableProductTable({ products }) {\n  return (\n    <div>\n      <SearchBar />\n      <ProductTable products={products} />\n    </div>\n  );\n}\n\nconst PRODUCTS = [\n  {category: \"Fruits\", price: \"$1\", stocked: true, name: \"Apple\"},\n  {category: \"Fruits\", price: \"$1\", stocked: true, name: \"Dragonfruit\"},\n  {category: \"Fruits\", price: \"$2\", stocked: false, name: \"Passionfruit\"},\n  {category: \"Vegetables\", price: \"$2\", stocked: true, name: \"Spinach\"},\n  {category: \"Vegetables\", price: \"$4\", stocked: false, name: \"Pumpkin\"},\n  {category: \"Vegetables\", price: \"$1\", stocked: true, name: \"Peas\"}\n];\n\nexport default function App() {\n  return <FilterableProductTable products={PRODUCTS} />;\n}\n```\n\nExample:\n```javascript\nfunction FilterableProductTable({ products }) {  const [filterText, setFilterText] = useState('');  const [inStockOnly, setInStockOnly] = useState(false);\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nfunction FilterableProductTable({ products }) {\n  const [filterText, setFilterText] = useState('');\n  const [inStockOnly, setInStockOnly] = useState(false);\n\n  return (\n    <div>\n      <SearchBar\n        filterText={filterText}\n        inStockOnly={inStockOnly} />\n      <ProductTable\n        products={products}\n        filterText={filterText}\n        inStockOnly={inStockOnly} />\n    </div>\n  );\n}\n\nfunction ProductCategoryRow({ category }) {\n  return (\n    <tr>\n      <th colSpan=\"2\">\n        {category}\n      </th>\n    </tr>\n  );\n}\n\nfunction ProductRow({ product }) {\n  const name = product.stocked ? product.name :\n    <span style={{ color: 'red' }}>\n      {product.name}\n    </span>;\n\n  return (\n    <tr>\n      <td>{name}</td>\n      <td>{product.price}</td>\n    </tr>\n  );\n}\n\nfunction ProductTable({ products, filterText, inStockOnly }) {\n  const rows = [];\n  let lastCategory = null;\n\n  products.forEach((product) => {\n    if (\n      product.name.toLowerCase().indexOf(\n        filterText.toLowerCase()\n      ) === -1\n    ) {\n      return;\n    }\n    if (inStockOnly && !product.stocked) {\n      return;\n    }\n    if (product.category !== lastCategory) {\n      rows.push(\n        <ProductCategoryRow\n          category={product.category}\n          key={product.category} />\n      );\n    }\n    rows.push(\n      <ProductRow\n        product={product}\n        key={product.name} />\n    );\n    lastCategory = product.category;\n  });\n\n  return (\n    <table>\n      <thead>\n        <tr>\n          <th>Name</th>\n          <th>Price</th>\n        </tr>\n      </thead>\n      <tbody>{rows}</tbody>\n    </table>\n  );\n}\n\nfunction SearchBar({ filterText, inStockOnly }) {\n  return (\n    <form>\n      <input\n        type=\"text\"\n        value={filterText}\n        placeholder=\"Search...\"/>\n      <label>\n        <input\n          type=\"checkbox\"\n          checked={inStockOnly} />\n        {' '}\n        Only show products in stock\n      </label>\n    </form>\n  );\n}\n\nconst PRODUCTS = [\n  {category: \"Fruits\", price: \"$1\", stocked: true, name: \"Apple\"},\n  {category: \"Fruits\", price: \"$1\", stocked: true, name: \"Dragonfruit\"},\n  {category: \"Fruits\", price: \"$2\", stocked: false, name: \"Passionfruit\"},\n  {category: \"Vegetables\", price: \"$2\", stocked: true, name: \"Spinach\"},\n  {category: \"Vegetables\", price: \"$4\", stocked: false, name: \"Pumpkin\"},\n  {category: \"Vegetables\", price: \"$1\", stocked: true, name: \"Peas\"}\n];\n\nexport default function App() {\n  return <FilterableProductTable products={PRODUCTS} />;\n}\n```\n\nExample:\n```javascript\nfunction SearchBar({ filterText, inStockOnly }) {  return (    <form>      <input        type=\"text\"        value={filterText}        placeholder=\"Search...\"/>\n```\n\nExample:\n```javascript\nfunction FilterableProductTable({ products }) {  const [filterText, setFilterText] = useState('');  const [inStockOnly, setInStockOnly] = useState(false);  return (    <div>      <SearchBar        filterText={filterText}        inStockOnly={inStockOnly}        onFilterTextChange={setFilterText}        onInStockOnlyChange={setInStockOnly} />\n```\n\nExample:\n```javascript\nfunction SearchBar({  filterText,  inStockOnly,  onFilterTextChange,  onInStockOnlyChange}) {  return (    <form>      <input        type=\"text\"        value={filterText}        placeholder=\"Search...\"        onChange={(e) => onFilterTextChange(e.target.value)}      />      <label>        <input          type=\"checkbox\"          checked={inStockOnly}          onChange={(e) => onInStockOnlyChange(e.target.checked)}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nfunction FilterableProductTable({ products }) {\n  const [filterText, setFilterText] = useState('');\n  const [inStockOnly, setInStockOnly] = useState(false);\n\n  return (\n    <div>\n      <SearchBar\n        filterText={filterText}\n        inStockOnly={inStockOnly}\n        onFilterTextChange={setFilterText}\n        onInStockOnlyChange={setInStockOnly} />\n      <ProductTable\n        products={products}\n        filterText={filterText}\n        inStockOnly={inStockOnly} />\n    </div>\n  );\n}\n\nfunction ProductCategoryRow({ category }) {\n  return (\n    <tr>\n      <th colSpan=\"2\">\n        {category}\n      </th>\n    </tr>\n  );\n}\n\nfunction ProductRow({ product }) {\n  const name = product.stocked ? product.name :\n    <span style={{ color: 'red' }}>\n      {product.name}\n    </span>;\n\n  return (\n    <tr>\n      <td>{name}</td>\n      <td>{product.price}</td>\n    </tr>\n  );\n}\n\nfunction ProductTable({ products, filterText, inStockOnly }) {\n  const rows = [];\n  let lastCategory = null;\n\n  products.forEach((product) => {\n    if (\n      product.name.toLowerCase().indexOf(\n        filterText.toLowerCase()\n      ) === -1\n    ) {\n      return;\n    }\n    if (inStockOnly && !product.stocked) {\n      return;\n    }\n    if (product.category !== lastCategory) {\n      rows.push(\n        <ProductCategoryRow\n          category={product.category}\n          key={product.category} />\n      );\n    }\n    rows.push(\n      <ProductRow\n        product={product}\n        key={product.name} />\n    );\n    lastCategory = product.category;\n  });\n\n  return (\n    <table>\n      <thead>\n        <tr>\n          <th>Name</th>\n          <th>Price</th>\n        </tr>\n      </thead>\n      <tbody>{rows}</tbody>\n    </table>\n  );\n}\n\nfunction SearchBar({\n  filterText,\n  inStockOnly,\n  onFilterTextChange,\n  onInStockOnlyChange\n}) {\n  return (\n    <form>\n      <input\n        type=\"text\"\n        value={filterText} placeholder=\"Search...\"\n        onChange={(e) => onFilterTextChange(e.target.value)} />\n      <label>\n        <input\n          type=\"checkbox\"\n          checked={inStockOnly}\n          onChange={(e) => onInStockOnlyChange(e.target.checked)} />\n        {' '}\n        Only show products in stock\n      </label>\n    </form>\n  );\n}\n\nconst PRODUCTS = [\n  {category: \"Fruits\", price: \"$1\", stocked: true, name: \"Apple\"},\n  {category: \"Fruits\", price: \"$1\", stocked: true, name: \"Dragonfruit\"},\n  {category: \"Fruits\", price: \"$2\", stocked: false, name: \"Passionfruit\"},\n  {category: \"Vegetables\", price: \"$2\", stocked: true, name: \"Spinach\"},\n  {category: \"Vegetables\", price: \"$4\", stocked: false, name: \"Pumpkin\"},\n  {category: \"Vegetables\", price: \"$1\", stocked: true, name: \"Peas\"}\n];\n\nexport default function App() {\n  return <FilterableProductTable products={PRODUCTS} />;\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.854Z","totalSectionsIncluded":0,"totalCodeBlocksIncluded":8,"totalLines":369,"estimatedTokens":2245}}2{"id":"doc-react_developer_tools_react-a8be8f0c","source":"documentation","title":"React Developer Tools – React","url":"https://react.dev/learn/react-developer-tools","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactSetupCopy pageCopyReact Developer ToolsUse React Developer Tools to inspect React components, edit props and state, and identify performance problems. You will learn How to install React Developer Tools Browser extension The easiest way to debug websites built with React is to install the React Developer Tools browser extension. It is available for several popular for Chrome Install for Firefox Install for Edge Now, if you visit a website built with React, you will see the Components and Profiler panels. Safari and other browsers For other browsers (for example, Safari), install the react-devtools npm package: # Yarnyarn global add react-devtools# Npmnpm install -g react-devtools Next open the developer tools from the Then connect your website by adding the following <script> tag to the beginning of your website’s <head>: <html> <head> <script src=\"http://localhost:8097\"></script> Reload your website in the browser now to view it in developer tools. Mobile (React Native) To inspect apps built with React Native, you can use React Native DevTools, the built-in debugger that deeply integrates React Developer Tools. All features work identically to the browser extension, including native element highlighting and selection. Learn more about debugging in React Native. For versions of React Native earlier than 0.76, please use the standalone build of React DevTools by following the Safari and other browsers guide above. PreviousUsing TypeScriptNextReact CompilerCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewBrowser extension Safari and other browsers Mobile (React Native)\n\nExample:\n```javascript\n# Yarnyarn global add react-devtools# Npmnpm install -g react-devtools\n```\n\nExample:\n```javascript\nreact-devtools\n```\n\nExample:\n```javascript\n<html>  <head>    <script src=\"http://localhost:8097\"></script>\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.854Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":3,"totalLines":18,"estimatedTokens":851}}3{"id":"doc-build_a_react_app_from_scratch_react-01212c85","source":"documentation","title":"Build a React app from Scratch – React","url":"https://react.dev/learn/build-a-react-app-from-scratch","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactInstallationCopy pageCopyBuild a React app from ScratchIf your app has constraints not well-served by existing frameworks, you prefer to build your own framework, or you just want to learn the basics of a React app, you can build a React app from scratch. Deep DiveConsider using a framework Show DetailsStarting from scratch is an easy way to get started using React, but a major tradeoff to be aware of is that going this route is often the same as building your own adhoc framework. As your requirements evolve, you may need to solve more framework-like problems that our recommended frameworks already have well developed and supported solutions for.For example, if in the future your app needs support for server-side rendering (SSR), static site generation (SSG), and/or React Server Components (RSC), you will have to implement those on your own. Similarly, future React features that require integrating at the framework level will have to be implemented on your own if you want to use them.Our recommended frameworks also help you build better performing apps. For example, reducing or eliminating waterfalls from network requests makes for a better user experience. This might not be a high priority when you are building a toy project, but if your app gains users you may want to improve its performance.Going this route also makes it more difficult to get support, since the way you develop routing, data-fetching, and other features will be unique to your situation. You should only choose this option if you are comfortable tackling these problems on your own, or if you’re confident that you will never need these features.For a list of recommended frameworks, check out Creating a React App. Step a build tool The first step is to install a build tool like vite, parcel, or rsbuild. These build tools provide features to package and run source code, provide a development server for local development and a build command to deploy your app to a production server. Vite Vite is a build tool that aims to provide a faster and leaner development experience for modern web projects. Terminal Copynpm create vite@latest my-app -- --template react-ts Vite is opinionated and comes with sensible defaults out of the box. Vite has a rich ecosystem of plugins to support fast refresh, JSX, Babel/SWC, and other common features. See Vite’s React plugin or React SWC plugin and React SSR example project to get started. Vite is already being used as a build tool in one of our recommended Router. Parcel Parcel combines a great out-of-the-box development experience with a scalable architecture that can take your project from just getting started to massive production applications. Terminal Copynpm install --save-dev parcel Parcel supports fast refresh, JSX, TypeScript, Flow, and styling out of the box. See Parcel’s React recipe to get started. Rsbuild Rsbuild is an Rspack-powered build tool that provides a seamless development experience for React applications. It comes with carefully tuned defaults and performance optimizations ready to use. Terminal Copynpx create-rsbuild --template react Rsbuild includes built-in support for React features like fast refresh, JSX, TypeScript, and styling. See Rsbuild’s React guide to get started. NoteMetro for React Native If you’re starting from scratch with React Native you’ll need to use Metro, the JavaScript bundler for React Native. Metro supports bundling for platforms like iOS and Android, but lacks many features when compared to the tools here. We recommend starting with Vite, Parcel, or Rsbuild unless your project requires React Native support. Step Common Application Patterns The build tools listed above start off with a client-only, single-page app (SPA), but don’t include any further solutions for common functionality like routing, data fetching, or styling. The React ecosystem includes many tools for these problems. We’ve listed a few that are widely used as a starting point, but feel free to choose other tools if those work better for you. Routing Routing determines what content or pages to display when a user visits a particular URL. You need to set up a router to map URLs to different parts of your app. You’ll also need to handle nested routes, route parameters, and query parameters. Routers can be configured within your code, or defined based on your component folder and file structures. Routers are a core part of modern applications, and are usually integrated with data fetching (including prefetching data for a whole page for faster loading), code splitting (to minimize client bundle sizes), and page rendering approaches (to decide how each page gets generated). We suggest Router Tanstack Router Data Fetching Fetching data from a server or other data source is a key part of most applications. Doing this properly requires handling loading states, error states, and caching the fetched data, which can be complex. Purpose-built data fetching libraries do the hard work of fetching and caching the data for you, letting you focus on what data your app needs and how to display it. These libraries are typically used directly in your components, but can also be integrated into routing loaders for faster pre-fetching and better performance, and in server rendering as well. Note that fetching data directly in components can lead to slower loading times due to network request waterfalls, so we recommend prefetching data in router loaders or on the server as much as possible! This allows a page’s data to be fetched all at once as the page is being displayed. If you’re fetching data from most backends or REST-style APIs, we suggest Query SWR RTK Query If you’re fetching data from a GraphQL API, we suggest Relay Code-splitting Code-splitting is the process of breaking your app into smaller bundles that can be loaded on demand. An app’s code size increases with every new feature and additional dependency. Apps can become slow to load because all of the code for the entire app needs to be sent before it can be used. Caching, reducing features/dependencies, and moving some code to run on the server can help mitigate slow loading but are incomplete solutions that can sacrifice functionality if overused. Similarly, if you rely on the apps using your framework to split the code, you might encounter situations where loading becomes slower than if no code splitting were happening at all. For example, lazily loading a chart delays sending the code needed to render the chart, splitting the chart code from the rest of the app. Parcel supports code splitting with React.lazy. However, if the chart loads its data after it has been initially rendered you are now waiting twice. This is a than fetching the data for the chart and sending the code to render it simultaneously, you must wait for each step to complete one after the other. Splitting code by route, when integrated with bundling and data fetching, can reduce the initial load time of your app and the time it takes for the largest visible content of the app to render (Largest Contentful Paint). For code-splitting instructions, see your build tool build optimizations Parcel code splitting Rsbuild code splitting Improving Application Performance Since the build tool you select only supports single page apps (SPAs), you’ll need to implement other rendering patterns like server-side rendering (SSR), static site generation (SSG), and/or React Server Components (RSC). Even if you don’t need these features at first, in the future there may be some routes that would benefit SSR, SSG or RSC. Single-page apps (SPA) load a single HTML page and dynamically updates the page as the user interacts with the app. SPAs are easier to get started with, but they can have slower initial load times. SPAs are the default architecture for most build tools. Streaming Server-side rendering (SSR) renders a page on the server and sends the fully rendered page to the client. SSR can improve performance, but it can be more complex to set up and maintain than a single-page app. With the addition of streaming, SSR can be very complex to set up and maintain. See Vite’s SSR guide. Static site generation (SSG) generates static HTML files for your app at build time. SSG can improve performance, but it can be more complex to set up and maintain than server-side rendering. See Vite’s SSG guide. React Server Components (RSC) lets you mix build-time, server-only, and interactive components in a single React tree. RSC can improve performance, but it currently requires deep expertise to set up and maintain. See Parcel’s RSC examples. Your rendering strategies need to integrate with your router so apps built with your framework can choose the rendering strategy on a per-route level. This will enable different rendering strategies without having to rewrite your whole app. For example, the landing page for your app might benefit from being statically generated (SSG), while a page with a content feed might perform best with server-side rendering. Using the right rendering strategy for the right routes can decrease the time it takes for the first byte of content to be loaded (Time to First Byte), the first piece of content to render (First Contentful Paint), and the largest visible content of the app to render (Largest Contentful Paint). And more… These are just a few examples of the features a new app will need to consider when building from scratch. Many limitations you’ll hit can be difficult to solve as each problem is interconnected with the others and can require deep expertise in problem areas you may not be familiar with. If you don’t want to solve these problems on your own, you can get started with a framework that provides these features out of the box.PreviousCreating a React AppNextAdd React to an Existing ProjectCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewStep a build tool Vite Parcel Rsbuild Step Common Application Patterns Routing Data Fetching Code-splitting Improving Application Performance And more…\n\nExample:\n```text\nnpm create vite@latest my-app -- --template react-ts\n```\n\nExample:\n```text\nnpm install --save-dev parcel\n```\n\nExample:\n```text\nnpx create-rsbuild --template react\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.855Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":3,"totalLines":18,"estimatedTokens":2942}}4{"id":"doc-react_compiler_react-62371402","source":"documentation","title":"React Compiler – React","url":"https://react.dev/learn/react-compiler","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactCopy pageCopyReact CompilerIntroduction Learn what React Compiler does and how it automatically optimizes your React application by handling memoization for you, eliminating the need for manual useMemo, useCallback, and React.memo. Installation Get started with installing React Compiler and learn how to configure it with your build tools. Incremental Adoption Learn strategies for gradually adopting React Compiler in your existing codebase if you’re not ready to enable it everywhere yet. Debugging and Troubleshooting When things don’t work as expected, use our debugging guide to understand the difference between compiler errors and runtime issues, identify common breaking patterns, and follow a systematic debugging workflow. Configuration and Reference For detailed configuration options and API Options - All compiler configuration options including React version compatibility Directives - Function-level compilation control Compiling Libraries - Shipping pre-compiled libraries Additional resources In addition to these docs, we recommend checking the React Compiler Working Group for additional information and discussion about the compiler.PreviousReact Developer ToolsNextIntroductionCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewIntroduction Installation Incremental Adoption Debugging and Troubleshooting Configuration and Reference Additional resources\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.856Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":738}}5{"id":"doc-setup_react-67b4a6b1","source":"documentation","title":"Setup – React","url":"https://react.dev/learn/setup","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactCopy pageCopySetupReact integrates with tools like editors, TypeScript, browser extensions, and compilers. This section will help you get your environment set up. Editor Setup See our recommended editors and learn how to set them up to work with React. Using TypeScript TypeScript is a popular way to add type definitions to JavaScript codebases. Learn how to integrate TypeScript into your React projects. React Developer Tools React Developer Tools is a browser extension that can inspect React components, edit props and state, and identify performance problems. Learn how to install it here. React Compiler React Compiler is a tool that automatically optimizes your React app. Learn more. Next steps Head to the Quick Start guide for a tour of the most important React concepts you will encounter every day.PreviousAdd React to an Existing ProjectNextEditor SetupCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewEditor Setup Using TypeScript React Developer Tools React Compiler Next steps\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.857Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":643}}6{"id":"doc-render_and_commit_react-4da7647e","source":"documentation","title":"Render and Commit – React","url":"https://react.dev/learn/render-and-commit","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactAdding InteractivityCopy pageCopyRender and CommitBefore your components are displayed on screen, they must be rendered by React. Understanding the steps in this process will help you think about how your code executes and explain its behavior. You will learn What rendering means in React When and why React renders a component The steps involved in displaying a component on screen Why rendering does not always produce a DOM update Imagine that your components are cooks in the kitchen, assembling tasty dishes from ingredients. In this scenario, React is the waiter who puts in requests from customers and brings them their orders. This process of requesting and serving UI has three a render (delivering the guest’s order to the kitchen) Rendering the component (preparing the order in the kitchen) Committing to the DOM (placing the order on the table) TriggerRenderCommitIllustrated by Rachel Lee Nabors Step a render There are two reasons for a component to ’s the component’s initial render. The component’s (or one of its ancestors’) state has been updated. Initial render When your app starts, you need to trigger the initial render. Frameworks and sandboxes sometimes hide this code, but it’s done by calling createRoot with the target DOM node, and then calling its render method with your Image from './Image.js'; import { createRoot } from 'react-dom/client'; const root = createRoot(document.getElementById('root')) root.render(<Image />); Try commenting out the root.render() call and see the component disappear! Re-renders when state updates Once the component has been initially rendered, you can trigger further renders by updating its state with the set function. Updating your component’s state automatically queues a render. (You can imagine these as a restaurant guest ordering tea, dessert, and all sorts of things after putting in their first order, depending on the state of their thirst or hunger.) State update......triggers......render!Illustrated by Rachel Lee Nabors Step renders your components After you trigger a render, React calls your components to figure out what to display on screen. “Rendering” is React calling your components. On initial render, React will call the root component. For subsequent renders, React will call the function component whose state update triggered the render. This process is the updated component returns some other component, React will render that component next, and if that component also returns something, it will render that component next, and so on. The process will continue until there are no more nested components and React knows exactly what should be displayed on screen. In the following example, React will call Gallery() and Image() several default function Gallery() { return ( <section> <h1>Inspiring Sculptures</h1> <Image /> <Image /> <Image /> </section> ); } function Image() { return ( <img src=\"https://react.dev/images/docs/scientists/ZF6s192.jpg\" alt=\"'Floralis Genérica' by Eduardo gigantic metallic flower sculpture with reflective petals\" /> ); } Show more During the initial render, React will create the DOM nodes for <section>, <h1>, and three <img> tags. During a re-render, React will calculate which of their properties, if any, have changed since the previous render. It won’t do anything with that information until the next step, the commit phase. PitfallRendering must always be a pure inputs, same output. Given the same inputs, a component should always return the same JSX. (When someone orders a salad with tomatoes, they should not receive a salad with onions!) It minds its own business. It should not change any objects or variables that existed before rendering. (One order should not change anyone else’s order.) Otherwise, you can encounter confusing bugs and unpredictable behavior as your codebase grows in complexity. When developing in “Strict Mode”, React calls each component’s function twice, which can help surface mistakes caused by impure functions. Deep DiveOptimizing performance Show DetailsThe default behavior of rendering all components nested within the updated component is not optimal for performance if the updated component is very high in the tree. If you run into a performance issue, there are several opt-in ways to solve it described in the Performance section. Don’t optimize prematurely! Step commits changes to the DOM After rendering (calling) your components, React will modify the DOM. For the initial render, React will use the appendChild() DOM API to put all the DOM nodes it has created on screen. For re-renders, React will apply the minimal necessary operations (calculated while rendering!) to make the DOM match the latest rendering output. React only changes the DOM nodes if there’s a difference between renders. For example, here is a component that re-renders with different props passed from its parent every second. Notice how you can add some text into the <input>, updating its value, but the text doesn’t disappear when the component default function Clock({ time }) { return ( <> <h1>{time}</h1> <input /> </> ); } This works because during this last step, React only updates the content of <h1> with the new time. It sees that the <input> appears in the JSX in the same place as last time, so React doesn’t touch the <input>—or its value! paint After rendering is done and React updated the DOM, the browser will repaint the screen. Although this process is known as “browser rendering”, we’ll refer to it as “painting” to avoid confusion throughout the docs. Illustrated by Rachel Lee Nabors Recap Any screen update in a React app happens in three Render Commit You can use Strict Mode to find mistakes in your components React does not touch the DOM if the rendering result is the same as last time Component's MemoryNextState as a SnapshotCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewStep a render Initial render Re-renders when state updates Step renders your components Step commits changes to the DOM paint Recap\n\nExample:\n```text\nimport Image from './Image.js';\nimport { createRoot } from 'react-dom/client';\n\nconst root = createRoot(document.getElementById('root'))\nroot.render(<Image />);\n```\n\nExample:\n```text\nexport default function Gallery() {\n  return (\n    <section>\n      <h1>Inspiring Sculptures</h1>\n      <Image />\n      <Image />\n      <Image />\n    </section>\n  );\n}\n\nfunction Image() {\n  return (\n    <img\n      src=\"https://react.dev/images/docs/scientists/ZF6s192.jpg\"\n      alt=\"'Floralis Genérica' by Eduardo Catalano: a gigantic metallic flower sculpture with reflective petals\"\n    />\n  );\n}\n```\n\nExample:\n```text\nexport default function Clock({ time }) {\n  return (\n    <>\n      <h1>{time}</h1>\n      <input />\n    </>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.858Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":3,"totalLines":47,"estimatedTokens":2078}}7{"id":"doc-keeping_components_pure_react-61e4a152","source":"documentation","title":"Keeping Components Pure – React","url":"https://react.dev/learn/keeping-components-pure","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactDescribing the UICopy pageCopyKeeping Components PureSome JavaScript functions are pure. Pure functions only perform a calculation and nothing more. By strictly only writing your components as pure functions, you can avoid an entire class of baffling bugs and unpredictable behavior as your codebase grows. To get these benefits, though, there are a few rules you must follow. You will learn What purity is and how it helps you avoid bugs How to keep components pure by keeping changes out of the render phase How to use Strict Mode to find mistakes in your components as formulas In computer science (and especially the world of functional programming), a pure function is a function with the following minds its own business. It does not change any objects or variables that existed before it was called. Same inputs, same output. Given the same inputs, a pure function should always return the same result. You might already be familiar with one example of pure in math. Consider this math = 2x. If x = 2 then y = 4. Always. If x = 3 then y = 6. Always. If x = 3, y won’t sometimes be 9 or –1 or 2.5 depending on the time of day or the state of the stock market. If y = 2x and x = 3, y will always be 6. If we made this into a JavaScript function, it would look like double(number) { return 2 * number;} In the above example, double is a pure function. If you pass it 3, it will return 6. Always. React is designed around this concept. React assumes that every component you write is a pure function. This means that React components you write must always return the same JSX given the same Recipe({ drinkers }) { return ( <ol> <li>Boil {drinkers} cups of water.</li> <li>Add {drinkers} spoons of tea and {0.5 * drinkers} spoons of spice.</li> <li>Add {0.5 * drinkers} cups of milk to boil and sugar to taste.</li> </ol> ); } export default function App() { return ( <section> <h1>Spiced Chai Recipe</h1> <h2>For two</h2> <Recipe drinkers={2} /> <h2>For a gathering</h2> <Recipe drinkers={4} /> </section> ); } Show more When you pass drinkers={2} to Recipe, it will return JSX containing 2 cups of water. Always. If you pass drinkers={4}, it will return JSX containing 4 cups of water. Always. Just like a math formula. You could think of your components as you follow them and don’t introduce new ingredients during the cooking process, you will get the same dish every time. That “dish” is the JSX that the component serves to React to render. Illustrated by Rachel Lee Nabors Side Effects: (un)intended consequences React’s rendering process must always be pure. Components should only return their JSX, and not change any objects or variables that existed before rendering—that would make them impure! Here is a component that breaks this guest = 0; function Cup() { // a preexisting variable! guest = guest + 1; return <h2>Tea cup for guest #{guest}</h2>; } export default function TeaSet() { return ( <> <Cup /> <Cup /> <Cup /> </> ); } Show more This component is reading and writing a guest variable declared outside of it. This means that calling this component multiple times will produce different JSX! And what’s more, if other components read guest, they will produce different JSX, too, depending on when they were rendered! That’s not predictable. Going back to our formula y = 2x, now even if x = 2, we cannot trust that y = 4. Our tests could fail, our users would be baffled, planes would fall out of the sky—you can see how this would lead to confusing bugs! You can fix this component by passing guest as a prop Cup({ guest }) { return <h2>Tea cup for guest #{guest}</h2>; } export default function TeaSet() { return ( <> <Cup guest={1} /> <Cup guest={2} /> <Cup guest={3} /> </> ); } Now your component is pure, as the JSX it returns only depends on the guest prop. In general, you should not expect your components to be rendered in any particular order. It doesn’t matter if you call y = 2x before or after y = formulas will resolve independently of each other. In the same way, each component should only “think for itself”, and not attempt to coordinate with or depend upon others during rendering. Rendering is like a school component should calculate JSX on their own! Deep DiveDetecting impure calculations with StrictMode Show DetailsAlthough you might not have used them all yet, in React there are three kinds of inputs that you can read while , state, and context. You should always treat these inputs as read-only.When you want to change something in response to user input, you should set state instead of writing to a variable. You should never change preexisting variables or objects while your component is rendering.React offers a “Strict Mode” in which it calls each component’s function twice during development. By calling the component functions twice, Strict Mode helps find components that break these rules.Notice how the original example displayed “Guest ) { return <h2>Tea cup for guest #{guest}</h2>; } export default function TeaGathering() { const cups = []; for (let i = 1; i <= 12; i++) { cups.push(<Cup key={i} guest={i} />); } return cups; } If the cups variable or the [] array were created outside the TeaGathering function, this would be a huge problem! You would be changing a preexisting object by pushing items into that array. However, it’s fine because you’ve created them during the same render, inside TeaGathering. No code outside of TeaGathering will ever know that this happened. This is called “local mutation”—it’s like your component’s little secret. Where you can cause side effects While functional programming relies heavily on purity, at some point, somewhere, something has to change. That’s kind of the point of programming! These changes—updating the screen, starting an animation, changing the data—are called side effects. They’re things that happen “on the side”, not during rendering. In React, side effects usually belong inside event handlers. Event handlers are functions that React runs when you perform some action—for example, when you click a button. Even though event handlers are defined inside your component, they don’t run during rendering! So event handlers don’t need to be pure. If you’ve exhausted all other options and can’t find the right event handler for your side effect, you can still attach it to your returned JSX with a useEffect call in your component. This tells React to execute it later, after rendering, when side effects are allowed. However, this approach should be your last resort. When possible, try to express your logic with rendering alone. You’ll be surprised how far this can take you! Deep DiveWhy does React care about purity? Show DetailsWriting pure functions takes some habit and discipline. But it also unlocks marvelous components could run in a different environment—for example, on the server! Since they return the same result for the same inputs, one component can serve many user requests. You can improve performance by skipping rendering components whose inputs have not changed. This is safe because pure functions always return the same results, so they are safe to cache. If some data changes in the middle of rendering a deep component tree, React can restart rendering without wasting time to finish the outdated render. Purity makes it safe to stop calculating at any time. Every new React feature we’re building takes advantage of purity. From data fetching to animations to performance, keeping components pure unlocks the power of the React paradigm. Recap A component must be pure, minds its own business. It should not change any objects or variables that existed before rendering. Same inputs, same output. Given the same inputs, a component should always return the same JSX. Rendering can happen at any time, so components should not depend on each others’ rendering sequence. You should not mutate any of the inputs that your components use for rendering. That includes props, state, and context. To update the screen, “set” state instead of mutating preexisting objects. Strive to express your component’s logic in the JSX you return. When you need to “change things”, you’ll usually want to do it in an event handler. As a last resort, you can useEffect. Writing pure functions takes a bit of practice, but it unlocks the power of React’s paradigm. Try out some challenges1. Fix a broken clock 2. Fix a broken profile 3. Fix a broken story tray Challenge 1 of a broken clock This component tries to set the <h1>’s CSS class to \"night\" during the time from midnight to six hours in the morning, and \"day\" at all other times. However, it doesn’t work. Can you fix this component?You can verify whether your solution works by temporarily changing the computer’s timezone. When the current time is between midnight and six in the morning, the clock should have inverted colors!Clock.jsClock.jsReloadClearForkexport default function Clock({ time }) { const hours = time.getHours(); if (hours >= 0 && hours <= 6) { document.getElementById('time').className = 'night'; } else { document.getElementById('time').className = 'day'; } return ( <h1 id=\"time\"> {time.toLocaleTimeString()} </h1> ); } Show hint Show solutionNext ChallengePreviousRendering ListsNextYour UI as a TreeCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this as formulas Side Effects: (un)intended consequences Local component’s little secret Where you can cause side effects RecapChallenges\n\nExample:\n```javascript\nfunction double(number) {  return 2 * number;}\n```\n\nExample:\n```text\nfunction Recipe({ drinkers }) {\n  return (\n    <ol>\n      <li>Boil {drinkers} cups of water.</li>\n      <li>Add {drinkers} spoons of tea and {0.5 * drinkers} spoons of spice.</li>\n      <li>Add {0.5 * drinkers} cups of milk to boil and sugar to taste.</li>\n    </ol>\n  );\n}\n\nexport default function App() {\n  return (\n    <section>\n      <h1>Spiced Chai Recipe</h1>\n      <h2>For two</h2>\n      <Recipe drinkers={2} />\n      <h2>For a gathering</h2>\n      <Recipe drinkers={4} />\n    </section>\n  );\n}\n```\n\nExample:\n```text\nlet guest = 0;\n\nfunction Cup() {\n  // Bad: changing a preexisting variable!\n  guest = guest + 1;\n  return <h2>Tea cup for guest #{guest}</h2>;\n}\n\nexport default function TeaSet() {\n  return (\n    <>\n      <Cup />\n      <Cup />\n      <Cup />\n    </>\n  );\n}\n```\n\nExample:\n```text\nfunction Cup({ guest }) {\n  return <h2>Tea cup for guest #{guest}</h2>;\n}\n\nexport default function TeaSet() {\n  return (\n    <>\n      <Cup guest={1} />\n      <Cup guest={2} />\n      <Cup guest={3} />\n    </>\n  );\n}\n```\n\nExample:\n```text\nfunction Cup({ guest }) {\n  return <h2>Tea cup for guest #{guest}</h2>;\n}\n\nexport default function TeaGathering() {\n  const cups = [];\n  for (let i = 1; i <= 12; i++) {\n    cups.push(<Cup key={i} guest={i} />);\n  }\n  return cups;\n}\n```\n\nExample:\n```text\nexport default function Clock({ time }) {\n  const hours = time.getHours();\n  if (hours >= 0 && hours <= 6) {\n    document.getElementById('time').className = 'night';\n  } else {\n    document.getElementById('time').className = 'day';\n  }\n  return (\n    <h1 id=\"time\">\n      {time.toLocaleTimeString()}\n    </h1>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.859Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":6,"totalLines":103,"estimatedTokens":3169}}8{"id":"doc-importing_and_exporting_components_react-b357b48d","source":"documentation","title":"Importing and Exporting Components – React","url":"https://react.dev/learn/importing-and-exporting-components","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactDescribing the UICopy pageCopyImporting and Exporting ComponentsThe magic of components lies in their can create components that are composed of other components. But as you nest more and more components, it often makes sense to start splitting them into different files. This lets you keep your files easy to scan and reuse components in more places. You will learn What a root component file is How to import and export a component When to use default and named imports and exports How to import and export multiple components from one file How to split components into multiple files The root component file In Your First Component, you made a Profile component and a Gallery component that renders Profile() { return ( <img src=\"https://react.dev/images/docs/scientists/MK3eW3As.jpg\" alt=\"Katherine Johnson\" /> ); } export default function Gallery() { return ( <section> <h1>Amazing scientists</h1> <Profile /> <Profile /> <Profile /> </section> ); } Show more These currently live in a root component file, named App.js in this example. Depending on your setup, your root component could be in another file, though. If you use a framework with file-based routing, such as Next.js, your root component will be different for every page. Exporting and importing a component What if you want to change the landing screen in the future and put a list of science books there? Or place all the profiles somewhere else? It makes sense to move Gallery and Profile out of the root component file. This will make them more modular and reusable in other files. You can move a component in three a new JS file to put the components in. Export your function component from that file (using either default or named exports). Import it in the file where you’ll use the component (using the corresponding technique for importing default or named exports). Here both Profile and Gallery have been moved out of App.js into a new file called Gallery.js. Now you can change App.js to import Gallery from Gallery.js: App.jsGallery.jsApp.jsReloadClearForkimport Gallery from './Gallery.js'; export default function App() { return ( <Gallery /> ); } Notice how this example is broken down into two component files : Defines the Profile component which is only used within the same file and is not exported. Exports the Gallery component as a default export. App.js: Imports Gallery as a default import from Gallery.js. Exports the root App component as a default export. NoteYou may encounter files that leave off the import Button from './Button.js';Namedexport function Button() {}import { Button } from './Button.js';When you write a default import, you can put any name you want after import. For example, you could write import Banana from './Button.js' instead and it would still provide you with the same default export. In contrast, with named imports, the name has to match on both sides. That’s why they are called named imports!People often use default exports if the file exports only one component, and use named exports if it exports multiple components and values. Regardless of which coding style you prefer, always give meaningful names to your component functions and the files that contain them. Components without names, like export default () => {}, are discouraged because they make debugging harder. Exporting and importing multiple components from the same file What if you want to show just one Profile instead of a gallery? You can export the Profile component, too. But Gallery.js already has a default export, and you can’t have two default exports. You could create a new file with a default export, or you could add a named export for Profile. A file can only have one default export, but it can have numerous named exports! NoteTo reduce the potential confusion between default and named exports, some teams choose to only stick to one style (default or named), or avoid mixing them in a single file. Do what works best for you! First, export Profile from Gallery.js using a named export (no default keyword): export function Profile() { // ...} Then, import Profile from Gallery.js to App.js using a named import (with the curly braces): import { Profile } from './Gallery.js'; Finally, render <Profile /> from the App default function App() { return <Profile />;} Now Gallery.js contains two default Gallery export, and a named Profile export. App.js imports both of them. Try editing <Profile /> to <Gallery /> and back in this Gallery from './Gallery.js'; import { Profile } from './Gallery.js'; export default function App() { return ( <Profile /> ); } Now you’re using a mix of default and named : Exports the Profile component as a named export called Profile. Exports the Gallery component as a default export. App.js: Imports Profile as a named import called Profile from Gallery.js. Imports Gallery as a default import from Gallery.js. Exports the root App component as a default export. RecapOn this page you a root component file is How to import and export a component When and how to use default and named imports and exports How to export multiple components from the same file Try out some challengesChallenge 1 of the components further Currently, Gallery.js exports both Profile and Gallery, which is a bit confusing.Move the Profile component to its own Profile.js, and then change the App component to render both <Profile /> and <Gallery /> one after another.You may use either a default or a named export for Profile, but make sure that you use the corresponding import syntax in both App.js and Gallery.js! You can refer to the table from the deep dive statementImport statementDefaultexport default function Button() {}import Button from './Button.js';Namedexport function Button() {}import { Button } from './Button.js';App.jsGallery.jsProfile.jsGallery.jsReloadClearFork// Move me to Profile.js! export function Profile() { return ( <img src=\"https://react.dev/images/docs/scientists/QIrZWGIs.jpg\" alt=\"Alan L. Hart\" /> ); } export default function Gallery() { return ( <section> <h1>Amazing scientists</h1> <Profile /> <Profile /> <Profile /> </section> ); } Show moreAfter you get it working with one kind of exports, make it work with the other kind. Show hint Show solutionPreviousYour First ComponentNextWriting Markup with JSXCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewThe root component file Exporting and importing a component Exporting and importing multiple components from the same file RecapChallenges\n\nExample:\n```text\nfunction Profile() {\n  return (\n    <img\n      src=\"https://react.dev/images/docs/scientists/MK3eW3As.jpg\"\n      alt=\"Katherine Johnson\"\n    />\n  );\n}\n\nexport default function Gallery() {\n  return (\n    <section>\n      <h1>Amazing scientists</h1>\n      <Profile />\n      <Profile />\n      <Profile />\n    </section>\n  );\n}\n```\n\nExample:\n```text\nimport Gallery from './Gallery.js';\n\nexport default function App() {\n  return (\n    <Gallery />\n  );\n}\n```\n\nExample:\n```javascript\nimport Gallery from './Gallery';\n```\n\nExample:\n```javascript\nexport function Profile() {  // ...}\n```\n\nExample:\n```javascript\nimport { Profile } from './Gallery.js';\n```\n\nExample:\n```javascript\nexport default function App() {  return <Profile />;}\n```\n\nExample:\n```text\nimport Gallery from './Gallery.js';\nimport { Profile } from './Gallery.js';\n\nexport default function App() {\n  return (\n    <Profile />\n  );\n}\n```\n\nExample:\n```text\n// Move me to Profile.js!\nexport function Profile() {\n  return (\n    <img\n      src=\"https://react.dev/images/docs/scientists/QIrZWGIs.jpg\"\n      alt=\"Alan L. Hart\"\n    />\n  );\n}\n\nexport default function Gallery() {\n  return (\n    <section>\n      <h1>Amazing scientists</h1>\n      <Profile />\n      <Profile />\n      <Profile />\n    </section>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.860Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":8,"totalLines":93,"estimatedTokens":2330}}9{"id":"doc-javascript_in_jsx_with_curly_braces_react-c4107c44","source":"documentation","title":"JavaScript in JSX with Curly Braces – React","url":"https://react.dev/learn/javascript-in-jsx-with-curly-braces","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactDescribing the UICopy pageCopyJavaScript in JSX with Curly BracesJSX lets you write HTML-like markup inside a JavaScript file, keeping rendering logic and content in the same place. Sometimes you will want to add a little JavaScript logic or reference a dynamic property inside that markup. In this situation, you can use curly braces in your JSX to open a window to JavaScript. You will learn How to pass strings with quotes How to reference a JavaScript variable inside JSX with curly braces How to call a JavaScript function inside JSX with curly braces How to use a JavaScript object inside JSX with curly braces Passing strings with quotes When you want to pass a string attribute to JSX, you put it in single or double default function Avatar() { return ( <img className=\"avatar\" src=\"https://react.dev/images/docs/scientists/7vQD0fPs.jpg\" alt=\"Gregorio Y. Zara\" /> ); } Here, \"https://react.dev/images/docs/scientists/7vQD0fPs.jpg\" and \"Gregorio Y. Zara\" are being passed as strings. But what if you want to dynamically specify the src or alt text? You could use a value from JavaScript by replacing \" and \" with { and }: App.jsApp.jsReloadClearForkexport default function Avatar() { const avatar = 'https://react.dev/images/docs/scientists/7vQD0fPs.jpg'; const description = 'Gregorio Y. Zara'; return ( <img className=\"avatar\" src={avatar} alt={description} /> ); } Notice the difference between className=\"avatar\", which specifies an \"avatar\" CSS class name that makes the image round, and src={avatar} that reads the value of the JavaScript variable called avatar. That’s because curly braces let you work with JavaScript right there in your markup! Using curly window into the JavaScript world JSX is a special way of writing JavaScript. That means it’s possible to use JavaScript inside it—with curly braces { }. The example below first declares a name for the scientist, name, then embeds it with curly braces inside the <h1>: App.jsApp.jsReloadClearForkexport default function TodoList() { const name = 'Gregorio Y. Zara'; return ( <h1>{name}'s To Do List</h1> ); } Try changing the name’s value from 'Gregorio Y. Zara' to 'Hedy Lamarr'. See how the list title changes? Any JavaScript expression will work between curly braces, including function calls like formatDate(): App.jsApp.jsReloadClearForkconst today = new Date(); function formatDate(date) { return new Intl.DateTimeFormat( 'en-US', { weekday: 'long' } ).format(date); } export default function TodoList() { return ( <h1>To Do List for {formatDate(today)}</h1> ); } Where to use curly braces You can only use curly braces in two ways inside text directly inside a JSX tag: <h1>{name}'s To Do List</h1> works, but <{tag}>Gregorio Y. Zara's To Do List</{tag}> will not. As attributes immediately following the = ={avatar} will read the avatar variable, but src=\"{avatar}\" will pass the string \"{avatar}\". Using “double curlies”: CSS and other objects in JSX In addition to strings, numbers, and other JavaScript expressions, you can even pass objects in JSX. Objects are also denoted with curly braces, like { name: \"Hedy Lamarr\", }. Therefore, to pass a JS object in JSX, you must wrap the object in another pair of curly ={{ name: \"Hedy Lamarr\", }}. You may see this with inline CSS styles in JSX. React does not require you to use inline styles (CSS classes work great for most cases). But when you need an inline style, you pass an object to the style default function TodoList() { return ( <ul style={{ backgroundColor: 'black', color: 'pink' }}> <li>Improve the videophone</li> <li>Prepare aeronautics lectures</li> <li>Work on the alcohol-fuelled engine</li> </ul> ); } Try changing the values of backgroundColor and color. You can really see the JavaScript object inside the curly braces when you write it like this: <ul style={ { backgroundColor: 'black', color: 'pink' }}> The next time you see {{ and }} in JSX, know that it’s nothing more than an object inside the JSX curlies! PitfallInline style properties are written in camelCase. For example, HTML <ul style=\"background-color: black\"> would be written as <ul style={{ backgroundColor: 'black' }}> in your component. More fun with JavaScript objects and curly braces You can move several expressions into one object, and reference them in your JSX inside curly person = { name: 'Gregorio Y. Zara', theme: { backgroundColor: 'black', color: 'pink' } }; export default function TodoList() { return ( <div style={person.theme}> <h1>{person.name}'s Todos</h1> <img className=\"avatar\" src=\"https://react.dev/images/docs/scientists/7vQD0fPs.jpg\" alt=\"Gregorio Y. Zara\" /> <ul> <li>Improve the videophone</li> <li>Prepare aeronautics lectures</li> <li>Work on the alcohol-fuelled engine</li> </ul> </div> ); } Show more In this example, the person JavaScript object contains a name string and a theme person = { name: 'Gregorio Y. Zara', theme: { backgroundColor: 'black', color: 'pink' }}; The component can use these values from person like so: <div style={person.theme}> <h1>{person.name}'s Todos</h1> JSX is very minimal as a templating language because it lets you organize data and logic using JavaScript. RecapNow you know almost everything about attributes inside quotes are passed as strings. Curly braces let you bring JavaScript logic and variables into your markup. They work inside the JSX tag content or immediately after = in attributes. {{ and }} is not special ’s a JavaScript object tucked inside JSX curly braces. Try out some challenges1. Fix the mistake 2. Extract information into an object 3. Write an expression inside JSX curly braces Challenge 1 of the mistake This code crashes with an error saying Objects are not valid as a React person = { name: 'Gregorio Y. Zara', theme: { backgroundColor: 'black', color: 'pink' } }; export default function TodoList() { return ( <div style={person.theme}> <h1>{person}'s Todos</h1> <img className=\"avatar\" src=\"https://react.dev/images/docs/scientists/7vQD0fPs.jpg\" alt=\"Gregorio Y. Zara\" /> <ul> <li>Improve the videophone</li> <li>Prepare aeronautics lectures</li> <li>Work on the alcohol-fuelled engine</li> </ul> </div> ); } Show moreCan you find the problem? Show hint Show solutionNext ChallengePreviousWriting Markup with JSXNextPassing Props to a ComponentCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewPassing strings with quotes Using curly window into the JavaScript world Where to use curly braces Using “double curlies”: CSS and other objects in JSX More fun with JavaScript objects and curly braces RecapChallenges\n\nExample:\n```text\nexport default function Avatar() {\n  return (\n    <img\n      className=\"avatar\"\n      src=\"https://react.dev/images/docs/scientists/7vQD0fPs.jpg\"\n      alt=\"Gregorio Y. Zara\"\n    />\n  );\n}\n```\n\nExample:\n```text\nexport default function Avatar() {\n  const avatar = 'https://react.dev/images/docs/scientists/7vQD0fPs.jpg';\n  const description = 'Gregorio Y. Zara';\n  return (\n    <img\n      className=\"avatar\"\n      src={avatar}\n      alt={description}\n    />\n  );\n}\n```\n\nExample:\n```text\nexport default function TodoList() {\n  const name = 'Gregorio Y. Zara';\n  return (\n    <h1>{name}'s To Do List</h1>\n  );\n}\n```\n\nExample:\n```text\nconst today = new Date();\n\nfunction formatDate(date) {\n  return new Intl.DateTimeFormat(\n    'en-US',\n    { weekday: 'long' }\n  ).format(date);\n}\n\nexport default function TodoList() {\n  return (\n    <h1>To Do List for {formatDate(today)}</h1>\n  );\n}\n```\n\nExample:\n```text\nexport default function TodoList() {\n  return (\n    <ul style={{\n      backgroundColor: 'black',\n      color: 'pink'\n    }}>\n      <li>Improve the videophone</li>\n      <li>Prepare aeronautics lectures</li>\n      <li>Work on the alcohol-fuelled engine</li>\n    </ul>\n  );\n}\n```\n\nExample:\n```javascript\n<ul style={  {    backgroundColor: 'black',    color: 'pink'  }}>\n```\n\nExample:\n```text\nconst person = {\n  name: 'Gregorio Y. Zara',\n  theme: {\n    backgroundColor: 'black',\n    color: 'pink'\n  }\n};\n\nexport default function TodoList() {\n  return (\n    <div style={person.theme}>\n      <h1>{person.name}'s Todos</h1>\n      <img\n        className=\"avatar\"\n        src=\"https://react.dev/images/docs/scientists/7vQD0fPs.jpg\"\n        alt=\"Gregorio Y. Zara\"\n      />\n      <ul>\n        <li>Improve the videophone</li>\n        <li>Prepare aeronautics lectures</li>\n        <li>Work on the alcohol-fuelled engine</li>\n      </ul>\n    </div>\n  );\n}\n```\n\nExample:\n```javascript\nconst person = {  name: 'Gregorio Y. Zara',  theme: {    backgroundColor: 'black',    color: 'pink'  }};\n```\n\nExample:\n```javascript\n<div style={person.theme}>  <h1>{person.name}'s Todos</h1>\n```\n\nExample:\n```text\nconst person = {\n  name: 'Gregorio Y. Zara',\n  theme: {\n    backgroundColor: 'black',\n    color: 'pink'\n  }\n};\n\nexport default function TodoList() {\n  return (\n    <div style={person.theme}>\n      <h1>{person}'s Todos</h1>\n      <img\n        className=\"avatar\"\n        src=\"https://react.dev/images/docs/scientists/7vQD0fPs.jpg\"\n        alt=\"Gregorio Y. Zara\"\n      />\n      <ul>\n        <li>Improve the videophone</li>\n        <li>Prepare aeronautics lectures</li>\n        <li>Work on the alcohol-fuelled engine</li>\n      </ul>\n    </div>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.861Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":10,"totalLines":148,"estimatedTokens":2691}}10{"id":"doc-state_as_a_snapshot_react-9b3a5fb4","source":"documentation","title":"State as a Snapshot – React","url":"https://react.dev/learn/state-as-a-snapshot","text":"Example:\n```text\nimport { useState } from 'react';\n\nexport default function Form() {\n  const [isSent, setIsSent] = useState(false);\n  const [message, setMessage] = useState('Hi!');\n  if (isSent) {\n    return <h1>Your message is on its way!</h1>\n  }\n  return (\n    <form onSubmit={(e) => {\n      e.preventDefault();\n      setIsSent(true);\n      sendMessage(message);\n    }}>\n      <textarea\n        placeholder=\"Message\"\n        value={message}\n        onChange={e => setMessage(e.target.value)}\n      />\n      <button type=\"submit\">Send</button>\n    </form>\n  );\n}\n\nfunction sendMessage(message) {\n  // ...\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Counter() {\n  const [number, setNumber] = useState(0);\n\n  return (\n    <>\n      <h1>{number}</h1>\n      <button onClick={() => {\n        setNumber(number + 1);\n        setNumber(number + 1);\n        setNumber(number + 1);\n      }}>+3</button>\n    </>\n  )\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Counter() {\n  const [number, setNumber] = useState(0);\n\n  return (\n    <>\n      <h1>{number}</h1>\n      <button onClick={() => {\n        setNumber(number + 5);\n        alert(number);\n      }}>+5</button>\n    </>\n  )\n}\n```\n\nExample:\n```javascript\nsetNumber(0 + 5);alert(0);\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Counter() {\n  const [number, setNumber] = useState(0);\n\n  return (\n    <>\n      <h1>{number}</h1>\n      <button onClick={() => {\n        setNumber(number + 5);\n        setTimeout(() => {\n          alert(number);\n        }, 3000);\n      }}>+5</button>\n    </>\n  )\n}\n```\n\nExample:\n```javascript\nsetNumber(0 + 5);setTimeout(() => {  alert(0);}, 3000);\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Form() {\n  const [to, setTo] = useState('Alice');\n  const [message, setMessage] = useState('Hello');\n\n  function handleSubmit(e) {\n    e.preventDefault();\n    setTimeout(() => {\n      alert(`You said ${message} to ${to}`);\n    }, 5000);\n  }\n\n  return (\n    <form onSubmit={handleSubmit}>\n      <label>\n        To:{' '}\n        <select\n          value={to}\n          onChange={e => setTo(e.target.value)}>\n          <option value=\"Alice\">Alice</option>\n          <option value=\"Bob\">Bob</option>\n        </select>\n      </label>\n      <textarea\n        placeholder=\"Message\"\n        value={message}\n        onChange={e => setMessage(e.target.value)}\n      />\n      <button type=\"submit\">Send</button>\n    </form>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function TrafficLight() {\n  const [walk, setWalk] = useState(true);\n\n  function handleClick() {\n    setWalk(!walk);\n  }\n\n  return (\n    <>\n      <button onClick={handleClick}>\n        Change to {walk ? 'Stop' : 'Walk'}\n      </button>\n      <h1 style={{\n        color: walk ? 'darkgreen' : 'darkred'\n      }}>\n        {walk ? 'Walk' : 'Stop'}\n      </h1>\n    </>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.862Z","totalSectionsIncluded":0,"totalCodeBlocksIncluded":8,"totalLines":165,"estimatedTokens":748}}11{"id":"doc-queueing_a_series_of_state_updates_react-0cb6df4c","source":"documentation","title":"Queueing a Series of State Updates – React","url":"https://react.dev/learn/queueing-a-series-of-state-updates","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactAdding InteractivityCopy pageCopyQueueing a Series of State UpdatesSetting a state variable will queue another render. But sometimes you might want to perform multiple operations on the value before queueing the next render. To do this, it helps to understand how React batches state updates. You will learn What “batching” is and how React uses it to process multiple state updates How to apply several updates to the same state variable in a row React batches state updates You might expect that clicking the “+3” button will increment the counter three times because it calls setNumber(number + 1) three { useState } from 'react'; export default function Counter() { const [number, setNumber] = useState(0); return ( <> <h1>{number}</h1> <button onClick={() => { setNumber(number + 1); setNumber(number + 1); setNumber(number + 1); }}>+3</button> </> ) } Show more However, as you might recall from the previous section, each render’s state values are fixed, so the value of number inside the first render’s event handler is always 0, no matter how many times you call setNumber(1): setNumber(0 + 1);setNumber(0 + 1);setNumber(0 + 1); But there is one other factor at play here. React waits until all code in the event handlers has run before processing your state updates. This is why the re-render only happens after all these setNumber() calls. This might remind you of a waiter taking an order at the restaurant. A waiter doesn’t run to the kitchen at the mention of your first dish! Instead, they let you finish your order, let you make changes to it, and even take orders from other people at the table. Illustrated by Rachel Lee Nabors This lets you update multiple state variables—even from multiple components—without triggering too many re-renders. But this also means that the UI won’t be updated until after your event handler, and any code in it, completes. This behavior, also known as batching, makes your React app run much faster. It also avoids dealing with confusing “half-finished” renders where only some of the variables have been updated. React does not batch across multiple intentional events like clicks—each click is handled separately. Rest assured that React only does batching when it’s generally safe to do. This ensures that, for example, if the first button click disables a form, the second click would not submit it again. Updating the same state multiple times before the next render It is an uncommon use case, but if you would like to update the same state variable multiple times before the next render, instead of passing the next state value like setNumber(number + 1), you can pass a function that calculates the next state based on the previous one in the queue, like setNumber(n => n + 1). It is a way to tell React to “do something with the state value” instead of just replacing it. Try incrementing the counter { useState } from 'react'; export default function Counter() { const [number, setNumber] = useState(0); return ( <> <h1>{number}</h1> <button onClick={() => { setNumber(n => n + 1); setNumber(n => n + 1); setNumber(n => n + 1); }}>+3</button> </> ) } Show more Here, n => n + 1 is called an updater function. When you pass it to a state queues this function to be processed after all the other code in the event handler has run. During the next render, React goes through the queue and gives you the final updated state. setNumber(n => n + 1);setNumber(n => n + 1);setNumber(n => n + 1); Here’s how React works through these lines of code while executing the event (n => n + 1): n => n + 1 is a function. React adds it to a queue. setNumber(n => n + 1): n => n + 1 is a function. React adds it to a queue. setNumber(n => n + 1): n => n + 1 is a function. React adds it to a queue. When you call useState during the next render, React goes through the queue. The previous number state was 0, so that’s what React passes to the first updater function as the n argument. Then React takes the return value of your previous updater function and passes it to the next updater as n, and so updatenreturnsn => n + 100 + 1 = 1n => n + 111 + 1 = 2n => n + 122 + 1 = 3 React stores 3 as the final result and returns it from useState. This is why clicking “+3” in the above example correctly increments the value by 3. What happens if you update state after replacing it What about this event handler? What do you think number will be in the next render? <button onClick={() => { setNumber(number + 5); setNumber(n => n + 1);}}> App.jsApp.jsReloadClearForkimport { useState } from 'react'; export default function Counter() { const [number, setNumber] = useState(0); return ( <> <h1>{number}</h1> <button onClick={() => { setNumber(number + 5); setNumber(n => n + 1); }}>Increase the number</button> </> ) } Here’s what this event handler tells React to (number + 5): number is 0, so setNumber(0 + 5). React adds “replace with 5” to its queue. setNumber(n => n + 1): n => n + 1 is an updater function. React adds that function to its queue. During the next render, React goes through the state updatenreturns”replace with 5”0 (unused)5n => n + 155 + 1 = 6 React stores 6 as the final result and returns it from useState. NoteYou may have noticed that setState(5) actually works like setState(n => 5), but n is unused! What happens if you replace state after updating it Let’s try one more example. What do you think number will be in the next render? <button onClick={() => { setNumber(number + 5); setNumber(n => n + 1); setNumber(42);}}> App.jsApp.jsReloadClearForkimport { useState } from 'react'; export default function Counter() { const [number, setNumber] = useState(0); return ( <> <h1>{number}</h1> <button onClick={() => { setNumber(number + 5); setNumber(n => n + 1); setNumber(42); }}>Increase the number</button> </> ) } Show more Here’s how React works through these lines of code while executing this event (number + 5): number is 0, so setNumber(0 + 5). React adds “replace with 5” to its queue. setNumber(n => n + 1): n => n + 1 is an updater function. React adds that function to its queue. setNumber(42): React adds “replace with 42” to its queue. During the next render, React goes through the state updatenreturns”replace with 5”0 (unused)5n => n + 155 + 1 = 6”replace with 42”6 (unused)42 Then React stores 42 as the final result and returns it from useState. To summarize, here’s how you can think of what you’re passing to the setNumber state updater function (e.g. n => n + 1) gets added to the queue. Any other value (e.g. number 5) adds “replace with 5” to the queue, ignoring what’s already queued. After the event handler completes, React will trigger a re-render. During the re-render, React will process the queue. Updater functions run during rendering, so updater functions must be pure and only return the result. Don’t try to set state from inside of them or run other side effects. In Strict Mode, React will run each updater function twice (but discard the second result) to help you find mistakes. Naming conventions It’s common to name the updater function argument by the first letters of the corresponding state (e => !e);setLastName(ln => ln.reverse());setFriendCount(fc => fc * 2); If you prefer more verbose code, another common convention is to repeat the full state variable name, like setEnabled(enabled => !enabled), or to use a prefix like setEnabled(prevEnabled => !prevEnabled). Recap Setting state does not change the variable in the existing render, but it requests a new render. React processes state updates after event handlers have finished running. This is called batching. To update some state multiple times in one event, you can use setNumber(n => n + 1) updater function. Try out some challenges1. Fix a request counter 2. Implement the state queue yourself Challenge 1 of a request counter You’re working on an art marketplace app that lets the user submit multiple orders for an art item at the same time. Each time the user presses the “Buy” button, the “Pending” counter should increase by one. After three seconds, the “Pending” counter should decrease, and the “Completed” counter should increase.However, the “Pending” counter does not behave as intended. When you press “Buy”, it decreases to -1 (which should not be possible!). And if you click fast twice, both counters seem to behave unpredictably.Why does this happen? Fix both counters.App.jsApp.jsReloadClearForkimport { useState } from 'react'; export default function RequestTracker() { const [pending, setPending] = useState(0); const [completed, setCompleted] = useState(0); async function handleClick() { setPending(pending + 1); await delay(3000); setPending(pending - 1); setCompleted(completed + 1); } return ( <> <h3> Pending: {pending} </h3> <h3> Completed: {completed} </h3> <button onClick={handleClick}> Buy </button> </> ); } function delay(ms) { return new Promise(resolve => { setTimeout(resolve, ms); }); } Show more Show solutionNext ChallengePreviousState as a SnapshotNextUpdating Objects in StateCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewReact batches state updates Updating the same state multiple times before the next render What happens if you update state after replacing it What happens if you replace state after updating it Naming conventions RecapChallenges\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Counter() {\n  const [number, setNumber] = useState(0);\n\n  return (\n    <>\n      <h1>{number}</h1>\n      <button onClick={() => {\n        setNumber(number + 1);\n        setNumber(number + 1);\n        setNumber(number + 1);\n      }}>+3</button>\n    </>\n  )\n}\n```\n\nExample:\n```javascript\nsetNumber(0 + 1);setNumber(0 + 1);setNumber(0 + 1);\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Counter() {\n  const [number, setNumber] = useState(0);\n\n  return (\n    <>\n      <h1>{number}</h1>\n      <button onClick={() => {\n        setNumber(n => n + 1);\n        setNumber(n => n + 1);\n        setNumber(n => n + 1);\n      }}>+3</button>\n    </>\n  )\n}\n```\n\nExample:\n```javascript\nsetNumber(n => n + 1);setNumber(n => n + 1);setNumber(n => n + 1);\n```\n\nExample:\n```javascript\n<button onClick={() => {  setNumber(number + 5);  setNumber(n => n + 1);}}>\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Counter() {\n  const [number, setNumber] = useState(0);\n\n  return (\n    <>\n      <h1>{number}</h1>\n      <button onClick={() => {\n        setNumber(number + 5);\n        setNumber(n => n + 1);\n      }}>Increase the number</button>\n    </>\n  )\n}\n```\n\nExample:\n```javascript\n<button onClick={() => {  setNumber(number + 5);  setNumber(n => n + 1);  setNumber(42);}}>\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Counter() {\n  const [number, setNumber] = useState(0);\n\n  return (\n    <>\n      <h1>{number}</h1>\n      <button onClick={() => {\n        setNumber(number + 5);\n        setNumber(n => n + 1);\n        setNumber(42);\n      }}>Increase the number</button>\n    </>\n  )\n}\n```\n\nExample:\n```javascript\nsetEnabled(e => !e);setLastName(ln => ln.reverse());setFriendCount(fc => fc * 2);\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function RequestTracker() {\n  const [pending, setPending] = useState(0);\n  const [completed, setCompleted] = useState(0);\n\n  async function handleClick() {\n    setPending(pending + 1);\n    await delay(3000);\n    setPending(pending - 1);\n    setCompleted(completed + 1);\n  }\n\n  return (\n    <>\n      <h3>\n        Pending: {pending}\n      </h3>\n      <h3>\n        Completed: {completed}\n      </h3>\n      <button onClick={handleClick}>\n        Buy\n      </button>\n    </>\n  );\n}\n\nfunction delay(ms) {\n  return new Promise(resolve => {\n    setTimeout(resolve, ms);\n  });\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.863Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":10,"totalLines":144,"estimatedTokens":3336}}12{"id":"doc-rendering_lists_react-2b723d76","source":"documentation","title":"Rendering Lists – React","url":"https://react.dev/learn/rendering-lists","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactDescribing the UICopy pageCopyRendering ListsYou will often want to display multiple similar components from a collection of data. You can use the JavaScript array methods to manipulate an array of data. On this page, you’ll use filter() and map() with React to filter and transform your array of data into an array of components. You will learn How to render components from an array using JavaScript’s map() How to render only specific components using JavaScript’s filter() When and why to use React keys Rendering data from arrays Say that you have a list of content. <ul> <li>Creola Katherine </li> <li>Mario José Molina-Pasquel Henríquez: chemist</li> <li>Mohammad Abdus </li> <li>Percy Lavon </li> <li>Subrahmanyan </li></ul> The only difference among those list items is their contents, their data. You will often need to show several instances of the same component using different data when building lists of comments to galleries of profile images. In these situations, you can store that data in JavaScript objects and arrays and use methods like map() and filter() to render lists of components from them. Here’s a short example of how to generate a list of items from an the data into an people = [ 'Creola Katherine ', 'Mario José Molina-Pasquel Henríquez: chemist', 'Mohammad Abdus ', 'Percy Lavon ', 'Subrahmanyan ']; Map the people members into a new array of JSX nodes, listItems = people.map(person => <li>{person}</li>); Return listItems from your component wrapped in a <ul>: return <ul>{listItems}</ul>; Here is the people = [ 'Creola Katherine ', 'Mario José Molina-Pasquel Henríquez: chemist', 'Mohammad Abdus ', 'Percy Lavon ', 'Subrahmanyan ' ]; export default function List() { const listItems = people.map(person => <li>{person}</li> ); return <ul>{listItems}</ul>; } Notice the sandbox above displays a console : Each child in a list should have a unique “key” prop. You’ll learn how to fix this error later on this page. Before we get to that, let’s add some structure to your data. Filtering arrays of items This data can be structured even more. const people = [{ , name: 'Creola Katherine Johnson', profession: 'mathematician',}, { , name: 'Mario José Molina-Pasquel Henríquez', profession: 'chemist',}, { , name: 'Mohammad Abdus Salam', profession: 'physicist',}, { , name: 'Percy Lavon Julian', profession: 'chemist',}, { , name: 'Subrahmanyan Chandrasekhar', profession: 'astrophysicist',}]; Let’s say you want a way to only show people whose profession is 'chemist'. You can use JavaScript’s filter() method to return just those people. This method takes an array of items, passes them through a “test” (a function that returns true or false), and returns a new array of only those items that passed the test (returned true). You only want the items where profession is 'chemist'. The “test” function for this looks like (person) => person.profession === 'chemist'. Here’s how to put it a new array of just “chemist” people, chemists, by calling filter() on the people filtering by person.profession === 'chemist': const chemists = people.filter(person => person.profession === 'chemist'); Now map over listItems = chemists.map(person => <li> <img src={getImageUrl(person)} alt={person.name} /> <p> <b>{person.name}:</b> {' ' + person.profession + ' '} known for {person.accomplishment} </p> </li>); Lastly, return the listItems from your <ul>{listItems}</ul>; App.jsdata.jsutils.jsApp.jsReloadClearForkimport { people } from './data.js'; import { getImageUrl } from './utils.js'; export default function List() { const chemists = people.filter(person => person.profession === 'chemist' ); const listItems = chemists.map(person => <li> <img src={getImageUrl(person)} alt={person.name} /> <p> <b>{person.name}:</b> {' ' + person.profession + ' '} known for {person.accomplishment} </p> </li> ); return <ul>{listItems}</ul>; } Show more PitfallArrow functions implicitly return the expression right after =>, so you didn’t need a return listItems = chemists.map(person => <li>...</li> // Implicit return!);However, you must write return explicitly if your => is followed by a { curly brace!const listItems = chemists.map(person => { // Curly brace return <li>...</li>;});Arrow functions containing => { are said to have a “block body”. They let you write more than a single line of code, but you have to write a return statement yourself. If you forget it, nothing gets returned! Keeping list items in order with key Notice that all the sandboxes above show an error in the : Each child in a list should have a unique “key” prop. You need to give each array item a key — a string or a number that uniquely identifies it among other items in that array: <li key={person.id}>...</li> NoteJSX elements directly inside a map() call always need keys! Keys tell React which array item each component corresponds to, so that it can match them up later. This becomes important if your array items can move (e.g. due to sorting), get inserted, or get deleted. A well-chosen key helps React infer what exactly has happened, and make the correct updates to the DOM tree. Rather than generating keys on the fly, you should include them in your const people = [{ , // Used in JSX as a key name: 'Creola Katherine Johnson', profession: 'mathematician', accomplishment: 'spaceflight calculations', imageId: 'MK3eW3A' }, { , // Used in JSX as a key name: 'Mario José Molina-Pasquel Henríquez', profession: 'chemist', accomplishment: 'discovery of Arctic ozone hole', imageId: 'mynHUSa' }, { , // Used in JSX as a key name: 'Mohammad Abdus Salam', profession: 'physicist', accomplishment: 'electromagnetism theory', imageId: 'bE7W1ji' }, { , // Used in JSX as a key name: 'Percy Lavon Julian', profession: 'chemist', accomplishment: 'pioneering cortisone drugs, steroids and birth control pills', imageId: 'IOjWm71' }, { , // Used in JSX as a key name: 'Subrahmanyan Chandrasekhar', profession: 'astrophysicist', accomplishment: 'white dwarf star mass calculations', imageId: 'lrWQx8l' }]; Show more Deep DiveDisplaying several DOM nodes for each list item Show DetailsWhat do you do when each item needs to render not one, but several DOM nodes?The short <>...</> Fragment syntax won’t let you pass a key, so you need to either group them into a single <div>, or use the slightly longer and more explicit <Fragment> { Fragment } from 'react';// ...const listItems = people.map(person => <Fragment key={person.id}> <h1>{person.name}</h1> <p>{person.bio}</p> </Fragment>);Fragments disappear from the DOM, so this will produce a flat list of <h1>, <p>, <h1>, <p>, and so on. Where to get your key Different sources of data provide different sources of from a your data is coming from a database, you can use the database keys/IDs, which are unique by nature. Locally generated your data is generated and persisted locally (e.g. notes in a note-taking app), use an incrementing counter, crypto.randomUUID() or a package like uuid when creating items. Rules of keys Keys must be unique among siblings. However, it’s okay to use the same keys for JSX nodes in different arrays. Keys must not change or that defeats their purpose! Don’t generate them while rendering. Why does React need keys? Imagine that files on your desktop didn’t have names. Instead, you’d refer to them by their order — the first file, the second file, and so on. You could get used to it, but once you delete a file, it would get confusing. The second file would become the first file, the third file would be the second file, and so on. File names in a folder and JSX keys in an array serve a similar purpose. They let us uniquely identify an item between its siblings. A well-chosen key provides more information than the position within the array. Even if the position changes due to reordering, the key lets React identify the item throughout its lifetime. PitfallYou might be tempted to use an item’s index in the array as its key. In fact, that’s what React will use if you don’t specify a key at all. But the order in which you render items will change over time if an item is inserted, deleted, or if the array gets reordered. Index as a key often leads to subtle and confusing bugs.Similarly, do not generate keys on the fly, e.g. with key={Math.random()}. This will cause keys to never match up between renders, leading to all your components and DOM being recreated every time. Not only is this slow, but it will also lose any user input inside the list items. Instead, use a stable ID based on the data.Note that your components won’t receive key as a prop. It’s only used as a hint by React itself. If your component needs an ID, you have to pass it as a separate prop: <Profile key={id} userId={id} />. RecapOn this page you to move data out of components and into data structures like arrays and objects. How to generate sets of similar components with JavaScript’s map(). How to create arrays of filtered items with JavaScript’s filter(). Why and how to set key on each component in a collection so React can keep track of each of them even if their position or data changes. Try out some challenges1. Splitting a list in two 2. Nested lists in one component 3. Extracting a list item component 4. List with a separator Challenge 1 of a list in two This example shows a list of all people.Change it to show two separate lists one after and Everyone Else. Like previously, you can determine whether a person is a chemist by checking if person.profession === 'chemist'.App.jsdata.jsutils.jsApp.jsReloadClearForkimport { people } from './data.js'; import { getImageUrl } from './utils.js'; export default function List() { const listItems = people.map(person => <li key={person.id}> <img src={getImageUrl(person)} alt={person.name} /> <p> <b>{person.name}:</b> {' ' + person.profession + ' '} known for {person.accomplishment} </p> </li> ); return ( <article> <h1>Scientists</h1> <ul>{listItems}</ul> </article> ); } Show more Show solutionNext ChallengePreviousConditional RenderingNextKeeping Components PureCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewRendering data from arrays Filtering arrays of items Keeping list items in order with key Where to get your key Rules of keys Why does React need keys? RecapChallenges\n\nExample:\n```javascript\nconst people = [  'Creola Katherine Johnson: mathematician',  'Mario José Molina-Pasquel Henríquez: chemist',  'Mohammad Abdus Salam: physicist',  'Percy Lavon Julian: chemist',  'Subrahmanyan Chandrasekhar: astrophysicist'];\n```\n\nExample:\n```javascript\nconst listItems = people.map(person => <li>{person}</li>);\n```\n\nExample:\n```javascript\nreturn <ul>{listItems}</ul>;\n```\n\nExample:\n```text\nconst people = [\n  'Creola Katherine Johnson: mathematician',\n  'Mario José Molina-Pasquel Henríquez: chemist',\n  'Mohammad Abdus Salam: physicist',\n  'Percy Lavon Julian: chemist',\n  'Subrahmanyan Chandrasekhar: astrophysicist'\n];\n\nexport default function List() {\n  const listItems = people.map(person =>\n    <li>{person}</li>\n  );\n  return <ul>{listItems}</ul>;\n}\n```\n\nExample:\n```javascript\nconst people = [{  id: 0,  name: 'Creola Katherine Johnson',  profession: 'mathematician',}, {  id: 1,  name: 'Mario José Molina-Pasquel Henríquez',  profession: 'chemist',}, {  id: 2,  name: 'Mohammad Abdus Salam',  profession: 'physicist',}, {  id: 3,  name: 'Percy Lavon Julian',  profession: 'chemist',}, {  id: 4,  name: 'Subrahmanyan Chandrasekhar',  profession: 'astrophysicist',}];\n```\n\nExample:\n```javascript\nconst chemists = people.filter(person =>  person.profession === 'chemist');\n```\n\nExample:\n```javascript\nconst listItems = chemists.map(person =>  <li>     <img       src={getImageUrl(person)}       alt={person.name}     />     <p>       <b>{person.name}:</b>       {' ' + person.profession + ' '}       known for {person.accomplishment}     </p>  </li>);\n```\n\nExample:\n```text\nimport { people } from './data.js';\nimport { getImageUrl } from './utils.js';\n\nexport default function List() {\n  const chemists = people.filter(person =>\n    person.profession === 'chemist'\n  );\n  const listItems = chemists.map(person =>\n    <li>\n      <img\n        src={getImageUrl(person)}\n        alt={person.name}\n      />\n      <p>\n        <b>{person.name}:</b>\n        {' ' + person.profession + ' '}\n        known for {person.accomplishment}\n      </p>\n    </li>\n  );\n  return <ul>{listItems}</ul>;\n}\n```\n\nExample:\n```javascript\nconst listItems = chemists.map(person =>  <li>...</li> // Implicit return!);\n```\n\nExample:\n```javascript\nconst listItems = chemists.map(person => { // Curly brace  return <li>...</li>;});\n```\n\nExample:\n```text\nexport const people = [{\n  id: 0, // Used in JSX as a key\n  name: 'Creola Katherine Johnson',\n  profession: 'mathematician',\n  accomplishment: 'spaceflight calculations',\n  imageId: 'MK3eW3A'\n}, {\n  id: 1, // Used in JSX as a key\n  name: 'Mario José Molina-Pasquel Henríquez',\n  profession: 'chemist',\n  accomplishment: 'discovery of Arctic ozone hole',\n  imageId: 'mynHUSa'\n}, {\n  id: 2, // Used in JSX as a key\n  name: 'Mohammad Abdus Salam',\n  profession: 'physicist',\n  accomplishment: 'electromagnetism theory',\n  imageId: 'bE7W1ji'\n}, {\n  id: 3, // Used in JSX as a key\n  name: 'Percy Lavon Julian',\n  profession: 'chemist',\n  accomplishment: 'pioneering cortisone drugs, steroids and birth control pills',\n  imageId: 'IOjWm71'\n}, {\n  id: 4, // Used in JSX as a key\n  name: 'Subrahmanyan Chandrasekhar',\n  profession: 'astrophysicist',\n  accomplishment: 'white dwarf star mass calculations',\n  imageId: 'lrWQx8l'\n}];\n```\n\nExample:\n```javascript\nimport { Fragment } from 'react';// ...const listItems = people.map(person =>  <Fragment key={person.id}>    <h1>{person.name}</h1>    <p>{person.bio}</p>  </Fragment>);\n```\n\nExample:\n```text\nimport { people } from './data.js';\nimport { getImageUrl } from './utils.js';\n\nexport default function List() {\n  const listItems = people.map(person =>\n    <li key={person.id}>\n      <img\n        src={getImageUrl(person)}\n        alt={person.name}\n      />\n      <p>\n        <b>{person.name}:</b>\n        {' ' + person.profession + ' '}\n        known for {person.accomplishment}\n      </p>\n    </li>\n  );\n  return (\n    <article>\n      <h1>Scientists</h1>\n      <ul>{listItems}</ul>\n    </article>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.864Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":13,"totalLines":155,"estimatedTokens":3953}}13{"id":"doc-writing_markup_with_jsx_react-cb6ff504","source":"documentation","title":"Writing Markup with JSX – React","url":"https://react.dev/learn/writing-markup-with-jsx","text":"Example:\n```javascript\n<h1>Hedy Lamarr's Todos</h1><img  src=\"https://react.dev/images/docs/scientists/yXOvdOSs.jpg\"  alt=\"Hedy Lamarr\"  class=\"photo\"><ul>    <li>Invent new traffic lights    <li>Rehearse a movie scene    <li>Improve the spectrum technology</ul>\n```\n\nExample:\n```javascript\nexport default function TodoList() {  return (    // ???  )}\n```\n\nExample:\n```text\nexport default function TodoList() {\n  return (\n    // This doesn't quite work!\n    <h1>Hedy Lamarr's Todos</h1>\n    <img\n      src=\"https://react.dev/images/docs/scientists/yXOvdOSs.jpg\"\n      alt=\"Hedy Lamarr\"\n      class=\"photo\"\n    >\n    <ul>\n      <li>Invent new traffic lights\n      <li>Rehearse a movie scene\n      <li>Improve the spectrum technology\n    </ul>\n```\n\nExample:\n```javascript\n<div>  <h1>Hedy Lamarr's Todos</h1>  <img    src=\"https://react.dev/images/docs/scientists/yXOvdOSs.jpg\"    alt=\"Hedy Lamarr\"    class=\"photo\"  >  <ul>    ...  </ul></div>\n```\n\nExample:\n```javascript\n<>  <h1>Hedy Lamarr's Todos</h1>  <img    src=\"https://react.dev/images/docs/scientists/yXOvdOSs.jpg\"    alt=\"Hedy Lamarr\"    class=\"photo\"  >  <ul>    ...  </ul></>\n```\n\nExample:\n```javascript\n<>  <img    src=\"https://react.dev/images/docs/scientists/yXOvdOSs.jpg\"    alt=\"Hedy Lamarr\"    class=\"photo\"   />  <ul>    <li>Invent new traffic lights</li>    <li>Rehearse a movie scene</li>    <li>Improve the spectrum technology</li>  </ul></>\n```\n\nExample:\n```javascript\n<img  src=\"https://react.dev/images/docs/scientists/yXOvdOSs.jpg\"  alt=\"Hedy Lamarr\"  className=\"photo\"/>\n```\n\nExample:\n```text\nexport default function TodoList() {\n  return (\n    <>\n      <h1>Hedy Lamarr's Todos</h1>\n      <img\n        src=\"https://react.dev/images/docs/scientists/yXOvdOSs.jpg\"\n        alt=\"Hedy Lamarr\"\n        className=\"photo\"\n      />\n      <ul>\n        <li>Invent new traffic lights</li>\n        <li>Rehearse a movie scene</li>\n        <li>Improve the spectrum technology</li>\n      </ul>\n    </>\n  );\n}\n```\n\nExample:\n```text\nexport default function Bio() {\n  return (\n    <div class=\"intro\">\n      <h1>Welcome to my website!</h1>\n    </div>\n    <p class=\"summary\">\n      You can find my thoughts here.\n      <br><br>\n      <b>And <i>pictures</b></i> of scientists!\n    </p>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.865Z","totalSectionsIncluded":0,"totalCodeBlocksIncluded":9,"totalLines":86,"estimatedTokens":566}}14{"id":"doc-passing_props_to_a_component_react-43f69f50","source":"documentation","title":"Passing Props to a Component – React","url":"https://react.dev/learn/passing-props-to-a-component","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactDescribing the UICopy pageCopyPassing Props to a ComponentReact components use props to communicate with each other. Every parent component can pass some information to its child components by giving them props. Props might remind you of HTML attributes, but you can pass any JavaScript value through them, including objects, arrays, and functions. You will learn How to pass props to a component How to read props from a component How to specify default values for props How to pass some JSX to a component How props change over time Familiar props Props are the information that you pass to a JSX tag. For example, className, src, alt, width, and height are some of the props you can pass to an <img>: App.jsApp.jsReloadClearForkfunction Avatar() { return ( <img className=\"avatar\" src=\"https://react.dev/images/docs/scientists/1bX5QH6.jpg\" alt=\"Lin Lanying\" width={100} height={100} /> ); } export default function Profile() { return ( <Avatar /> ); } Show more The props you can pass to an <img> tag are predefined (ReactDOM conforms to the HTML standard). But you can pass any props to your own components, such as <Avatar>, to customize them. Here’s how! Passing props to a component In this code, the Profile component isn’t passing any props to its child component, default function Profile() { return ( <Avatar /> );} You can give Avatar some props in two steps. Step props to the child component First, pass some props to Avatar. For example, let’s pass two (an object), and size (a number): export default function Profile() { return ( <Avatar person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }} size={100} /> );} NoteIf double curly braces after person= confuse you, recall they’re merely an object inside the JSX curlies. Now you can read these props inside the Avatar component. Step props inside the child component You can read these props by listing their names person, size separated by the commas inside ({ and }) directly after function Avatar. This lets you use them inside the Avatar code, like you would with a variable. function Avatar({ person, size }) { // person and size are available here} Add some logic to Avatar that uses the person and size props for rendering, and you’re done. Now you can configure Avatar to render in many different ways with different props. Try tweaking the values! App.jsutils.jsApp.jsReloadClearForkimport { getImageUrl } from './utils.js'; function Avatar({ person, size }) { return ( <img className=\"avatar\" src={getImageUrl(person)} alt={person.name} width={size} height={size} /> ); } export default function Profile() { return ( <div> <Avatar size={100} person={{ name: 'Katsuko Saruhashi', imageId: 'YfeOqp2' }} /> <Avatar size={80} person={{ name: 'Aklilu Lemma', imageId: 'OKS67lh' }} /> <Avatar size={50} person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }} /> </div> ); } Show more Props let you think about parent and child components independently. For example, you can change the person or the size props inside Profile without having to think about how Avatar uses them. Similarly, you can change how the Avatar uses these props, without looking at the Profile. You can think of props like “knobs” that you can adjust. They serve the same role as arguments serve for functions—in fact, props are the only argument to your component! React component functions accept a single argument, a props Avatar(props) { let person = props.person; let size = props.size; // ...} Usually you don’t need the whole props object itself, so you destructure it into individual props. PitfallDon’t miss the pair of { and } curlies inside of ( and ) when declaring Avatar({ person, size }) { // ...}This syntax is called “destructuring” and is equivalent to reading properties from a function Avatar(props) { let person = props.person; let size = props.size; // ...} Specifying a default value for a prop If you want to give a prop a default value to fall back on when no value is specified, you can do it with the destructuring by putting = and the default value right after the Avatar({ person, size = 100 }) { // ...} Now, if <Avatar person={...} /> is rendered with no size prop, the size will be set to 100. The default value is only used if the size prop is missing or if you pass size={undefined}. But if you pass size={null} or size={0}, the default value will not be used. Forwarding props with the JSX spread syntax Sometimes, passing props gets very Profile({ person, size, isSepia, thickBorder }) { return ( <div className=\"card\"> <Avatar person={person} size={size} isSepia={isSepia} thickBorder={thickBorder} /> </div> );} There’s nothing wrong with repetitive code—it can be more legible. But at times you may value conciseness. Some components forward all of their props to their children, like how this Profile does with Avatar. Because they don’t use any of their props directly, it can make sense to use a more concise “spread” Profile(props) { return ( <div className=\"card\"> <Avatar {...props} /> </div> );} This forwards all of Profile’s props to the Avatar without listing each of their names. Use spread syntax with restraint. If you’re using it in every other component, something is wrong. Often, it indicates that you should split your components and pass children as JSX. More on that next! Passing JSX as children It is common to nest built-in browser tags: <div> <img /></div> Sometimes you’ll want to nest your own components the same way: <Card> <Avatar /></Card> When you nest content inside a JSX tag, the parent component will receive that content in a prop called children. For example, the Card component below will receive a children prop set to <Avatar /> and render it in a wrapper Avatar from './Avatar.js'; function Card({ children }) { return ( <div className=\"card\"> {children} </div> ); } export default function Profile() { return ( <Card> <Avatar size={100} person={{ name: 'Katsuko Saruhashi', imageId: 'YfeOqp2' }} /> </Card> ); } Show more Try replacing the <Avatar> inside <Card> with some text to see how the Card component can wrap any nested content. It doesn’t need to “know” what’s being rendered inside of it. You will see this flexible pattern in many places. You can think of a component with a children prop as having a “hole” that can be “filled in” by its parent components with arbitrary JSX. You will often use the children prop for visual , grids, etc. Illustrated by Rachel Lee Nabors How props change over time The Clock component below receives two props from its parent and time. (The parent component’s code is omitted because it uses state, which we won’t dive into just yet.) Try changing the color in the select box default function Clock({ color, time }) { return ( <h1 style={{ }}> {time} </h1> ); } This example illustrates that a component may receive different props over time. Props are not always static! Here, the time prop changes every second, and the color prop changes when you select another color. Props reflect a component’s data at any point in time, rather than only in the beginning. However, props are immutable—a term from computer science meaning “unchangeable”. When a component needs to change its props (for example, in response to a user interaction or new data), it will have to “ask” its parent component to pass it different props—a new object! Its old props will then be cast aside, and eventually the JavaScript engine will reclaim the memory taken by them. Don’t try to “change props”. When you need to respond to the user input (like changing the selected color), you will need to “set state”, which you can learn about in Component’s Memory. Recap To pass props, add them to the JSX, just like you would with HTML attributes. To read props, use the function Avatar({ person, size }) destructuring syntax. You can specify a default value like size = 100, which is used for missing and undefined props. You can forward all props with <Avatar {...props} /> JSX spread syntax, but don’t overuse it! Nested JSX like <Card><Avatar /></Card> will appear as Card component’s children prop. Props are read-only snapshots in render receives a new version of props. You can’t change props. When you need interactivity, you’ll need to set state. Try out some challenges1. Extract a component 2. Adjust the image size based on a prop 3. Passing JSX in a children prop Challenge 1 of a component This Gallery component contains some very similar markup for two profiles. Extract a Profile component out of it to reduce the duplication. You’ll need to choose what props to pass to it.App.jsutils.jsApp.jsReloadClearForkimport { getImageUrl } from './utils.js'; export default function Gallery() { return ( <div> <h1>Notable Scientists</h1> <section className=\"profile\"> <h2>Maria Skłodowska-Curie</h2> <img className=\"avatar\" src={getImageUrl('szV5sdG')} alt=\"Maria Skłodowska-Curie\" width={70} height={70} /> <ul> <li> <b>Profession: </b> physicist and chemist </li> <li> <b>Awards: 4 </b> (Nobel Prize in Physics, Nobel Prize in Chemistry, Davy Medal, Matteucci Medal) </li> <li> <b>Discovered: </b> polonium (chemical element) </li> </ul> </section> <section className=\"profile\"> <h2>Katsuko Saruhashi</h2> <img className=\"avatar\" src={getImageUrl('YfeOqp2')} alt=\"Katsuko Saruhashi\" width={70} height={70} /> <ul> <li> <b>Profession: </b> geochemist </li> <li> <b>Awards: 2 </b> (Miyake Prize for geochemistry, Tanaka Prize) </li> <li> <b>Discovered: </b> a method for measuring carbon dioxide in seawater </li> </ul> </section> </div> ); } Show more Show hint Show solutionNext ChallengePreviousJavaScript in JSX with Curly BracesNextConditional RenderingCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewFamiliar props Passing props to a component Step props to the child component Step props inside the child component Specifying a default value for a prop Forwarding props with the JSX spread syntax Passing JSX as children How props change over time RecapChallenges\n\nExample:\n```text\nfunction Avatar() {\n  return (\n    <img\n      className=\"avatar\"\n      src=\"https://react.dev/images/docs/scientists/1bX5QH6.jpg\"\n      alt=\"Lin Lanying\"\n      width={100}\n      height={100}\n    />\n  );\n}\n\nexport default function Profile() {\n  return (\n    <Avatar />\n  );\n}\n```\n\nExample:\n```javascript\nexport default function Profile() {  return (    <Avatar />  );}\n```\n\nExample:\n```javascript\nexport default function Profile() {  return (    <Avatar      person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }}      size={100}    />  );}\n```\n\nExample:\n```javascript\nfunction Avatar({ person, size }) {  // person and size are available here}\n```\n\nExample:\n```text\nimport { getImageUrl } from './utils.js';\n\nfunction Avatar({ person, size }) {\n  return (\n    <img\n      className=\"avatar\"\n      src={getImageUrl(person)}\n      alt={person.name}\n      width={size}\n      height={size}\n    />\n  );\n}\n\nexport default function Profile() {\n  return (\n    <div>\n      <Avatar\n        size={100}\n        person={{\n          name: 'Katsuko Saruhashi',\n          imageId: 'YfeOqp2'\n        }}\n      />\n      <Avatar\n        size={80}\n        person={{\n          name: 'Aklilu Lemma',\n          imageId: 'OKS67lh'\n        }}\n      />\n      <Avatar\n        size={50}\n        person={{\n          name: 'Lin Lanying',\n          imageId: '1bX5QH6'\n        }}\n      />\n    </div>\n  );\n}\n```\n\nExample:\n```javascript\nfunction Avatar(props) {  let person = props.person;  let size = props.size;  // ...}\n```\n\nExample:\n```javascript\nfunction Avatar({ person, size }) {  // ...}\n```\n\nExample:\n```javascript\nfunction Avatar({ person, size = 100 }) {  // ...}\n```\n\nExample:\n```javascript\nfunction Profile({ person, size, isSepia, thickBorder }) {  return (    <div className=\"card\">      <Avatar        person={person}        size={size}        isSepia={isSepia}        thickBorder={thickBorder}      />    </div>  );}\n```\n\nExample:\n```javascript\nfunction Profile(props) {  return (    <div className=\"card\">      <Avatar {...props} />    </div>  );}\n```\n\nExample:\n```javascript\n<Card>  <Avatar /></Card>\n```\n\nExample:\n```text\nimport Avatar from './Avatar.js';\n\nfunction Card({ children }) {\n  return (\n    <div className=\"card\">\n      {children}\n    </div>\n  );\n}\n\nexport default function Profile() {\n  return (\n    <Card>\n      <Avatar\n        size={100}\n        person={{\n          name: 'Katsuko Saruhashi',\n          imageId: 'YfeOqp2'\n        }}\n      />\n    </Card>\n  );\n}\n```\n\nExample:\n```text\nexport default function Clock({ color, time }) {\n  return (\n    <h1 style={{ color: color }}>\n      {time}\n    </h1>\n  );\n}\n```\n\nExample:\n```text\nimport { getImageUrl } from './utils.js';\n\nexport default function Gallery() {\n  return (\n    <div>\n      <h1>Notable Scientists</h1>\n      <section className=\"profile\">\n        <h2>Maria Skłodowska-Curie</h2>\n        <img\n          className=\"avatar\"\n          src={getImageUrl('szV5sdG')}\n          alt=\"Maria Skłodowska-Curie\"\n          width={70}\n          height={70}\n        />\n        <ul>\n          <li>\n            <b>Profession: </b>\n            physicist and chemist\n          </li>\n          <li>\n            <b>Awards: 4 </b>\n            (Nobel Prize in Physics, Nobel Prize in Chemistry, Davy Medal, Matteucci Medal)\n          </li>\n          <li>\n            <b>Discovered: </b>\n            polonium (chemical element)\n          </li>\n        </ul>\n      </section>\n      <section className=\"profile\">\n        <h2>Katsuko Saruhashi</h2>\n        <img\n          className=\"avatar\"\n          src={getImageUrl('YfeOqp2')}\n          alt=\"Katsuko Saruhashi\"\n          width={70}\n          height={70}\n        />\n        <ul>\n          <li>\n            <b>Profession: </b>\n            geochemist\n          </li>\n          <li>\n            <b>Awards: 2 </b>\n            (Miyake Prize for geochemistry, Tanaka Prize)\n          </li>\n          <li>\n            <b>Discovered: </b>\n            a method for measuring carbon dioxide in seawater\n          </li>\n        </ul>\n      </section>\n    </div>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.866Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":14,"totalLines":213,"estimatedTokens":3888}}15{"id":"doc-conditional_rendering_react-a3183b31","source":"documentation","title":"Conditional Rendering – React","url":"https://react.dev/learn/conditional-rendering","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactDescribing the UICopy pageCopyConditional RenderingYour components will often need to display different things depending on different conditions. In React, you can conditionally render JSX using JavaScript syntax like if statements, &&, and ? : operators. You will learn How to return different JSX depending on a condition How to conditionally include or exclude a piece of JSX Common conditional syntax shortcuts you’ll encounter in React codebases Conditionally returning JSX Let’s say you have a PackingList component rendering several Items, which can be marked as packed or Item({ name, isPacked }) { return <li className=\"item\">{name}</li>; } export default function PackingList() { return ( <section> <h1>Sally Ride's Packing List</h1> <ul> <Item isPacked={true} name=\"Space suit\" /> <Item isPacked={true} name=\"Helmet with a golden leaf\" /> <Item isPacked={false} name=\"Photo of Tam\" /> </ul> </section> ); } Show more Notice that some of the Item components have their isPacked prop set to true instead of false. You want to add a checkmark (✅) to packed items if isPacked={true}. You can write this as an if/else statement like (isPacked) { return <li className=\"item\">{name} ✅</li>;}return <li className=\"item\">{name}</li>; If the isPacked prop is true, this code returns a different JSX tree. With this change, some of the items get a checkmark at the Item({ name, isPacked }) { if (isPacked) { return <li className=\"item\">{name} ✅</li>; } return <li className=\"item\">{name}</li>; } export default function PackingList() { return ( <section> <h1>Sally Ride's Packing List</h1> <ul> <Item isPacked={true} name=\"Space suit\" /> <Item isPacked={true} name=\"Helmet with a golden leaf\" /> <Item isPacked={false} name=\"Photo of Tam\" /> </ul> </section> ); } Show more Try editing what gets returned in either case, and see how the result changes! Notice how you’re creating branching logic with JavaScript’s if and return statements. In React, control flow (like conditions) is handled by JavaScript. Conditionally returning nothing with null In some situations, you won’t want to render anything at all. For example, say you don’t want to show packed items at all. A component must return something. In this case, you can return (isPacked) { return null;}return <li className=\"item\">{name}</li>; If isPacked is true, the component will return nothing, null. Otherwise, it will return JSX to render. App.jsApp.jsReloadClearForkfunction Item({ name, isPacked }) { if (isPacked) { return null; } return <li className=\"item\">{name}</li>; } export default function PackingList() { return ( <section> <h1>Sally Ride's Packing List</h1> <ul> <Item isPacked={true} name=\"Space suit\" /> <Item isPacked={true} name=\"Helmet with a golden leaf\" /> <Item isPacked={false} name=\"Photo of Tam\" /> </ul> </section> ); } Show more In practice, returning null from a component isn’t common because it might surprise a developer trying to render it. More often, you would conditionally include or exclude the component in the parent component’s JSX. Here’s how to do that! Conditionally including JSX In the previous example, you controlled which (if any!) JSX tree would be returned by the component. You may already have noticed some duplication in the render output: <li className=\"item\">{name} ✅</li> is very similar to <li className=\"item\">{name}</li> Both of the conditional branches return <li className=\"item\">...</li>: if (isPacked) { return <li className=\"item\">{name} ✅</li>;}return <li className=\"item\">{name}</li>; While this duplication isn’t harmful, it could make your code harder to maintain. What if you want to change the className? You’d have to do it in two places in your code! In such a situation, you could conditionally include a little JSX to make your code more DRY. Conditional (ternary) operator (? :) JavaScript has a compact syntax for writing a conditional expression — the conditional operator or “ternary operator”. Instead of (isPacked) { return <li className=\"item\">{name} ✅</li>;}return <li className=\"item\">{name}</li>; You can write ( <li className=\"item\"> {isPacked ? name + ' ✅' : name} </li>); You can read it as “if isPacked is true, then (?) render name + ' ✅', otherwise (:) render name”. Deep DiveAre these two examples fully equivalent? Show DetailsIf you’re coming from an object-oriented programming background, you might assume that the two examples above are subtly different because one of them may create two different “instances” of <li>. But JSX elements aren’t “instances” because they don’t hold any internal state and aren’t real DOM nodes. They’re lightweight descriptions, like blueprints. So these two examples, in fact, are completely equivalent. Preserving and Resetting State goes into detail about how this works. Now let’s say you want to wrap the completed item’s text into another HTML tag, like <del> to strike it out. You can add even more newlines and parentheses so that it’s easier to nest more JSX in each of the Item({ name, isPacked }) { return ( <li className=\"item\"> {isPacked ? ( <del> {name + ' ✅'} </del> ) : ( name )} </li> ); } export default function PackingList() { return ( <section> <h1>Sally Ride's Packing List</h1> <ul> <Item isPacked={true} name=\"Space suit\" /> <Item isPacked={true} name=\"Helmet with a golden leaf\" /> <Item isPacked={false} name=\"Photo of Tam\" /> </ul> </section> ); } Show more This style works well for simple conditions, but use it in moderation. If your components get messy with too much nested conditional markup, consider extracting child components to clean things up. In React, markup is a part of your code, so you can use tools like variables and functions to tidy up complex expressions. Logical AND operator (&&) Another common shortcut you’ll encounter is the JavaScript logical AND (&&) operator. Inside React components, it often comes up when you want to render some JSX when the condition is true, or render nothing otherwise. With &&, you could conditionally render the checkmark only if isPacked is ( <li className=\"item\"> {name} {isPacked && '✅'} </li>); You can read this as “if isPacked, then (&&) render the checkmark, otherwise, render nothing”. Here it is in Item({ name, isPacked }) { return ( <li className=\"item\"> {name} {isPacked && '✅'} </li> ); } export default function PackingList() { return ( <section> <h1>Sally Ride's Packing List</h1> <ul> <Item isPacked={true} name=\"Space suit\" /> <Item isPacked={true} name=\"Helmet with a golden leaf\" /> <Item isPacked={false} name=\"Photo of Tam\" /> </ul> </section> ); } Show more A JavaScript && expression returns the value of its right side (in our case, the checkmark) if the left side (our condition) is true. But if the condition is false, the whole expression becomes false. React considers false as a “hole” in the JSX tree, just like null or undefined, and doesn’t render anything in its place. PitfallDon’t put numbers on the left side of &&.To test the condition, JavaScript converts the left side to a boolean automatically. However, if the left side is 0, then the whole expression gets that value (0), and React will happily render 0 rather than nothing.For example, a common mistake is to write code like messageCount && <p>New messages</p>. It’s easy to assume that it renders nothing when messageCount is 0, but it really renders the 0 itself!To fix it, make the left side a > 0 && <p>New messages</p>. Conditionally assigning JSX to a variable When the shortcuts get in the way of writing plain code, try using an if statement and a variable. You can reassign variables defined with let, so start by providing the default content you want to display, the itemContent = name; Use an if statement to reassign a JSX expression to itemContent if isPacked is (isPacked) { itemContent = name + \" ✅\";} Curly braces open the “window into JavaScript”. Embed the variable with curly braces in the returned JSX tree, nesting the previously calculated expression inside of JSX: <li className=\"item\"> {itemContent}</li> This style is the most verbose, but it’s also the most flexible. Here it is in Item({ name, isPacked }) { let itemContent = name; if (isPacked) { itemContent = name + \" ✅\"; } return ( <li className=\"item\"> {itemContent} </li> ); } export default function PackingList() { return ( <section> <h1>Sally Ride's Packing List</h1> <ul> <Item isPacked={true} name=\"Space suit\" /> <Item isPacked={true} name=\"Helmet with a golden leaf\" /> <Item isPacked={false} name=\"Photo of Tam\" /> </ul> </section> ); } Show more Like before, this works not only for text, but for arbitrary JSX Item({ name, isPacked }) { let itemContent = name; if (isPacked) { itemContent = ( <del> {name + \" ✅\"} </del> ); } return ( <li className=\"item\"> {itemContent} </li> ); } export default function PackingList() { return ( <section> <h1>Sally Ride's Packing List</h1> <ul> <Item isPacked={true} name=\"Space suit\" /> <Item isPacked={true} name=\"Helmet with a golden leaf\" /> <Item isPacked={false} name=\"Photo of Tam\" /> </ul> </section> ); } Show more If you’re not familiar with JavaScript, this variety of styles might seem overwhelming at first. However, learning them will help you read and write any JavaScript code — and not just React components! Pick the one you prefer for a start, and then consult this reference again if you forget how the other ones work. Recap In React, you control branching logic with JavaScript. You can return a JSX expression conditionally with an if statement. You can conditionally save some JSX to a variable and then include it inside other JSX by using the curly braces. In JSX, {cond ? <A /> : <B />} means “if cond, render <A />, otherwise <B />”. In JSX, {cond && <A />} means “if cond, render <A />, otherwise nothing”. The shortcuts are common, but you don’t have to use them if you prefer plain if. Try out some challenges1. Show an icon for incomplete items with ? : 2. Show the item importance with && 3. Refactor a series of ? : to if and variables Challenge 1 of an icon for incomplete items with ? : Use the conditional operator (cond ? ) to render a ❌ if isPacked isn’t true.App.jsApp.jsReloadClearForkfunction Item({ name, isPacked }) { return ( <li className=\"item\"> {name} {isPacked && '✅'} </li> ); } export default function PackingList() { return ( <section> <h1>Sally Ride's Packing List</h1> <ul> <Item isPacked={true} name=\"Space suit\" /> <Item isPacked={true} name=\"Helmet with a golden leaf\" /> <Item isPacked={false} name=\"Photo of Tam\" /> </ul> </section> ); } Show more Show solutionNext ChallengePreviousPassing Props to a ComponentNextRendering ListsCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewConditionally returning JSX Conditionally returning nothing with null Conditionally including JSX Conditional (ternary) operator (? :) Logical AND operator (&&) Conditionally assigning JSX to a variable RecapChallenges\n\nExample:\n```text\nfunction Item({ name, isPacked }) {\n  return <li className=\"item\">{name}</li>;\n}\n\nexport default function PackingList() {\n  return (\n    <section>\n      <h1>Sally Ride's Packing List</h1>\n      <ul>\n        <Item\n          isPacked={true}\n          name=\"Space suit\"\n        />\n        <Item\n          isPacked={true}\n          name=\"Helmet with a golden leaf\"\n        />\n        <Item\n          isPacked={false}\n          name=\"Photo of Tam\"\n        />\n      </ul>\n    </section>\n  );\n}\n```\n\nExample:\n```javascript\nif (isPacked) {  return <li className=\"item\">{name} ✅</li>;}return <li className=\"item\">{name}</li>;\n```\n\nExample:\n```text\nfunction Item({ name, isPacked }) {\n  if (isPacked) {\n    return <li className=\"item\">{name} ✅</li>;\n  }\n  return <li className=\"item\">{name}</li>;\n}\n\nexport default function PackingList() {\n  return (\n    <section>\n      <h1>Sally Ride's Packing List</h1>\n      <ul>\n        <Item\n          isPacked={true}\n          name=\"Space suit\"\n        />\n        <Item\n          isPacked={true}\n          name=\"Helmet with a golden leaf\"\n        />\n        <Item\n          isPacked={false}\n          name=\"Photo of Tam\"\n        />\n      </ul>\n    </section>\n  );\n}\n```\n\nExample:\n```javascript\nif (isPacked) {  return null;}return <li className=\"item\">{name}</li>;\n```\n\nExample:\n```text\nfunction Item({ name, isPacked }) {\n  if (isPacked) {\n    return null;\n  }\n  return <li className=\"item\">{name}</li>;\n}\n\nexport default function PackingList() {\n  return (\n    <section>\n      <h1>Sally Ride's Packing List</h1>\n      <ul>\n        <Item\n          isPacked={true}\n          name=\"Space suit\"\n        />\n        <Item\n          isPacked={true}\n          name=\"Helmet with a golden leaf\"\n        />\n        <Item\n          isPacked={false}\n          name=\"Photo of Tam\"\n        />\n      </ul>\n    </section>\n  );\n}\n```\n\nExample:\n```javascript\nreturn (  <li className=\"item\">    {isPacked ? name + ' ✅' : name}  </li>);\n```\n\nExample:\n```text\nfunction Item({ name, isPacked }) {\n  return (\n    <li className=\"item\">\n      {isPacked ? (\n        <del>\n          {name + ' ✅'}\n        </del>\n      ) : (\n        name\n      )}\n    </li>\n  );\n}\n\nexport default function PackingList() {\n  return (\n    <section>\n      <h1>Sally Ride's Packing List</h1>\n      <ul>\n        <Item\n          isPacked={true}\n          name=\"Space suit\"\n        />\n        <Item\n          isPacked={true}\n          name=\"Helmet with a golden leaf\"\n        />\n        <Item\n          isPacked={false}\n          name=\"Photo of Tam\"\n        />\n      </ul>\n    </section>\n  );\n}\n```\n\nExample:\n```javascript\nreturn (  <li className=\"item\">    {name} {isPacked && '✅'}  </li>);\n```\n\nExample:\n```text\nfunction Item({ name, isPacked }) {\n  return (\n    <li className=\"item\">\n      {name} {isPacked && '✅'}\n    </li>\n  );\n}\n\nexport default function PackingList() {\n  return (\n    <section>\n      <h1>Sally Ride's Packing List</h1>\n      <ul>\n        <Item\n          isPacked={true}\n          name=\"Space suit\"\n        />\n        <Item\n          isPacked={true}\n          name=\"Helmet with a golden leaf\"\n        />\n        <Item\n          isPacked={false}\n          name=\"Photo of Tam\"\n        />\n      </ul>\n    </section>\n  );\n}\n```\n\nExample:\n```javascript\nlet itemContent = name;\n```\n\nExample:\n```javascript\nif (isPacked) {  itemContent = name + \" ✅\";}\n```\n\nExample:\n```text\nfunction Item({ name, isPacked }) {\n  let itemContent = name;\n  if (isPacked) {\n    itemContent = name + \" ✅\";\n  }\n  return (\n    <li className=\"item\">\n      {itemContent}\n    </li>\n  );\n}\n\nexport default function PackingList() {\n  return (\n    <section>\n      <h1>Sally Ride's Packing List</h1>\n      <ul>\n        <Item\n          isPacked={true}\n          name=\"Space suit\"\n        />\n        <Item\n          isPacked={true}\n          name=\"Helmet with a golden leaf\"\n        />\n        <Item\n          isPacked={false}\n          name=\"Photo of Tam\"\n        />\n      </ul>\n    </section>\n  );\n}\n```\n\nExample:\n```text\nfunction Item({ name, isPacked }) {\n  let itemContent = name;\n  if (isPacked) {\n    itemContent = (\n      <del>\n        {name + \" ✅\"}\n      </del>\n    );\n  }\n  return (\n    <li className=\"item\">\n      {itemContent}\n    </li>\n  );\n}\n\nexport default function PackingList() {\n  return (\n    <section>\n      <h1>Sally Ride's Packing List</h1>\n      <ul>\n        <Item\n          isPacked={true}\n          name=\"Space suit\"\n        />\n        <Item\n          isPacked={true}\n          name=\"Helmet with a golden leaf\"\n        />\n        <Item\n          isPacked={false}\n          name=\"Photo of Tam\"\n        />\n      </ul>\n    </section>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.868Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":13,"totalLines":276,"estimatedTokens":4270}}16{"id":"doc-responding_to_events_react-db4d75a0","source":"documentation","title":"Responding to Events – React","url":"https://react.dev/learn/responding-to-events","text":"Example:\n```text\nexport default function Button() {\n  return (\n    <button>\n      I don't do anything\n    </button>\n  );\n}\n```\n\nExample:\n```text\nexport default function Button() {\n  function handleClick() {\n    alert('You clicked me!');\n  }\n\n  return (\n    <button onClick={handleClick}>\n      Click me\n    </button>\n  );\n}\n```\n\nExample:\n```javascript\n<button onClick={function handleClick() {  alert('You clicked me!');}}>\n```\n\nExample:\n```javascript\n<button onClick={() => {  alert('You clicked me!');}}>\n```\n\nExample:\n```javascript\n// This alert fires when the component renders, not when clicked!<button onClick={alert('You clicked me!')}>\n```\n\nExample:\n```javascript\n<button onClick={() => alert('You clicked me!')}>\n```\n\nExample:\n```text\nfunction AlertButton({ message, children }) {\n  return (\n    <button onClick={() => alert(message)}>\n      {children}\n    </button>\n  );\n}\n\nexport default function Toolbar() {\n  return (\n    <div>\n      <AlertButton message=\"Playing!\">\n        Play Movie\n      </AlertButton>\n      <AlertButton message=\"Uploading!\">\n        Upload Image\n      </AlertButton>\n    </div>\n  );\n}\n```\n\nExample:\n```text\nfunction Button({ onClick, children }) {\n  return (\n    <button onClick={onClick}>\n      {children}\n    </button>\n  );\n}\n\nfunction PlayButton({ movieName }) {\n  function handlePlayClick() {\n    alert(`Playing ${movieName}!`);\n  }\n\n  return (\n    <Button onClick={handlePlayClick}>\n      Play \"{movieName}\"\n    </Button>\n  );\n}\n\nfunction UploadButton() {\n  return (\n    <Button onClick={() => alert('Uploading!')}>\n      Upload Image\n    </Button>\n  );\n}\n\nexport default function Toolbar() {\n  return (\n    <div>\n      <PlayButton movieName=\"Kiki's Delivery Service\" />\n      <UploadButton />\n    </div>\n  );\n}\n```\n\nExample:\n```text\nfunction Button({ onSmash, children }) {\n  return (\n    <button onClick={onSmash}>\n      {children}\n    </button>\n  );\n}\n\nexport default function App() {\n  return (\n    <div>\n      <Button onSmash={() => alert('Playing!')}>\n        Play Movie\n      </Button>\n      <Button onSmash={() => alert('Uploading!')}>\n        Upload Image\n      </Button>\n    </div>\n  );\n}\n```\n\nExample:\n```text\nexport default function App() {\n  return (\n    <Toolbar\n      onPlayMovie={() => alert('Playing!')}\n      onUploadImage={() => alert('Uploading!')}\n    />\n  );\n}\n\nfunction Toolbar({ onPlayMovie, onUploadImage }) {\n  return (\n    <div>\n      <Button onClick={onPlayMovie}>\n        Play Movie\n      </Button>\n      <Button onClick={onUploadImage}>\n        Upload Image\n      </Button>\n    </div>\n  );\n}\n\nfunction Button({ onClick, children }) {\n  return (\n    <button onClick={onClick}>\n      {children}\n    </button>\n  );\n}\n```\n\nExample:\n```text\nexport default function Toolbar() {\n  return (\n    <div className=\"Toolbar\" onClick={() => {\n      alert('You clicked on the toolbar!');\n    }}>\n      <button onClick={() => alert('Playing!')}>\n        Play Movie\n      </button>\n      <button onClick={() => alert('Uploading!')}>\n        Upload Image\n      </button>\n    </div>\n  );\n}\n```\n\nExample:\n```text\nfunction Button({ onClick, children }) {\n  return (\n    <button onClick={e => {\n      e.stopPropagation();\n      onClick();\n    }}>\n      {children}\n    </button>\n  );\n}\n\nexport default function Toolbar() {\n  return (\n    <div className=\"Toolbar\" onClick={() => {\n      alert('You clicked on the toolbar!');\n    }}>\n      <Button onClick={() => alert('Playing!')}>\n        Play Movie\n      </Button>\n      <Button onClick={() => alert('Uploading!')}>\n        Upload Image\n      </Button>\n    </div>\n  );\n}\n```\n\nExample:\n```javascript\nfunction Button({ onClick, children }) {  return (    <button onClick={e => {      e.stopPropagation();      onClick();    }}>      {children}    </button>  );}\n```\n\nExample:\n```text\nexport default function Signup() {\n  return (\n    <form onSubmit={() => alert('Submitting!')}>\n      <input />\n      <button>Send</button>\n    </form>\n  );\n}\n```\n\nExample:\n```text\nexport default function Signup() {\n  return (\n    <form onSubmit={e => {\n      e.preventDefault();\n      alert('Submitting!');\n    }}>\n      <input />\n      <button>Send</button>\n    </form>\n  );\n}\n```\n\nExample:\n```text\nexport default function LightSwitch() {\n  function handleClick() {\n    let bodyStyle = document.body.style;\n    if (bodyStyle.backgroundColor === 'black') {\n      bodyStyle.backgroundColor = 'white';\n    } else {\n      bodyStyle.backgroundColor = 'black';\n    }\n  }\n\n  return (\n    <button onClick={handleClick()}>\n      Toggle the lights\n    </button>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.869Z","totalSectionsIncluded":0,"totalCodeBlocksIncluded":16,"totalLines":267,"estimatedTokens":1140}}17{"id":"doc-sharing_state_between_components_react-b2474c67","source":"documentation","title":"Sharing State Between Components – React","url":"https://react.dev/learn/sharing-state-between-components","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactManaging StateCopy pageCopySharing State Between ComponentsSometimes, you want the state of two components to always change together. To do it, remove state from both of them, move it to their closest common parent, and then pass it down to them via props. This is known as lifting state up, and it’s one of the most common things you will do writing React code. You will learn How to share state between components by lifting it up What are controlled and uncontrolled components Lifting state up by example In this example, a parent Accordion component renders two separate Panel Panel Each Panel component has a boolean isActive state that determines whether its content is visible. Press the Show button for both { useState } from 'react'; function Panel({ title, children }) { const [isActive, setIsActive] = useState(false); return ( <section className=\"panel\"> <h3>{title}</h3> {isActive ? ( <p>{children}</p> ) : ( <button onClick={() => setIsActive(true)}> Show </button> )} </section> ); } export default function Accordion() { return ( <> <h2>Almaty, Kazakhstan</h2> <Panel title=\"About\"> With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city. </Panel> <Panel title=\"Etymology\"> The name comes from <span lang=\"kk-KZ\">алма</span>, the Kazakh word for \"apple\" and is often translated as \"full of apples\". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang=\"la\">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple. </Panel> </> ); } Show more Notice how pressing one panel’s button does not affect the other panel—they are independent. Initially, each Panel’s isActive state is false, so they both appear collapsedClicking either Panel’s button will only update that Panel’s isActive state alone But now let’s say you want to change it so that only one panel is expanded at any given time. With that design, expanding the second panel should collapse the first one. How would you do that? To coordinate these two panels, you need to “lift their state up” to a parent component in three state from the child components. Pass hardcoded data from the common parent. Add state to the common parent and pass it down together with the event handlers. This will allow the Accordion component to coordinate both Panels and only expand one at a time. Step state from the child components You will give control of the Panel’s isActive to its parent component. This means that the parent component will pass isActive to Panel as a prop instead. Start by removing this line from the Panel [isActive, setIsActive] = useState(false); And instead, add isActive to the Panel’s list of Panel({ title, children, isActive }) { Now the Panel’s parent component can control isActive by passing it down as a prop. Conversely, the Panel component now has no control over the value of isActive—it’s now up to the parent component! Step hardcoded data from the common parent To lift state up, you must locate the closest common parent component of both of the child components that you want to (closest common parent) Panel Panel In this example, it’s the Accordion component. Since it’s above both panels and can control their props, it will become the “source of truth” for which panel is currently active. Make the Accordion component pass a hardcoded value of isActive (for example, true) to both { useState } from 'react'; export default function Accordion() { return ( <> <h2>Almaty, Kazakhstan</h2> <Panel title=\"About\" isActive={true}> With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city. </Panel> <Panel title=\"Etymology\" isActive={true}> The name comes from <span lang=\"kk-KZ\">алма</span>, the Kazakh word for \"apple\" and is often translated as \"full of apples\". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang=\"la\">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple. </Panel> </> ); } function Panel({ title, children, isActive }) { return ( <section className=\"panel\"> <h3>{title}</h3> {isActive ? ( <p>{children}</p> ) : ( <button onClick={() => setIsActive(true)}> Show </button> )} </section> ); } Show more Try editing the hardcoded isActive values in the Accordion component and see the result on the screen. Step state to the common parent Lifting state up often changes the nature of what you’re storing as state. In this case, only one panel should be active at a time. This means that the Accordion common parent component needs to keep track of which panel is the active one. Instead of a boolean value, it could use a number as the index of the active Panel for the state [activeIndex, setActiveIndex] = useState(0); When the activeIndex is 0, the first panel is active, and when it’s 1, it’s the second one. Clicking the “Show” button in either Panel needs to change the active index in Accordion. A Panel can’t set the activeIndex state directly because it’s defined inside the Accordion. The Accordion component needs to explicitly allow the Panel component to change its state by passing an event handler down as a prop: <> <Panel isActive={activeIndex === 0} onShow={() => setActiveIndex(0)} > ... </Panel> <Panel isActive={activeIndex === 1} onShow={() => setActiveIndex(1)} > ... </Panel></> The <button> inside the Panel will now use the onShow prop as its click event { useState } from 'react'; export default function Accordion() { const [activeIndex, setActiveIndex] = useState(0); return ( <> <h2>Almaty, Kazakhstan</h2> <Panel title=\"About\" isActive={activeIndex === 0} onShow={() => setActiveIndex(0)} > With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city. </Panel> <Panel title=\"Etymology\" isActive={activeIndex === 1} onShow={() => setActiveIndex(1)} > The name comes from <span lang=\"kk-KZ\">алма</span>, the Kazakh word for \"apple\" and is often translated as \"full of apples\". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang=\"la\">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple. </Panel> </> ); } function Panel({ title, children, isActive, onShow }) { return ( <section className=\"panel\"> <h3>{title}</h3> {isActive ? ( <p>{children}</p> ) : ( <button onClick={onShow}> Show </button> )} </section> ); } Show more This completes lifting state up! Moving state into the common parent component allowed you to coordinate the two panels. Using the active index instead of two “is shown” flags ensured that only one panel is active at a given time. And passing down the event handler to the child allowed the child to change the parent’s state. Initially, Accordion’s activeIndex is 0, so the first Panel receives isActive = trueWhen Accordion’s activeIndex state changes to 1, the second Panel receives isActive = true instead Deep DiveControlled and uncontrolled components Show DetailsIt is common to call a component with some local state “uncontrolled”. For example, the original Panel component with an isActive state variable is uncontrolled because its parent cannot influence whether the panel is active or not.In contrast, you might say a component is “controlled” when the important information in it is driven by props rather than its own local state. This lets the parent component fully specify its behavior. The final Panel component with the isActive prop is controlled by the Accordion component.Uncontrolled components are easier to use within their parents because they require less configuration. But they’re less flexible when you want to coordinate them together. Controlled components are maximally flexible, but they require the parent components to fully configure them with props.In practice, “controlled” and “uncontrolled” aren’t strict technical terms—each component usually has some mix of both local state and props. However, this is a useful way to talk about how components are designed and what capabilities they offer.When writing a component, consider which information in it should be controlled (via props), and which information should be uncontrolled (via state). But you can always change your mind and refactor later. A single source of truth for each state In a React application, many components will have their own state. Some state may “live” close to the leaf components (components at the bottom of the tree) like inputs. Other state may “live” closer to the top of the app. For example, even client-side routing libraries are usually implemented by storing the current route in the React state, and passing it down by props! For each unique piece of state, you will choose the component that “owns” it. This principle is also known as having a “single source of truth”. It doesn’t mean that all state lives in one place—but that for each piece of state, there is a specific component that holds that piece of information. Instead of duplicating shared state between components, lift it up to their common shared parent, and pass it down to the children that need it. Your app will change as you work on it. It is common that you will move state down or back up while you’re still figuring out where each piece of the state “lives”. This is all part of the process! To see what this feels like in practice with a few more components, read Thinking in React. Recap When you want to coordinate two components, move their state to their common parent. Then pass the information down through props from their common parent. Finally, pass the event handlers down so that the children can change the parent’s state. It’s useful to consider components as “controlled” (driven by props) or “uncontrolled” (driven by state). Try out some challenges1. Synced inputs 2. Filtering a list Challenge 1 of inputs These two inputs are independent. Make them stay in one input should update the other input with the same text, and vice versa.App.jsApp.jsReloadClearForkimport { useState } from 'react'; export default function SyncedInputs() { return ( <> <Input label=\"First input\" /> <Input label=\"Second input\" /> </> ); } function Input({ label }) { const [text, setText] = useState(''); function handleChange(e) { setText(e.target.value); } return ( <label> {label} {' '} <input value={text} onChange={handleChange} /> </label> ); } Show more Show hint Show solutionNext ChallengePreviousChoosing the State StructureNextPreserving and Resetting StateCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewLifting state up by example Step state from the child components Step hardcoded data from the common parent Step state to the common parent A single source of truth for each state RecapChallenges\n\nExample:\n```text\nimport { useState } from 'react';\n\nfunction Panel({ title, children }) {\n  const [isActive, setIsActive] = useState(false);\n  return (\n    <section className=\"panel\">\n      <h3>{title}</h3>\n      {isActive ? (\n        <p>{children}</p>\n      ) : (\n        <button onClick={() => setIsActive(true)}>\n          Show\n        </button>\n      )}\n    </section>\n  );\n}\n\nexport default function Accordion() {\n  return (\n    <>\n      <h2>Almaty, Kazakhstan</h2>\n      <Panel title=\"About\">\n        With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city.\n      </Panel>\n      <Panel title=\"Etymology\">\n        The name comes from <span lang=\"kk-KZ\">алма</span>, the Kazakh word for \"apple\" and is often translated as \"full of apples\". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang=\"la\">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple.\n      </Panel>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nconst [isActive, setIsActive] = useState(false);\n```\n\nExample:\n```javascript\nfunction Panel({ title, children, isActive }) {\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Accordion() {\n  return (\n    <>\n      <h2>Almaty, Kazakhstan</h2>\n      <Panel title=\"About\" isActive={true}>\n        With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city.\n      </Panel>\n      <Panel title=\"Etymology\" isActive={true}>\n        The name comes from <span lang=\"kk-KZ\">алма</span>, the Kazakh word for \"apple\" and is often translated as \"full of apples\". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang=\"la\">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple.\n      </Panel>\n    </>\n  );\n}\n\nfunction Panel({ title, children, isActive }) {\n  return (\n    <section className=\"panel\">\n      <h3>{title}</h3>\n      {isActive ? (\n        <p>{children}</p>\n      ) : (\n        <button onClick={() => setIsActive(true)}>\n          Show\n        </button>\n      )}\n    </section>\n  );\n}\n```\n\nExample:\n```javascript\nconst [activeIndex, setActiveIndex] = useState(0);\n```\n\nExample:\n```javascript\n<>  <Panel    isActive={activeIndex === 0}    onShow={() => setActiveIndex(0)}  >    ...  </Panel>  <Panel    isActive={activeIndex === 1}    onShow={() => setActiveIndex(1)}  >    ...  </Panel></>\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Accordion() {\n  const [activeIndex, setActiveIndex] = useState(0);\n  return (\n    <>\n      <h2>Almaty, Kazakhstan</h2>\n      <Panel\n        title=\"About\"\n        isActive={activeIndex === 0}\n        onShow={() => setActiveIndex(0)}\n      >\n        With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city.\n      </Panel>\n      <Panel\n        title=\"Etymology\"\n        isActive={activeIndex === 1}\n        onShow={() => setActiveIndex(1)}\n      >\n        The name comes from <span lang=\"kk-KZ\">алма</span>, the Kazakh word for \"apple\" and is often translated as \"full of apples\". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang=\"la\">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple.\n      </Panel>\n    </>\n  );\n}\n\nfunction Panel({\n  title,\n  children,\n  isActive,\n  onShow\n}) {\n  return (\n    <section className=\"panel\">\n      <h3>{title}</h3>\n      {isActive ? (\n        <p>{children}</p>\n      ) : (\n        <button onClick={onShow}>\n          Show\n        </button>\n      )}\n    </section>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function SyncedInputs() {\n  return (\n    <>\n      <Input label=\"First input\" />\n      <Input label=\"Second input\" />\n    </>\n  );\n}\n\nfunction Input({ label }) {\n  const [text, setText] = useState('');\n\n  function handleChange(e) {\n    setText(e.target.value);\n  }\n\n  return (\n    <label>\n      {label}\n      {' '}\n      <input\n        value={text}\n        onChange={handleChange}\n      />\n    </label>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.870Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":8,"totalLines":173,"estimatedTokens":4187}}18{"id":"doc-referencing_values_with_refs_react-c07e154c","source":"documentation","title":"Referencing Values with Refs – React","url":"https://react.dev/learn/referencing-values-with-refs","text":"Example:\n```javascript\nimport { useRef } from 'react';\n```\n\nExample:\n```javascript\nconst ref = useRef(0);\n```\n\nExample:\n```javascript\n{  current: 0 // The value you passed to useRef}\n```\n\nExample:\n```text\nimport { useRef } from 'react';\n\nexport default function Counter() {\n  let ref = useRef(0);\n\n  function handleClick() {\n    ref.current = ref.current + 1;\n    alert('You clicked ' + ref.current + ' times!');\n  }\n\n  return (\n    <button onClick={handleClick}>\n      Click me!\n    </button>\n  );\n}\n```\n\nExample:\n```javascript\nconst [startTime, setStartTime] = useState(null);const [now, setNow] = useState(null);\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Stopwatch() {\n  const [startTime, setStartTime] = useState(null);\n  const [now, setNow] = useState(null);\n\n  function handleStart() {\n    // Start counting.\n    setStartTime(Date.now());\n    setNow(Date.now());\n\n    setInterval(() => {\n      // Update the current time every 10ms.\n      setNow(Date.now());\n    }, 10);\n  }\n\n  let secondsPassed = 0;\n  if (startTime != null && now != null) {\n    secondsPassed = (now - startTime) / 1000;\n  }\n\n  return (\n    <>\n      <h1>Time passed: {secondsPassed.toFixed(3)}</h1>\n      <button onClick={handleStart}>\n        Start\n      </button>\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState, useRef } from 'react';\n\nexport default function Stopwatch() {\n  const [startTime, setStartTime] = useState(null);\n  const [now, setNow] = useState(null);\n  const intervalRef = useRef(null);\n\n  function handleStart() {\n    setStartTime(Date.now());\n    setNow(Date.now());\n\n    clearInterval(intervalRef.current);\n    intervalRef.current = setInterval(() => {\n      setNow(Date.now());\n    }, 10);\n  }\n\n  function handleStop() {\n    clearInterval(intervalRef.current);\n  }\n\n  let secondsPassed = 0;\n  if (startTime != null && now != null) {\n    secondsPassed = (now - startTime) / 1000;\n  }\n\n  return (\n    <>\n      <h1>Time passed: {secondsPassed.toFixed(3)}</h1>\n      <button onClick={handleStart}>\n        Start\n      </button>\n      <button onClick={handleStop}>\n        Stop\n      </button>\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Counter() {\n  const [count, setCount] = useState(0);\n\n  function handleClick() {\n    setCount(count + 1);\n  }\n\n  return (\n    <button onClick={handleClick}>\n      You clicked {count} times\n    </button>\n  );\n}\n```\n\nExample:\n```text\nimport { useRef } from 'react';\n\nexport default function Counter() {\n  let countRef = useRef(0);\n\n  function handleClick() {\n    // This doesn't re-render the component!\n    countRef.current = countRef.current + 1;\n  }\n\n  return (\n    <button onClick={handleClick}>\n      You clicked {countRef.current} times\n    </button>\n  );\n}\n```\n\nExample:\n```javascript\n// Inside of Reactfunction useRef(initialValue) {  const [ref, unused] = useState({ current: initialValue });  return ref;}\n```\n\nExample:\n```javascript\nref.current = 5;console.log(ref.current); // 5\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Chat() {\n  const [text, setText] = useState('');\n  const [isSending, setIsSending] = useState(false);\n  let timeoutID = null;\n\n  function handleSend() {\n    setIsSending(true);\n    timeoutID = setTimeout(() => {\n      alert('Sent!');\n      setIsSending(false);\n    }, 3000);\n  }\n\n  function handleUndo() {\n    setIsSending(false);\n    clearTimeout(timeoutID);\n  }\n\n  return (\n    <>\n      <input\n        disabled={isSending}\n        value={text}\n        onChange={e => setText(e.target.value)}\n      />\n      <button\n        disabled={isSending}\n        onClick={handleSend}>\n        {isSending ? 'Sending...' : 'Send'}\n      </button>\n      {isSending &&\n        <button onClick={handleUndo}>\n          Undo\n        </button>\n      }\n    </>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.872Z","totalSectionsIncluded":0,"totalCodeBlocksIncluded":12,"totalLines":211,"estimatedTokens":966}}19{"id":"doc-reacting_to_input_with_state_react-b04d97d9","source":"documentation","title":"Reacting to Input with State – React","url":"https://react.dev/learn/reacting-to-input-with-state","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactManaging StateCopy pageCopyReacting to Input with StateReact provides a declarative way to manipulate the UI. Instead of manipulating individual pieces of the UI directly, you describe the different states that your component can be in, and switch between them in response to the user input. This is similar to how designers think about the UI. You will learn How declarative UI programming differs from imperative UI programming How to enumerate the different visual states your component can be in How to trigger the changes between the different visual states from code How declarative UI compares to imperative When you design UI interactions, you probably think about how the UI changes in response to user actions. Consider a form that lets the user submit an you type something into the form, the “Submit” button becomes enabled. When you press “Submit”, both the form and the button become disabled, and a spinner appears. If the network request succeeds, the form gets hidden, and the “Thank you” message appears. If the network request fails, an error message appears, and the form becomes enabled again. In imperative programming, the above corresponds directly to how you implement interaction. You have to write the exact instructions to manipulate the UI depending on what just happened. Here’s another way to think about riding next to someone in a car and telling them turn by turn where to go. Illustrated by Rachel Lee Nabors They don’t know where you want to go, they just follow your commands. (And if you get the directions wrong, you end up in the wrong place!) It’s called imperative because you have to “command” each element, from the spinner to the button, telling the computer how to update the UI. In this example of imperative UI programming, the form is built without React. It only uses the browser function handleFormSubmit(e) { e.preventDefault(); disable(textarea); disable(button); show(loadingMessage); hide(errorMessage); try { await submitForm(textarea.value); show(successMessage); hide(form); } catch (err) { show(errorMessage); errorMessage.textContent = err.message; } finally { hide(loadingMessage); enable(textarea); enable(button); } } function handleTextareaChange() { if (textarea.value.length === 0) { disable(button); } else { enable(button); } } function hide(el) { el.style.display = 'none'; } function show(el) { el.style.display = ''; } function enable(el) { el.disabled = false; } function disable(el) { el.disabled = true; } function submitForm(answer) { // Pretend it's hitting the network. return new Promise((resolve, reject) => { setTimeout(() => { if (answer.toLowerCase() === 'istanbul') { resolve(); } else { reject(new Error('Good guess but a wrong answer. Try again!')); } }, 1500); }); } let form = document.getElementById('form'); let textarea = document.getElementById('textarea'); let button = document.getElementById('button'); let loadingMessage = document.getElementById('loading'); let errorMessage = document.getElementById('error'); let successMessage = document.getElementById('success'); form.onsubmit = handleFormSubmit; textarea.oninput = handleTextareaChange; Show more Manipulating the UI imperatively works well enough for isolated examples, but it gets exponentially more difficult to manage in more complex systems. Imagine updating a page full of different forms like this one. Adding a new UI element or a new interaction would require carefully checking all existing code to make sure you haven’t introduced a bug (for example, forgetting to show or hide something). React was built to solve this problem. In React, you don’t directly manipulate the UI—meaning you don’t enable, disable, show, or hide components directly. Instead, you declare what you want to show, and React figures out how to update the UI. Think of getting into a taxi and telling the driver where you want to go instead of telling them exactly where to turn. It’s the driver’s job to get you there, and they might even know some shortcuts you haven’t considered! Illustrated by Rachel Lee Nabors Thinking about UI declaratively You’ve seen how to implement a form imperatively above. To better understand how to think in React, you’ll walk through reimplementing this UI in React your component’s different visual states Determine what triggers those state changes Represent the state in memory using useState Remove any non-essential state variables Connect the event handlers to set the state Step your component’s different visual states In computer science, you may hear about a “state machine” being in one of several “states”. If you work with a designer, you may have seen mockups for different “visual states”. React stands at the intersection of design and computer science, so both of these ideas are sources of inspiration. First, you need to visualize all the different “states” of the UI the user might : Form has a disabled “Submit” button. has an enabled “Submit” button. is completely disabled. Spinner is shown. Success: “Thank you” message is shown instead of a form. as Typing state, but with an extra error message. Just like a designer, you’ll want to “mock up” or create “mocks” for the different states before you add logic. For example, here is a mock for just the visual part of the form. This mock is controlled by a prop called status with a default value of 'empty': App.jsApp.jsReloadClearForkexport default function Form({ status = 'empty' }) { if (status === 'success') { return <h1>That's right!</h1> } return ( <> <h2>City quiz</h2> <p> In which city is there a billboard that turns air into drinkable water? </p> <form> <textarea /> <br /> <button> Submit </button> </form> </> ) } Show more You could call that prop anything you like, the naming is not important. Try editing status = 'empty' to status = 'success' to see the success message appear. Mocking lets you quickly iterate on the UI before you wire up any logic. Here is a more fleshed out prototype of the same component, still “controlled” by the status default function Form({ // Try 'submitting', 'error', 'success': status = 'empty' }) { if (status === 'success') { return <h1>That's right!</h1> } return ( <> <h2>City quiz</h2> <p> In which city is there a billboard that turns air into drinkable water? </p> <form> <textarea disabled={ status === 'submitting' } /> <br /> <button disabled={ status === 'empty' || status === 'submitting' }> Submit </button> {status === 'error' && <p className=\"Error\"> Good guess but a wrong answer. Try again! </p> } </form> </> ); } Show more Deep DiveDisplaying many visual states at once Show DetailsIf a component has a lot of visual states, it can be convenient to show them all on one Form from './Form.js'; let statuses = [ 'empty', 'typing', 'submitting', 'success', 'error', ]; export default function App() { return ( <> {statuses.map(status => ( <section key={status}> <h4>Form ({status}):</h4> <Form status={status} /> </section> ))} </> ); } Show morePages like this are often called “living styleguides” or “storybooks”. Step what triggers those state changes You can trigger state updates in response to two kinds of inputs, like clicking a button, typing in a field, navigating a link. Computer inputs, like a network response arriving, a timeout completing, an image loading. Human inputsComputer inputsIllustrated by Rachel Lee Nabors In both cases, you must set state variables to update the UI. For the form you’re developing, you will need to change state in response to a few different the text input (human) should switch it from the Empty state to the Typing state or back, depending on whether the text box is empty or not. Clicking the Submit button (human) should switch it to the Submitting state. Successful network response (computer) should switch it to the Success state. Failed network response (computer) should switch it to the Error state with the matching error message. NoteNotice that human inputs often require event handlers! To help visualize this flow, try drawing each state on paper as a labeled circle, and each change between two states as an arrow. You can sketch out many flows this way and sort out bugs long before implementation. Form states Step the state in memory with useState Next you’ll need to represent the visual states of your component in memory with useState. Simplicity is piece of state is a “moving piece”, and you want as few “moving pieces” as possible. More complexity leads to more bugs! Start with the state that absolutely must be there. For example, you’ll need to store the answer for the input, and the error (if it exists) to store the last [answer, setAnswer] = useState('');const [error, setError] = useState(null); Then, you’ll need a state variable representing which one of the visual states that you want to display. There’s usually more than a single way to represent that in memory, so you’ll need to experiment with it. If you struggle to think of the best way immediately, start by adding enough state that you’re definitely sure that all the possible visual states are [isEmpty, setIsEmpty] = useState(true);const [isTyping, setIsTyping] = useState(false);const [isSubmitting, setIsSubmitting] = useState(false);const [isSuccess, setIsSuccess] = useState(false);const [isError, setIsError] = useState(false); Your first idea likely won’t be the best, but that’s ok—refactoring state is a part of the process! Step any non-essential state variables You want to avoid duplication in the state content so you’re only tracking what is essential. Spending a little time on refactoring your state structure will make your components easier to understand, reduce duplication, and avoid unintended meanings. Your goal is to prevent the cases where the state in memory doesn’t represent any valid UI that you’d want a user to see. (For example, you never want to show an error message and disable the input at the same time, or the user won’t be able to correct the error!) Here are some questions you can ask about your state this state cause a paradox? For example, isTyping and isSubmitting can’t both be true. A paradox usually means that the state is not constrained enough. There are four possible combinations of two booleans, but only three correspond to valid states. To remove the “impossible” state, you can combine these into a status that must be one of three values: 'typing', 'submitting', or 'success'. Is the same information available in another state variable already? Another and isTyping can’t be true at the same time. By making them separate state variables, you risk them going out of sync and causing bugs. Fortunately, you can remove isEmpty and instead check answer.length === 0. Can you get the same information from the inverse of another state variable? isError is not needed because you can check error !== null instead. After this clean-up, you’re left with 3 (down from 7!) essential state [answer, setAnswer] = useState('');const [error, setError] = useState(null);const [status, setStatus] = useState('typing'); // 'typing', 'submitting', or 'success' You know they are essential, because you can’t remove any of them without breaking the functionality. Deep DiveEliminating “impossible” states with a reducer Show DetailsThese three variables are a good enough representation of this form’s state. However, there are still some intermediate states that don’t fully make sense. For example, a non-null error doesn’t make sense when status is 'success'. To model the state more precisely, you can extract it into a reducer. Reducers let you unify multiple state variables into a single object and consolidate all the related logic! Step the event handlers to set state Lastly, create event handlers that update the state. Below is the final form, with all event handlers wired { useState } from 'react'; export default function Form() { const [answer, setAnswer] = useState(''); const [error, setError] = useState(null); const [status, setStatus] = useState('typing'); if (status === 'success') { return <h1>That's right!</h1> } async function handleSubmit(e) { e.preventDefault(); setStatus('submitting'); try { await submitForm(answer); setStatus('success'); } catch (err) { setStatus('typing'); setError(err); } } function handleTextareaChange(e) { setAnswer(e.target.value); } return ( <> <h2>City quiz</h2> <p> In which city is there a billboard that turns air into drinkable water? </p> <form onSubmit={handleSubmit}> <textarea value={answer} onChange={handleTextareaChange} disabled={status === 'submitting'} /> <br /> <button disabled={ answer.length === 0 || status === 'submitting' }> Submit </button> {error !== null && <p className=\"Error\"> {error.message} </p> } </form> </> ); } function submitForm(answer) { // Pretend it's hitting the network. return new Promise((resolve, reject) => { setTimeout(() => { let shouldError = answer.toLowerCase() !== 'lima' if (shouldError) { reject(new Error('Good guess but a wrong answer. Try again!')); } else { resolve(); } }, 1500); }); } Show more Although this code is longer than the original imperative example, it is much less fragile. Expressing all interactions as state changes lets you later introduce new visual states without breaking existing ones. It also lets you change what should be displayed in each state without changing the logic of the interaction itself. Recap Declarative programming means describing the UI for each visual state rather than micromanaging the UI (imperative). When developing a all its visual states. Determine the human and computer triggers for state changes. Model the state with useState. Remove non-essential state to avoid bugs and paradoxes. Connect the event handlers to set state. Try out some challenges1. Add and remove a CSS class 2. Profile editor 3. Refactor the imperative solution without React Challenge 1 of and remove a CSS class Make it so that clicking on the picture removes the background--active CSS class from the outer <div>, but adds the picture--active class to the <img>. Clicking the background again should restore the original CSS classes.Visually, you should expect that clicking on the picture removes the purple background and highlights the picture border. Clicking outside the picture highlights the background, but removes the picture border highlight.App.jsApp.jsReloadClearForkexport default function Picture() { return ( <div className=\"background background--active\"> <img className=\"picture\" alt=\"Rainbow houses in Kampung Pelangi, Indonesia\" src=\"https://react.dev/images/docs/scientists/5qwVYb1.jpeg\" /> </div> ); } Show solutionNext ChallengePreviousManaging StateNextChoosing the State StructureCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewHow declarative UI compares to imperative Thinking about UI declaratively Step your component’s different visual states Step what triggers those state changes Step the state in memory with useState Step any non-essential state variables Step the event handlers to set state RecapChallenges\n\nExample:\n```text\nasync function handleFormSubmit(e) {\n  e.preventDefault();\n  disable(textarea);\n  disable(button);\n  show(loadingMessage);\n  hide(errorMessage);\n  try {\n    await submitForm(textarea.value);\n    show(successMessage);\n    hide(form);\n  } catch (err) {\n    show(errorMessage);\n    errorMessage.textContent = err.message;\n  } finally {\n    hide(loadingMessage);\n    enable(textarea);\n    enable(button);\n  }\n}\n\nfunction handleTextareaChange() {\n  if (textarea.value.length === 0) {\n    disable(button);\n  } else {\n    enable(button);\n  }\n}\n\nfunction hide(el) {\n  el.style.display = 'none';\n}\n\nfunction show(el) {\n  el.style.display = '';\n}\n\nfunction enable(el) {\n  el.disabled = false;\n}\n\nfunction disable(el) {\n  el.disabled = true;\n}\n\nfunction submitForm(answer) {\n  // Pretend it's hitting the network.\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      if (answer.toLowerCase() === 'istanbul') {\n        resolve();\n      } else {\n        reject(new Error('Good guess but a wrong answer. Try again!'));\n      }\n    }, 1500);\n  });\n}\n\nlet form = document.getElementById('form');\nlet textarea = document.getElementById('textarea');\nlet button = document.getElementById('button');\nlet loadingMessage = document.getElementById('loading');\nlet errorMessage = document.getElementById('error');\nlet successMessage = document.getElementById('success');\nform.onsubmit = handleFormSubmit;\ntextarea.oninput = handleTextareaChange;\n```\n\nExample:\n```text\nexport default function Form({\n  status = 'empty'\n}) {\n  if (status === 'success') {\n    return <h1>That's right!</h1>\n  }\n  return (\n    <>\n      <h2>City quiz</h2>\n      <p>\n        In which city is there a billboard that turns air into drinkable water?\n      </p>\n      <form>\n        <textarea />\n        <br />\n        <button>\n          Submit\n        </button>\n      </form>\n    </>\n  )\n}\n```\n\nExample:\n```text\nexport default function Form({\n  // Try 'submitting', 'error', 'success':\n  status = 'empty'\n}) {\n  if (status === 'success') {\n    return <h1>That's right!</h1>\n  }\n  return (\n    <>\n      <h2>City quiz</h2>\n      <p>\n        In which city is there a billboard that turns air into drinkable water?\n      </p>\n      <form>\n        <textarea disabled={\n          status === 'submitting'\n        } />\n        <br />\n        <button disabled={\n          status === 'empty' ||\n          status === 'submitting'\n        }>\n          Submit\n        </button>\n        {status === 'error' &&\n          <p className=\"Error\">\n            Good guess but a wrong answer. Try again!\n          </p>\n        }\n      </form>\n      </>\n  );\n}\n```\n\nExample:\n```text\nimport Form from './Form.js';\n\nlet statuses = [\n  'empty',\n  'typing',\n  'submitting',\n  'success',\n  'error',\n];\n\nexport default function App() {\n  return (\n    <>\n      {statuses.map(status => (\n        <section key={status}>\n          <h4>Form ({status}):</h4>\n          <Form status={status} />\n        </section>\n      ))}\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nconst [answer, setAnswer] = useState('');const [error, setError] = useState(null);\n```\n\nExample:\n```javascript\nconst [isEmpty, setIsEmpty] = useState(true);const [isTyping, setIsTyping] = useState(false);const [isSubmitting, setIsSubmitting] = useState(false);const [isSuccess, setIsSuccess] = useState(false);const [isError, setIsError] = useState(false);\n```\n\nExample:\n```javascript\nconst [answer, setAnswer] = useState('');const [error, setError] = useState(null);const [status, setStatus] = useState('typing'); // 'typing', 'submitting', or 'success'\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Form() {\n  const [answer, setAnswer] = useState('');\n  const [error, setError] = useState(null);\n  const [status, setStatus] = useState('typing');\n\n  if (status === 'success') {\n    return <h1>That's right!</h1>\n  }\n\n  async function handleSubmit(e) {\n    e.preventDefault();\n    setStatus('submitting');\n    try {\n      await submitForm(answer);\n      setStatus('success');\n    } catch (err) {\n      setStatus('typing');\n      setError(err);\n    }\n  }\n\n  function handleTextareaChange(e) {\n    setAnswer(e.target.value);\n  }\n\n  return (\n    <>\n      <h2>City quiz</h2>\n      <p>\n        In which city is there a billboard that turns air into drinkable water?\n      </p>\n      <form onSubmit={handleSubmit}>\n        <textarea\n          value={answer}\n          onChange={handleTextareaChange}\n          disabled={status === 'submitting'}\n        />\n        <br />\n        <button disabled={\n          answer.length === 0 ||\n          status === 'submitting'\n        }>\n          Submit\n        </button>\n        {error !== null &&\n          <p className=\"Error\">\n            {error.message}\n          </p>\n        }\n      </form>\n    </>\n  );\n}\n\nfunction submitForm(answer) {\n  // Pretend it's hitting the network.\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      let shouldError = answer.toLowerCase() !== 'lima'\n      if (shouldError) {\n        reject(new Error('Good guess but a wrong answer. Try again!'));\n      } else {\n        resolve();\n      }\n    }, 1500);\n  });\n}\n```\n\nExample:\n```text\nexport default function Picture() {\n  return (\n    <div className=\"background background--active\">\n      <img\n        className=\"picture\"\n        alt=\"Rainbow houses in Kampung Pelangi, Indonesia\"\n        src=\"https://react.dev/images/docs/scientists/5qwVYb1.jpeg\"\n      />\n    </div>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.874Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":9,"totalLines":264,"estimatedTokens":5508}}20{"id":"doc-updating_objects_in_state_react-6733305b","source":"documentation","title":"Updating Objects in State – React","url":"https://react.dev/learn/updating-objects-in-state","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactAdding InteractivityCopy pageCopyUpdating Objects in StateState can hold any kind of JavaScript value, including objects. But you shouldn’t change objects that you hold in the React state directly. Instead, when you want to update an object, you need to create a new one (or make a copy of an existing one), and then set the state to use that copy. You will learn How to correctly update an object in React state How to update a nested object without mutating it What immutability is, and how not to break it How to make object copying less repetitive with Immer What’s a mutation? You can store any kind of JavaScript value in state. const [x, setX] = useState(0); So far you’ve been working with numbers, strings, and booleans. These kinds of JavaScript values are “immutable”, meaning unchangeable or “read-only”. You can trigger a re-render to replace a (5); The x state changed from 0 to 5, but the number 0 itself did not change. It’s not possible to make any changes to the built-in primitive values like numbers, strings, and booleans in JavaScript. Now consider an object in [position, setPosition] = useState({ , }); Technically, it is possible to change the contents of the object itself. This is called a = 5; However, although objects in React state are technically mutable, you should treat them as if they were immutable—like numbers, booleans, and strings. Instead of mutating them, you should always replace them. Treat state as read-only In other words, you should treat any JavaScript object that you put into state as read-only. This example holds an object in state to represent the current pointer position. The red dot is supposed to move when you touch or move the cursor over the preview area. But the dot stays in the initial { useState } from 'react'; export default function MovingDot() { const [position, setPosition] = useState({ , }); return ( <div onPointerMove={e => { position.x = e.clientX; position.y = e.clientY; }} style={{ position: 'relative', width: '100vw', height: '100vh', }}> <div style={{ position: 'absolute', backgroundColor: 'red', borderRadius: '50%', transform: `translate(${position.x}px, ${position.y}px)`, , , , , }} /> </div> ); } Show more The problem is with this bit of code. onPointerMove={e => { position.x = e.clientX; position.y = e.clientY;}} This code modifies the object assigned to position from the previous render. But without using the state setting function, React has no idea that object has changed. So React does not do anything in response. It’s like trying to change the order after you’ve already eaten the meal. While mutating state can work in some cases, we don’t recommend it. You should treat the state value you have access to in a render as read-only. To actually trigger a re-render in this case, create a new object and pass it to the state setting ={e => { setPosition({ , });}} With setPosition, you’re telling position with this new object And render this component again Notice how the red dot now follows your pointer when you touch or hover over the preview { useState } from 'react'; export default function MovingDot() { const [position, setPosition] = useState({ , }); return ( <div onPointerMove={e => { setPosition({ , }); }} style={{ position: 'relative', width: '100vw', height: '100vh', }}> <div style={{ position: 'absolute', backgroundColor: 'red', borderRadius: '50%', transform: `translate(${position.x}px, ${position.y}px)`, , , , , }} /> </div> ); } Show more Deep DiveLocal mutation is fine Show DetailsCode like this is a problem because it modifies an existing object in = e.clientX;position.y = e.clientY;But code like this is absolutely fine because you’re mutating a fresh object you have just nextPosition = {};nextPosition.x = e.clientX;nextPosition.y = e.clientY;setPosition(nextPosition);In fact, it is completely equivalent to writing ({ , });Mutation is only a problem when you change existing objects that are already in state. Mutating an object you’ve just created is okay because no other code references it yet. Changing it isn’t going to accidentally impact something that depends on it. This is called a “local mutation”. You can even do local mutation while rendering. Very convenient and completely okay! Copying objects with the spread syntax In the previous example, the position object is always created fresh from the current cursor position. But often, you will want to include existing data as a part of the new object you’re creating. For example, you may want to update only one field in a form, but keep the previous values for all other fields. These input fields don’t work because the onChange handlers mutate the { useState } from 'react'; export default function Form() { const [person, setPerson] = useState({ firstName: 'Barbara', lastName: 'Hepworth', email: 'bhepworth@sculpture.com' }); function handleFirstNameChange(e) { person.firstName = e.target.value; } function handleLastNameChange(e) { person.lastName = e.target.value; } function handleEmailChange(e) { person.email = e.target.value; } return ( <> <label> First name: <input value={person.firstName} onChange={handleFirstNameChange} /> </label> <label> Last name: <input value={person.lastName} onChange={handleLastNameChange} /> </label> <label> Email: <input value={person.email} onChange={handleEmailChange} /> </label> <p> {person.firstName}{' '} {person.lastName}{' '} ({person.email}) </p> </> ); } Show more For example, this line mutates the state from a past = e.target.value; The reliable way to get the behavior you’re looking for is to create a new object and pass it to setPerson. But here, you want to also copy the existing data into it because only one of the fields has ({ , // New first name from the input , }); You can use the ... object spread syntax so that you don’t need to copy every property separately. setPerson({ ...person, // Copy the old fields // But override this one}); Now the form works! Notice how you didn’t declare a separate state variable for each input field. For large forms, keeping all data grouped in an object is very convenient—as long as you update it correctly! App.jsApp.jsReloadClearForkimport { useState } from 'react'; export default function Form() { const [person, setPerson] = useState({ firstName: 'Barbara', lastName: 'Hepworth', email: 'bhepworth@sculpture.com' }); function handleFirstNameChange(e) { setPerson({ ...person, }); } function handleLastNameChange(e) { setPerson({ ...person, }); } function handleEmailChange(e) { setPerson({ ...person, }); } return ( <> <label> First name: <input value={person.firstName} onChange={handleFirstNameChange} /> </label> <label> Last name: <input value={person.lastName} onChange={handleLastNameChange} /> </label> <label> Email: <input value={person.email} onChange={handleEmailChange} /> </label> <p> {person.firstName}{' '} {person.lastName}{' '} ({person.email}) </p> </> ); } Show more Note that the ... spread syntax is “shallow”—it only copies things one level deep. This makes it fast, but it also means that if you want to update a nested property, you’ll have to use it more than once. Deep DiveUsing a single event handler for multiple fields Show DetailsYou can also use the [ and ] braces inside your object definition to specify a property with a dynamic name. Here is the same example, but with a single event handler instead of three different { useState } from 'react'; export default function Form() { const [person, setPerson] = useState({ firstName: 'Barbara', lastName: 'Hepworth', email: 'bhepworth@sculpture.com' }); function handleChange(e) { setPerson({ ...person, [e.target.name]: e.target.value }); } return ( <> <label> First name: <input name=\"firstName\" value={person.firstName} onChange={handleChange} /> </label> <label> Last name: <input name=\"lastName\" value={person.lastName} onChange={handleChange} /> </label> <label> Email: <input name=\"email\" value={person.email} onChange={handleChange} /> </label> <p> {person.firstName}{' '} {person.lastName}{' '} ({person.email}) </p> </> ); } Show moreHere, e.target.name refers to the name property given to the <input> DOM element. Updating a nested object Consider a nested object structure like [person, setPerson] = useState({ name: 'Niki de Saint Phalle', artwork: { title: 'Blue Nana', city: 'Hamburg', image: 'https://react.dev/images/docs/scientists/Sd1AgUOm.jpg', }}); If you wanted to update person.artwork.city, it’s clear how to do it with = 'New Delhi'; But in React, you treat state as immutable! In order to change city, you would first need to produce the new artwork object (pre-populated with data from the previous one), and then produce the new person object which points at the new nextArtwork = { ...person.artwork, city: 'New Delhi' };const nextPerson = { ...person, };setPerson(nextPerson); Or, written as a single function ({ ...person, // Copy other fields artwork: { // but replace the artwork ...person.artwork, // with the same one city: 'New Delhi' // but in New Delhi! }}); This gets a bit wordy, but it works fine for many { useState } from 'react'; export default function Form() { const [person, setPerson] = useState({ name: 'Niki de Saint Phalle', artwork: { title: 'Blue Nana', city: 'Hamburg', image: 'https://react.dev/images/docs/scientists/Sd1AgUOm.jpg', } }); function handleNameChange(e) { setPerson({ ...person, }); } function handleTitleChange(e) { setPerson({ ...person, artwork: { ...person.artwork, } }); } function handleCityChange(e) { setPerson({ ...person, artwork: { ...person.artwork, } }); } function handleImageChange(e) { setPerson({ ...person, artwork: { ...person.artwork, } }); } return ( <> <label> Name: <input value={person.name} onChange={handleNameChange} /> </label> <label> Title: <input value={person.artwork.title} onChange={handleTitleChange} /> </label> <label> City: <input value={person.artwork.city} onChange={handleCityChange} /> </label> <label> Image: <input value={person.artwork.image} onChange={handleImageChange} /> </label> <p> <i>{person.artwork.title}</i> {' by '} {person.name} <br /> (located in {person.artwork.city}) </p> <img src={person.artwork.image} alt={person.artwork.title} /> </> ); } Show more Deep DiveObjects are not really nested Show DetailsAn object like this appears “nested” in obj = { name: 'Niki de Saint Phalle', artwork: { title: 'Blue Nana', city: 'Hamburg', image: 'https://react.dev/images/docs/scientists/Sd1AgUOm.jpg', }};However, “nesting” is an inaccurate way to think about how objects behave. When the code executes, there is no such thing as a “nested” object. You are really looking at two different obj1 = { title: 'Blue Nana', city: 'Hamburg', image: 'https://react.dev/images/docs/scientists/Sd1AgUOm.jpg',};let obj2 = { name: 'Niki de Saint Phalle', };The obj1 object is not “inside” obj2. For example, obj3 could “point” at obj1 obj1 = { title: 'Blue Nana', city: 'Hamburg', image: 'https://react.dev/images/docs/scientists/Sd1AgUOm.jpg',};let obj2 = { name: 'Niki de Saint Phalle', };let obj3 = { name: 'Copycat', };If you were to mutate obj3.artwork.city, it would affect both obj2.artwork.city and obj1.city. This is because obj3.artwork, obj2.artwork, and obj1 are the same object. This is difficult to see when you think of objects as “nested”. Instead, they are separate objects “pointing” at each other with properties. Write concise update logic with Immer If your state is deeply nested, you might want to consider flattening it. But, if you don’t want to change your state structure, you might prefer a shortcut to nested spreads. Immer is a popular library that lets you write using the convenient but mutating syntax and takes care of producing the copies for you. With Immer, the code you write looks like you are “breaking the rules” and mutating an (draft => { draft.artwork.city = 'Lagos';}); But unlike a regular mutation, it doesn’t overwrite the past state! Deep DiveHow does Immer work? Show DetailsThe draft provided by Immer is a special type of object, called a Proxy, that “records” what you do with it. This is why you can mutate it freely as much as you like! Under the hood, Immer figures out which parts of the draft have been changed, and produces a completely new object that contains your edits. To try npm install use-immer to add Immer as a dependency Then replace import { useState } from 'react' with import { useImmer } from 'use-immer' Here is the above example converted to { \"dependencies\": { \"immer\": \"1.7.3\", \"react\": \"latest\", \"react-dom\": \"latest\", \"react-scripts\": \"latest\", \"use-immer\": \"0.5.1\" }, \"scripts\": { \"start\": \"react-scripts start\", \"build\": \"react-scripts build\", \"test\": \"react-scripts test --env=jsdom\", \"eject\": \"react-scripts eject\" }, \"devDependencies\": {} } Notice how much more concise the event handlers have become. You can mix and match useState and useImmer in a single component as much as you like. Immer is a great way to keep the update handlers concise, especially if there’s nesting in your state, and copying objects leads to repetitive code. Deep DiveWhy is mutating state not recommended in React? Show DetailsThere are a few : If you use console.log and don’t mutate state, your past logs won’t get clobbered by the more recent state changes. So you can clearly see how state has changed between renders. React optimization strategies rely on skipping work if previous props or state are the same as the next ones. If you never mutate state, it is very fast to check whether there were any changes. If prevObj === obj, you can be sure that nothing could have changed inside of it. New new React features we’re building rely on state being treated like a snapshot. If you’re mutating past versions of state, that may prevent you from using the new features. Requirement application features, like implementing Undo/Redo, showing a history of changes, or letting the user reset a form to earlier values, are easier to do when nothing is mutated. This is because you can keep past copies of state in memory, and reuse them when appropriate. If you start with a mutative approach, features like this can be difficult to add later on. Simpler React does not rely on mutation, it does not need to do anything special with your objects. It does not need to hijack their properties, always wrap them into Proxies, or do other work at initialization as many “reactive” solutions do. This is also why React lets you put any object into state—no matter how large—without additional performance or correctness pitfalls. In practice, you can often “get away” with mutating state in React, but we strongly advise you not to do that so that you can use new React features developed with this approach in mind. Future contributors and perhaps even your future self will thank you! Recap Treat all state in React as immutable. When you store objects in state, mutating them will not trigger renders and will change the state in previous render “snapshots”. Instead of mutating an object, create a new version of it, and trigger a re-render by setting state to it. You can use the {...obj, something: 'newValue'} object spread syntax to create copies of objects. Spread syntax is only copies one level deep. To update a nested object, you need to create copies all the way up from the place you’re updating. To reduce repetitive copying code, use Immer. Try out some challenges1. Fix incorrect state updates 2. Find and fix the mutation 3. Update an object with Immer Challenge 1 of incorrect state updates This form has a few bugs. Click the button that increases the score a few times. Notice that it does not increase. Then edit the first name, and notice that the score has suddenly “caught up” with your changes. Finally, edit the last name, and notice that the score has disappeared completely.Your task is to fix all of these bugs. As you fix them, explain why each of them happens.App.jsApp.jsReloadClearForkimport { useState } from 'react'; export default function Scoreboard() { const [player, setPlayer] = useState({ firstName: 'Ranjani', lastName: 'Shettar', , }); function handlePlusClick() { player.score++; } function handleFirstNameChange(e) { setPlayer({ ...player, , }); } function handleLastNameChange(e) { setPlayer({ }); } return ( <> <label> Score: <b>{player.score}</b> {' '} <button onClick={handlePlusClick}> +1 </button> </label> <label> First name: <input value={player.firstName} onChange={handleFirstNameChange} /> </label> <label> Last name: <input value={player.lastName} onChange={handleLastNameChange} /> </label> </> ); } Show more Show solutionNext ChallengePreviousQueueing a Series of State UpdatesNextUpdating Arrays in StateCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewWhat’s a mutation? Treat state as read-only Copying objects with the spread syntax Updating a nested object Write concise update logic with Immer RecapChallenges\n\nExample:\n```javascript\nconst [x, setX] = useState(0);\n```\n\nExample:\n```javascript\nsetX(5);\n```\n\nExample:\n```javascript\nconst [position, setPosition] = useState({ x: 0, y: 0 });\n```\n\nExample:\n```javascript\nposition.x = 5;\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function MovingDot() {\n  const [position, setPosition] = useState({\n    x: 0,\n    y: 0\n  });\n  return (\n    <div\n      onPointerMove={e => {\n        position.x = e.clientX;\n        position.y = e.clientY;\n      }}\n      style={{\n        position: 'relative',\n        width: '100vw',\n        height: '100vh',\n      }}>\n      <div style={{\n        position: 'absolute',\n        backgroundColor: 'red',\n        borderRadius: '50%',\n        transform: `translate(${position.x}px, ${position.y}px)`,\n        left: -10,\n        top: -10,\n        width: 20,\n        height: 20,\n      }} />\n    </div>\n  );\n}\n```\n\nExample:\n```javascript\nonPointerMove={e => {  position.x = e.clientX;  position.y = e.clientY;}}\n```\n\nExample:\n```javascript\nonPointerMove={e => {  setPosition({    x: e.clientX,    y: e.clientY  });}}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function MovingDot() {\n  const [position, setPosition] = useState({\n    x: 0,\n    y: 0\n  });\n  return (\n    <div\n      onPointerMove={e => {\n        setPosition({\n          x: e.clientX,\n          y: e.clientY\n        });\n      }}\n      style={{\n        position: 'relative',\n        width: '100vw',\n        height: '100vh',\n      }}>\n      <div style={{\n        position: 'absolute',\n        backgroundColor: 'red',\n        borderRadius: '50%',\n        transform: `translate(${position.x}px, ${position.y}px)`,\n        left: -10,\n        top: -10,\n        width: 20,\n        height: 20,\n      }} />\n    </div>\n  );\n}\n```\n\nExample:\n```javascript\nposition.x = e.clientX;position.y = e.clientY;\n```\n\nExample:\n```javascript\nconst nextPosition = {};nextPosition.x = e.clientX;nextPosition.y = e.clientY;setPosition(nextPosition);\n```\n\nExample:\n```javascript\nsetPosition({  x: e.clientX,  y: e.clientY});\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Form() {\n  const [person, setPerson] = useState({\n    firstName: 'Barbara',\n    lastName: 'Hepworth',\n    email: 'bhepworth@sculpture.com'\n  });\n\n  function handleFirstNameChange(e) {\n    person.firstName = e.target.value;\n  }\n\n  function handleLastNameChange(e) {\n    person.lastName = e.target.value;\n  }\n\n  function handleEmailChange(e) {\n    person.email = e.target.value;\n  }\n\n  return (\n    <>\n      <label>\n        First name:\n        <input\n          value={person.firstName}\n          onChange={handleFirstNameChange}\n        />\n      </label>\n      <label>\n        Last name:\n        <input\n          value={person.lastName}\n          onChange={handleLastNameChange}\n        />\n      </label>\n      <label>\n        Email:\n        <input\n          value={person.email}\n          onChange={handleEmailChange}\n        />\n      </label>\n      <p>\n        {person.firstName}{' '}\n        {person.lastName}{' '}\n        ({person.email})\n      </p>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nperson.firstName = e.target.value;\n```\n\nExample:\n```javascript\nsetPerson({  firstName: e.target.value, // New first name from the input  lastName: person.lastName,  email: person.email});\n```\n\nExample:\n```javascript\nsetPerson({  ...person, // Copy the old fields  firstName: e.target.value // But override this one});\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Form() {\n  const [person, setPerson] = useState({\n    firstName: 'Barbara',\n    lastName: 'Hepworth',\n    email: 'bhepworth@sculpture.com'\n  });\n\n  function handleFirstNameChange(e) {\n    setPerson({\n      ...person,\n      firstName: e.target.value\n    });\n  }\n\n  function handleLastNameChange(e) {\n    setPerson({\n      ...person,\n      lastName: e.target.value\n    });\n  }\n\n  function handleEmailChange(e) {\n    setPerson({\n      ...person,\n      email: e.target.value\n    });\n  }\n\n  return (\n    <>\n      <label>\n        First name:\n        <input\n          value={person.firstName}\n          onChange={handleFirstNameChange}\n        />\n      </label>\n      <label>\n        Last name:\n        <input\n          value={person.lastName}\n          onChange={handleLastNameChange}\n        />\n      </label>\n      <label>\n        Email:\n        <input\n          value={person.email}\n          onChange={handleEmailChange}\n        />\n      </label>\n      <p>\n        {person.firstName}{' '}\n        {person.lastName}{' '}\n        ({person.email})\n      </p>\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Form() {\n  const [person, setPerson] = useState({\n    firstName: 'Barbara',\n    lastName: 'Hepworth',\n    email: 'bhepworth@sculpture.com'\n  });\n\n  function handleChange(e) {\n    setPerson({\n      ...person,\n      [e.target.name]: e.target.value\n    });\n  }\n\n  return (\n    <>\n      <label>\n        First name:\n        <input\n          name=\"firstName\"\n          value={person.firstName}\n          onChange={handleChange}\n        />\n      </label>\n      <label>\n        Last name:\n        <input\n          name=\"lastName\"\n          value={person.lastName}\n          onChange={handleChange}\n        />\n      </label>\n      <label>\n        Email:\n        <input\n          name=\"email\"\n          value={person.email}\n          onChange={handleChange}\n        />\n      </label>\n      <p>\n        {person.firstName}{' '}\n        {person.lastName}{' '}\n        ({person.email})\n      </p>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nconst [person, setPerson] = useState({  name: 'Niki de Saint Phalle',  artwork: {    title: 'Blue Nana',    city: 'Hamburg',    image: 'https://react.dev/images/docs/scientists/Sd1AgUOm.jpg',  }});\n```\n\nExample:\n```javascript\nperson.artwork.city = 'New Delhi';\n```\n\nExample:\n```javascript\nconst nextArtwork = { ...person.artwork, city: 'New Delhi' };const nextPerson = { ...person, artwork: nextArtwork };setPerson(nextPerson);\n```\n\nExample:\n```javascript\nsetPerson({  ...person, // Copy other fields  artwork: { // but replace the artwork    ...person.artwork, // with the same one    city: 'New Delhi' // but in New Delhi!  }});\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Form() {\n  const [person, setPerson] = useState({\n    name: 'Niki de Saint Phalle',\n    artwork: {\n      title: 'Blue Nana',\n      city: 'Hamburg',\n      image: 'https://react.dev/images/docs/scientists/Sd1AgUOm.jpg',\n    }\n  });\n\n  function handleNameChange(e) {\n    setPerson({\n      ...person,\n      name: e.target.value\n    });\n  }\n\n  function handleTitleChange(e) {\n    setPerson({\n      ...person,\n      artwork: {\n        ...person.artwork,\n        title: e.target.value\n      }\n    });\n  }\n\n  function handleCityChange(e) {\n    setPerson({\n      ...person,\n      artwork: {\n        ...person.artwork,\n        city: e.target.value\n      }\n    });\n  }\n\n  function handleImageChange(e) {\n    setPerson({\n      ...person,\n      artwork: {\n        ...person.artwork,\n        image: e.target.value\n      }\n    });\n  }\n\n  return (\n    <>\n      <label>\n        Name:\n        <input\n          value={person.name}\n          onChange={handleNameChange}\n        />\n      </label>\n      <label>\n        Title:\n        <input\n          value={person.artwork.title}\n          onChange={handleTitleChange}\n        />\n      </label>\n      <label>\n        City:\n        <input\n          value={person.artwork.city}\n          onChange={handleCityChange}\n        />\n      </label>\n      <label>\n        Image:\n        <input\n          value={person.artwork.image}\n          onChange={handleImageChange}\n        />\n      </label>\n      <p>\n        <i>{person.artwork.title}</i>\n        {' by '}\n        {person.name}\n        <br />\n        (located in {person.artwork.city})\n      </p>\n      <img\n        src={person.artwork.image}\n        alt={person.artwork.title}\n      />\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nlet obj = {  name: 'Niki de Saint Phalle',  artwork: {    title: 'Blue Nana',    city: 'Hamburg',    image: 'https://react.dev/images/docs/scientists/Sd1AgUOm.jpg',  }};\n```\n\nExample:\n```javascript\nlet obj1 = {  title: 'Blue Nana',  city: 'Hamburg',  image: 'https://react.dev/images/docs/scientists/Sd1AgUOm.jpg',};let obj2 = {  name: 'Niki de Saint Phalle',  artwork: obj1};\n```\n\nExample:\n```javascript\nlet obj1 = {  title: 'Blue Nana',  city: 'Hamburg',  image: 'https://react.dev/images/docs/scientists/Sd1AgUOm.jpg',};let obj2 = {  name: 'Niki de Saint Phalle',  artwork: obj1};let obj3 = {  name: 'Copycat',  artwork: obj1};\n```\n\nExample:\n```javascript\nupdatePerson(draft => {  draft.artwork.city = 'Lagos';});\n```\n\nExample:\n```text\n{\n  \"dependencies\": {\n    \"immer\": \"1.7.3\",\n    \"react\": \"latest\",\n    \"react-dom\": \"latest\",\n    \"react-scripts\": \"latest\",\n    \"use-immer\": \"0.5.1\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"test\": \"react-scripts test --env=jsdom\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"devDependencies\": {}\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Scoreboard() {\n  const [player, setPlayer] = useState({\n    firstName: 'Ranjani',\n    lastName: 'Shettar',\n    score: 10,\n  });\n\n  function handlePlusClick() {\n    player.score++;\n  }\n\n  function handleFirstNameChange(e) {\n    setPlayer({\n      ...player,\n      firstName: e.target.value,\n    });\n  }\n\n  function handleLastNameChange(e) {\n    setPlayer({\n      lastName: e.target.value\n    });\n  }\n\n  return (\n    <>\n      <label>\n        Score: <b>{player.score}</b>\n        {' '}\n        <button onClick={handlePlusClick}>\n          +1\n        </button>\n      </label>\n      <label>\n        First name:\n        <input\n          value={player.firstName}\n          onChange={handleFirstNameChange}\n        />\n      </label>\n      <label>\n        Last name:\n        <input\n          value={player.lastName}\n          onChange={handleLastNameChange}\n        />\n      </label>\n    </>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.876Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":28,"totalLines":523,"estimatedTokens":7133}}21{"id":"doc-adding_interactivity_react-14ab7e48","source":"documentation","title":"Adding Interactivity – React","url":"https://react.dev/learn/adding-interactivity","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactCopy pageCopyAdding InteractivitySome things on the screen update in response to user input. For example, clicking an image gallery switches the active image. In React, data that changes over time is called state. You can add state to any component, and update it as needed. In this chapter, you’ll learn how to write components that handle interactions, update their state, and display different output over time. In this chapter How to handle user-initiated events How to make components “remember” information with state How React updates the UI in two phases Why state doesn’t update right after you change it How to queue multiple state updates How to update an object in state How to update an array in state Responding to events React lets you add event handlers to your JSX. Event handlers are your own functions that will be triggered in response to user interactions like clicking, hovering, focusing on form inputs, and so on. Built-in components like <button> only support built-in browser events like onClick. However, you can also create your own components, and give their event handler props any application-specific names that you like. App.jsApp.jsReloadClearForkexport default function App() { return ( <Toolbar onPlayMovie={() => alert('Playing!')} onUploadImage={() => alert('Uploading!')} /> ); } function Toolbar({ onPlayMovie, onUploadImage }) { return ( <div> <Button onClick={onPlayMovie}> Play Movie </Button> <Button onClick={onUploadImage}> Upload Image </Button> </div> ); } function Button({ onClick, children }) { return ( <button onClick={onClick}> {children} </button> ); } Show more Ready to learn this topic?Read Responding to Events to learn how to add event handlers.Read More component’s memory Components often need to change what’s on the screen as a result of an interaction. Typing into the form should update the input field, clicking “next” on an image carousel should change which image is displayed, clicking “buy” puts a product in the shopping cart. Components need to “remember” current input value, the current image, the shopping cart. In React, this kind of component-specific memory is called state. You can add state to a component with a useState Hook. Hooks are special functions that let your components use React features (state is one of those features). The useState Hook lets you declare a state variable. It takes the initial state and returns a pair of current state, and a state setter function that lets you update it. const [index, setIndex] = useState(0);const [showMore, setShowMore] = useState(false); Here is how an image gallery uses and updates state on { useState } from 'react'; import { sculptureList } from './data.js'; export default function Gallery() { const [index, setIndex] = useState(0); const [showMore, setShowMore] = useState(false); const hasNext = index < sculptureList.length - 1; function handleNextClick() { if (hasNext) { setIndex(index + 1); } else { setIndex(0); } } function handleMoreClick() { setShowMore(!showMore); } let sculpture = sculptureList[index]; return ( <> <button onClick={handleNextClick}> Next </button> <h2> <i>{sculpture.name} </i> by {sculpture.artist} </h2> <h3> ({index + 1} of {sculptureList.length}) </h3> <button onClick={handleMoreClick}> {showMore ? 'Hide' : 'Show'} details </button> {showMore && <p>{sculpture.description}</p>} <img src={sculpture.url} alt={sculpture.alt} /> </> ); } Show more Ready to learn this topic?Read Component’s Memory to learn how to remember a value and update it on interaction.Read More Render and commit Before your components are displayed on the screen, they must be rendered by React. Understanding the steps in this process will help you think about how your code executes and explain its behavior. Imagine that your components are cooks in the kitchen, assembling tasty dishes from ingredients. In this scenario, React is the waiter who puts in requests from customers and brings them their orders. This process of requesting and serving UI has three a render (delivering the diner’s order to the kitchen) Rendering the component (preparing the order in the kitchen) Committing to the DOM (placing the order on the table) TriggerRenderCommitIllustrated by Rachel Lee Nabors Ready to learn this topic?Read Render and Commit to learn the lifecycle of a UI update.Read More State as a snapshot Unlike regular JavaScript variables, React state behaves more like a snapshot. Setting it does not change the state variable you already have, but instead triggers a re-render. This can be surprising at first! console.log(count); // 0setCount(count + 1); // Request a re-render with 1console.log(count); // Still 0! This behavior helps you avoid subtle bugs. Here is a little chat app. Try to guess what happens if you press “Send” first and then change the recipient to Bob. Whose name will appear in the alert five seconds later? App.jsApp.jsReloadClearForkimport { useState } from 'react'; export default function Form() { const [to, setTo] = useState('Alice'); const [message, setMessage] = useState('Hello'); function handleSubmit(e) { e.preventDefault(); setTimeout(() => { alert(`You said ${message} to ${to}`); }, 5000); } return ( <form onSubmit={handleSubmit}> <label> To:{' '} <select value={to} onChange={e => setTo(e.target.value)}> <option value=\"Alice\">Alice</option> <option value=\"Bob\">Bob</option> </select> </label> <textarea placeholder=\"Message\" value={message} onChange={e => setMessage(e.target.value)} /> <button type=\"submit\">Send</button> </form> ); } Show more Ready to learn this topic?Read State as a Snapshot to learn why state appears “fixed” and unchanging inside the event handlers.Read More Queueing a series of state updates This component is “+3” increments the score only once. App.jsApp.jsReloadClearForkimport { useState } from 'react'; export default function Counter() { const [score, setScore] = useState(0); function increment() { setScore(score + 1); } return ( <> <button onClick={() => increment()}>+1</button> <button onClick={() => { increment(); increment(); increment(); }}>+3</button> <h1>Score: {score}</h1> </> ) } Show more State as a Snapshot explains why this is happening. Setting state requests a new re-render, but does not change it in the already running code. So score continues to be 0 right after you call setScore(score + 1). console.log(score); // 0setScore(score + 1); // setScore(0 + 1);console.log(score); // 0setScore(score + 1); // setScore(0 + 1);console.log(score); // 0setScore(score + 1); // setScore(0 + 1);console.log(score); // 0 You can fix this by passing an updater function when setting state. Notice how replacing setScore(score + 1) with setScore(s => s + 1) fixes the “+3” button. This lets you queue multiple state updates. App.jsApp.jsReloadClearForkimport { useState } from 'react'; export default function Counter() { const [score, setScore] = useState(0); function increment() { setScore(s => s + 1); } return ( <> <button onClick={() => increment()}>+1</button> <button onClick={() => { increment(); increment(); increment(); }}>+3</button> <h1>Score: {score}</h1> </> ) } Show more Ready to learn this topic?Read Queueing a Series of State Updates to learn how to queue a sequence of state updates.Read More Updating objects in state State can hold any kind of JavaScript value, including objects. But you shouldn’t change objects and arrays that you hold in the React state directly. Instead, when you want to update an object and array, you need to create a new one (or make a copy of an existing one), and then update the state to use that copy. Usually, you will use the ... spread syntax to copy objects and arrays that you want to change. For example, updating a nested object could look like { useState } from 'react'; export default function Form() { const [person, setPerson] = useState({ name: 'Niki de Saint Phalle', artwork: { title: 'Blue Nana', city: 'Hamburg', image: 'https://react.dev/images/docs/scientists/Sd1AgUOm.jpg', } }); function handleNameChange(e) { setPerson({ ...person, }); } function handleTitleChange(e) { setPerson({ ...person, artwork: { ...person.artwork, } }); } function handleCityChange(e) { setPerson({ ...person, artwork: { ...person.artwork, } }); } function handleImageChange(e) { setPerson({ ...person, artwork: { ...person.artwork, } }); } return ( <> <label> Name: <input value={person.name} onChange={handleNameChange} /> </label> <label> Title: <input value={person.artwork.title} onChange={handleTitleChange} /> </label> <label> City: <input value={person.artwork.city} onChange={handleCityChange} /> </label> <label> Image: <input value={person.artwork.image} onChange={handleImageChange} /> </label> <p> <i>{person.artwork.title}</i> {' by '} {person.name} <br /> (located in {person.artwork.city}) </p> <img src={person.artwork.image} alt={person.artwork.title} /> </> ); } Show more If copying objects in code gets tedious, you can use a library like Immer to reduce repetitive { \"dependencies\": { \"immer\": \"1.7.3\", \"react\": \"latest\", \"react-dom\": \"latest\", \"react-scripts\": \"latest\", \"use-immer\": \"0.5.1\" }, \"scripts\": { \"start\": \"react-scripts start\", \"build\": \"react-scripts build\", \"test\": \"react-scripts test --env=jsdom\", \"eject\": \"react-scripts eject\" }, \"devDependencies\": {} } Ready to learn this topic?Read Updating Objects in State to learn how to update objects correctly.Read More Updating arrays in state Arrays are another type of mutable JavaScript objects you can store in state and should treat as read-only. Just like with objects, when you want to update an array stored in state, you need to create a new one (or make a copy of an existing one), and then set state to use the new { useState } from 'react'; const initialList = [ { , title: 'Big Bellies', }, { , title: 'Lunar Landscape', }, { , title: 'Terracotta Army', }, ]; export default function BucketList() { const [list, setList] = useState( initialList ); function handleToggle(artworkId, nextSeen) { setList(list.map(artwork => { if (artwork.id === artworkId) { return { ...artwork, }; } else { return artwork; } })); } return ( <> <h1>Art Bucket List</h1> <h2>My list of art to see:</h2> <ItemList artworks={list} onToggle={handleToggle} /> </> ); } function ItemList({ artworks, onToggle }) { return ( <ul> {artworks.map(artwork => ( <li key={artwork.id}> <label> <input type=\"checkbox\" checked={artwork.seen} onChange={e => { onToggle( artwork.id, e.target.checked ); }} /> {artwork.title} </label> </li> ))} </ul> ); } Show more If copying arrays in code gets tedious, you can use a library like Immer to reduce repetitive { \"dependencies\": { \"immer\": \"1.7.3\", \"react\": \"latest\", \"react-dom\": \"latest\", \"react-scripts\": \"latest\", \"use-immer\": \"0.5.1\" }, \"scripts\": { \"start\": \"react-scripts start\", \"build\": \"react-scripts build\", \"test\": \"react-scripts test --env=jsdom\", \"eject\": \"react-scripts eject\" }, \"devDependencies\": {} } Ready to learn this topic?Read Updating Arrays in State to learn how to update arrays correctly.Read More What’s next? Head over to Responding to Events to start reading this chapter page by page! Or, if you’re already familiar with these topics, why not read about Managing State?PreviousYour UI as a TreeNextResponding to EventsCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewResponding to events component’s memory Render and commit State as a snapshot Queueing a series of state updates Updating objects in state Updating arrays in state What’s next?\n\nExample:\n```text\nexport default function App() {\n  return (\n    <Toolbar\n      onPlayMovie={() => alert('Playing!')}\n      onUploadImage={() => alert('Uploading!')}\n    />\n  );\n}\n\nfunction Toolbar({ onPlayMovie, onUploadImage }) {\n  return (\n    <div>\n      <Button onClick={onPlayMovie}>\n        Play Movie\n      </Button>\n      <Button onClick={onUploadImage}>\n        Upload Image\n      </Button>\n    </div>\n  );\n}\n\nfunction Button({ onClick, children }) {\n  return (\n    <button onClick={onClick}>\n      {children}\n    </button>\n  );\n}\n```\n\nExample:\n```javascript\nconst [index, setIndex] = useState(0);const [showMore, setShowMore] = useState(false);\n```\n\nExample:\n```text\nimport { useState } from 'react';\nimport { sculptureList } from './data.js';\n\nexport default function Gallery() {\n  const [index, setIndex] = useState(0);\n  const [showMore, setShowMore] = useState(false);\n  const hasNext = index < sculptureList.length - 1;\n\n  function handleNextClick() {\n    if (hasNext) {\n      setIndex(index + 1);\n    } else {\n      setIndex(0);\n    }\n  }\n\n  function handleMoreClick() {\n    setShowMore(!showMore);\n  }\n\n  let sculpture = sculptureList[index];\n  return (\n    <>\n      <button onClick={handleNextClick}>\n        Next\n      </button>\n      <h2>\n        <i>{sculpture.name} </i>\n        by {sculpture.artist}\n      </h2>\n      <h3>\n        ({index + 1} of {sculptureList.length})\n      </h3>\n      <button onClick={handleMoreClick}>\n        {showMore ? 'Hide' : 'Show'} details\n      </button>\n      {showMore && <p>{sculpture.description}</p>}\n      <img\n        src={sculpture.url}\n        alt={sculpture.alt}\n      />\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nconsole.log(count);  // 0setCount(count + 1); // Request a re-render with 1console.log(count);  // Still 0!\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Form() {\n  const [to, setTo] = useState('Alice');\n  const [message, setMessage] = useState('Hello');\n\n  function handleSubmit(e) {\n    e.preventDefault();\n    setTimeout(() => {\n      alert(`You said ${message} to ${to}`);\n    }, 5000);\n  }\n\n  return (\n    <form onSubmit={handleSubmit}>\n      <label>\n        To:{' '}\n        <select\n          value={to}\n          onChange={e => setTo(e.target.value)}>\n          <option value=\"Alice\">Alice</option>\n          <option value=\"Bob\">Bob</option>\n        </select>\n      </label>\n      <textarea\n        placeholder=\"Message\"\n        value={message}\n        onChange={e => setMessage(e.target.value)}\n      />\n      <button type=\"submit\">Send</button>\n    </form>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Counter() {\n  const [score, setScore] = useState(0);\n\n  function increment() {\n    setScore(score + 1);\n  }\n\n  return (\n    <>\n      <button onClick={() => increment()}>+1</button>\n      <button onClick={() => {\n        increment();\n        increment();\n        increment();\n      }}>+3</button>\n      <h1>Score: {score}</h1>\n    </>\n  )\n}\n```\n\nExample:\n```javascript\nconsole.log(score);  // 0setScore(score + 1); // setScore(0 + 1);console.log(score);  // 0setScore(score + 1); // setScore(0 + 1);console.log(score);  // 0setScore(score + 1); // setScore(0 + 1);console.log(score);  // 0\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Counter() {\n  const [score, setScore] = useState(0);\n\n  function increment() {\n    setScore(s => s + 1);\n  }\n\n  return (\n    <>\n      <button onClick={() => increment()}>+1</button>\n      <button onClick={() => {\n        increment();\n        increment();\n        increment();\n      }}>+3</button>\n      <h1>Score: {score}</h1>\n    </>\n  )\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Form() {\n  const [person, setPerson] = useState({\n    name: 'Niki de Saint Phalle',\n    artwork: {\n      title: 'Blue Nana',\n      city: 'Hamburg',\n      image: 'https://react.dev/images/docs/scientists/Sd1AgUOm.jpg',\n    }\n  });\n\n  function handleNameChange(e) {\n    setPerson({\n      ...person,\n      name: e.target.value\n    });\n  }\n\n  function handleTitleChange(e) {\n    setPerson({\n      ...person,\n      artwork: {\n        ...person.artwork,\n        title: e.target.value\n      }\n    });\n  }\n\n  function handleCityChange(e) {\n    setPerson({\n      ...person,\n      artwork: {\n        ...person.artwork,\n        city: e.target.value\n      }\n    });\n  }\n\n  function handleImageChange(e) {\n    setPerson({\n      ...person,\n      artwork: {\n        ...person.artwork,\n        image: e.target.value\n      }\n    });\n  }\n\n  return (\n    <>\n      <label>\n        Name:\n        <input\n          value={person.name}\n          onChange={handleNameChange}\n        />\n      </label>\n      <label>\n        Title:\n        <input\n          value={person.artwork.title}\n          onChange={handleTitleChange}\n        />\n      </label>\n      <label>\n        City:\n        <input\n          value={person.artwork.city}\n          onChange={handleCityChange}\n        />\n      </label>\n      <label>\n        Image:\n        <input\n          value={person.artwork.image}\n          onChange={handleImageChange}\n        />\n      </label>\n      <p>\n        <i>{person.artwork.title}</i>\n        {' by '}\n        {person.name}\n        <br />\n        (located in {person.artwork.city})\n      </p>\n      <img\n        src={person.artwork.image}\n        alt={person.artwork.title}\n      />\n    </>\n  );\n}\n```\n\nExample:\n```text\n{\n  \"dependencies\": {\n    \"immer\": \"1.7.3\",\n    \"react\": \"latest\",\n    \"react-dom\": \"latest\",\n    \"react-scripts\": \"latest\",\n    \"use-immer\": \"0.5.1\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"test\": \"react-scripts test --env=jsdom\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"devDependencies\": {}\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nconst initialList = [\n  { id: 0, title: 'Big Bellies', seen: false },\n  { id: 1, title: 'Lunar Landscape', seen: false },\n  { id: 2, title: 'Terracotta Army', seen: true },\n];\n\nexport default function BucketList() {\n  const [list, setList] = useState(\n    initialList\n  );\n\n  function handleToggle(artworkId, nextSeen) {\n    setList(list.map(artwork => {\n      if (artwork.id === artworkId) {\n        return { ...artwork, seen: nextSeen };\n      } else {\n        return artwork;\n      }\n    }));\n  }\n\n  return (\n    <>\n      <h1>Art Bucket List</h1>\n      <h2>My list of art to see:</h2>\n      <ItemList\n        artworks={list}\n        onToggle={handleToggle} />\n    </>\n  );\n}\n\nfunction ItemList({ artworks, onToggle }) {\n  return (\n    <ul>\n      {artworks.map(artwork => (\n        <li key={artwork.id}>\n          <label>\n            <input\n              type=\"checkbox\"\n              checked={artwork.seen}\n              onChange={e => {\n                onToggle(\n                  artwork.id,\n                  e.target.checked\n                );\n              }}\n            />\n            {artwork.title}\n          </label>\n        </li>\n      ))}\n    </ul>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.878Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":11,"totalLines":364,"estimatedTokens":5022}}22{"id":"doc-state_a_component_s_memory_react-00938603","source":"documentation","title":"State: A Component's Memory – React","url":"https://react.dev/learn/state-a-components-memory","text":"Example:\n```text\nimport { sculptureList } from './data.js';\n\nexport default function Gallery() {\n  let index = 0;\n\n  function handleClick() {\n    index = index + 1;\n  }\n\n  let sculpture = sculptureList[index];\n  return (\n    <>\n      <button onClick={handleClick}>\n        Next\n      </button>\n      <h2>\n        <i>{sculpture.name} </i>\n        by {sculpture.artist}\n      </h2>\n      <h3>\n        ({index + 1} of {sculptureList.length})\n      </h3>\n      <img\n        src={sculpture.url}\n        alt={sculpture.alt}\n      />\n      <p>\n        {sculpture.description}\n      </p>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nimport { useState } from 'react';\n```\n\nExample:\n```javascript\nlet index = 0;\n```\n\nExample:\n```javascript\nconst [index, setIndex] = useState(0);\n```\n\nExample:\n```javascript\nfunction handleClick() {  setIndex(index + 1);}\n```\n\nExample:\n```text\nimport { useState } from 'react';\nimport { sculptureList } from './data.js';\n\nexport default function Gallery() {\n  const [index, setIndex] = useState(0);\n\n  function handleClick() {\n    setIndex(index + 1);\n  }\n\n  let sculpture = sculptureList[index];\n  return (\n    <>\n      <button onClick={handleClick}>\n        Next\n      </button>\n      <h2>\n        <i>{sculpture.name} </i>\n        by {sculpture.artist}\n      </h2>\n      <h3>\n        ({index + 1} of {sculptureList.length})\n      </h3>\n      <img\n        src={sculpture.url}\n        alt={sculpture.alt}\n      />\n      <p>\n        {sculpture.description}\n      </p>\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\nimport { sculptureList } from './data.js';\n\nexport default function Gallery() {\n  const [index, setIndex] = useState(0);\n  const [showMore, setShowMore] = useState(false);\n\n  function handleNextClick() {\n    setIndex(index + 1);\n  }\n\n  function handleMoreClick() {\n    setShowMore(!showMore);\n  }\n\n  let sculpture = sculptureList[index];\n  return (\n    <>\n      <button onClick={handleNextClick}>\n        Next\n      </button>\n      <h2>\n        <i>{sculpture.name} </i>\n        by {sculpture.artist}\n      </h2>\n      <h3>\n        ({index + 1} of {sculptureList.length})\n      </h3>\n      <button onClick={handleMoreClick}>\n        {showMore ? 'Hide' : 'Show'} details\n      </button>\n      {showMore && <p>{sculpture.description}</p>}\n      <img\n        src={sculpture.url}\n        alt={sculpture.alt}\n      />\n    </>\n  );\n}\n```\n\nExample:\n```text\nlet componentHooks = [];\nlet currentHookIndex = 0;\n\n// How useState works inside React (simplified).\nfunction useState(initialState) {\n  let pair = componentHooks[currentHookIndex];\n  if (pair) {\n    // This is not the first render,\n    // so the state pair already exists.\n    // Return it and prepare for next Hook call.\n    currentHookIndex++;\n    return pair;\n  }\n\n  // This is the first time we're rendering,\n  // so create a state pair and store it.\n  pair = [initialState, setState];\n\n  function setState(nextState) {\n    // When the user requests a state change,\n    // put the new value into the pair.\n    pair[0] = nextState;\n    updateDOM();\n  }\n\n  // Store the pair for future renders\n  // and prepare for the next Hook call.\n  componentHooks[currentHookIndex] = pair;\n  currentHookIndex++;\n  return pair;\n}\n\nfunction Gallery() {\n  // Each useState() call will get the next pair.\n  const [index, setIndex] = useState(0);\n  const [showMore, setShowMore] = useState(false);\n\n  function handleNextClick() {\n    setIndex(index + 1);\n  }\n\n  function handleMoreClick() {\n    setShowMore(!showMore);\n  }\n\n  let sculpture = sculptureList[index];\n  // This example doesn't use React, so\n  // return an output object instead of JSX.\n  return {\n    onNextClick: handleNextClick,\n    onMoreClick: handleMoreClick,\n    header: `${sculpture.name} by ${sculpture.artist}`,\n    counter: `${index + 1} of ${sculptureList.length}`,\n    more: `${showMore ? 'Hide' : 'Show'} details`,\n    description: showMore ? sculpture.description : null,\n    imageSrc: sculpture.url,\n    imageAlt: sculpture.alt\n  };\n}\n\nfunction updateDOM() {\n  // Reset the current Hook index\n  // before rendering the component.\n  currentHookIndex = 0;\n  let output = Gallery();\n\n  // Update the DOM to match the output.\n  // This is the part React does for you.\n  nextButton.onclick = output.onNextClick;\n  header.textContent = output.header;\n  moreButton.onclick = output.onMoreClick;\n  moreButton.textContent = output.more;\n  image.src = output.imageSrc;\n  image.alt = output.imageAlt;\n  if (output.description !== null) {\n    description.textContent = output.description;\n    description.style.display = '';\n  } else {\n    description.style.display = 'none';\n  }\n}\n\nlet nextButton = document.getElementById('nextButton');\nlet header = document.getElementById('header');\nlet moreButton = document.getElementById('moreButton');\nlet description = document.getElementById('description');\nlet image = document.getElementById('image');\nlet sculptureList = [{\n  name: 'Homenaje a la Neurocirugía',\n  artist: 'Marta Colvin Andrade',\n  description: 'Although Colvin is predominantly known for abstract themes that allude to pre-Hispanic symbols, this gigantic sculpture, an homage to neurosurgery, is one of her most recognizable public art pieces.',\n  url: 'https://react.dev/images/docs/scientists/Mx7dA2Y.jpg',\n  alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.'\n}, {\n  name: 'Floralis Genérica',\n  artist: 'Eduardo Catalano',\n  description: 'This enormous (75 ft. or 23m) silver flower is located in Buenos Aires. It is designed to move, closing its petals in the evening or when strong winds blow and opening them in the morning.',\n  url: 'https://react.dev/images/docs/scientists/ZF6s192m.jpg',\n  alt: 'A gigantic metallic flower sculpture with reflective mirror-like petals and strong stamens.'\n}, {\n  name: 'Eternal Presence',\n  artist: 'John Woodrow Wilson',\n  description: 'Wilson was known for his preoccupation with equality, social justice, as well as the essential and spiritual qualities of humankind. This massive (7ft. or 2,13m) bronze represents what he described as \"a symbolic Black presence infused with a sense of universal humanity.\"',\n  url: 'https://react.dev/images/docs/scientists/aTtVpES.jpg',\n  alt: 'The sculpture depicting a human head seems ever-present and solemn. It radiates calm and serenity.'\n}, {\n  name: 'Moai',\n  artist: 'Unknown Artist',\n  description: 'Located on the Easter Island, there are 1,000 moai, or extant monumental statues, created by the early Rapa Nui people, which some believe represented deified ancestors.',\n  url: 'https://react.dev/images/docs/scientists/RCwLEoQm.jpg',\n  alt: 'Three monumental stone busts with the heads that are disproportionately large with somber faces.'\n}, {\n  name: 'Blue Nana',\n  artist: 'Niki de Saint Phalle',\n  description: 'The Nanas are triumphant creatures, symbols of femininity and maternity. Initially, Saint Phalle used fabric and found objects for the Nanas, and later on introduced polyester to achieve a more vibrant effect.',\n  url: 'https://react.dev/images/docs/scientists/Sd1AgUOm.jpg',\n  alt: 'A large mosaic sculpture of a whimsical dancing female figure in a colorful costume emanating joy.'\n}, {\n  name: 'Ultimate Form',\n  artist: 'Barbara Hepworth',\n  description: 'This abstract bronze sculpture is a part of The Family of Man series located at Yorkshire Sculpture Park. Hepworth chose not to create literal representations of the world but developed abstract forms inspired by people and landscapes.',\n  url: 'https://react.dev/images/docs/scientists/2heNQDcm.jpg',\n  alt: 'A tall sculpture made of three elements stacked on each other reminding of a human figure.'\n}, {\n  name: 'Cavaliere',\n  artist: 'Lamidi Olonade Fakeye',\n  description: \"Descended from four generations of woodcarvers, Fakeye's work blended traditional and contemporary Yoruba themes.\",\n  url: 'https://react.dev/images/docs/scientists/wIdGuZwm.png',\n  alt: 'An intricate wood sculpture of a warrior with a focused face on a horse adorned with patterns.'\n}, {\n  name: 'Big Bellies',\n  artist: 'Alina Szapocznikow',\n  description: \"Szapocznikow is known for her sculptures of the fragmented body as a metaphor for the fragility and impermanence of youth and beauty. This sculpture depicts two very realistic large bellies stacked on top of each other, each around five feet (1,5m) tall.\",\n  url: 'https://react.dev/images/docs/scientists/AlHTAdDm.jpg',\n  alt: 'The sculpture reminds a cascade of folds, quite different from bellies in classical sculptures.'\n}, {\n  name: 'Terracotta Army',\n  artist: 'Unknown Artist',\n  description: 'The Terracotta Army is a collection of terracotta sculptures depicting the armies of Qin Shi Huang, the first Emperor of China. The army consisted of more than 8,000 soldiers, 130 chariots with 520 horses, and 150 cavalry horses.',\n  url: 'https://react.dev/images/docs/scientists/HMFmH6m.jpg',\n  alt: '12 terracotta sculptures of solemn warriors, each with a unique facial expression and armor.'\n}, {\n  name: 'Lunar Landscape',\n  artist: 'Louise Nevelson',\n  description: 'Nevelson was known for scavenging objects from New York City debris, which she would later assemble into monumental constructions. In this one, she used disparate parts like a bedpost, juggling pin, and seat fragment, nailing and gluing them into boxes that reflect the influence of Cubism’s geometric abstraction of space and form.',\n  url: 'https://react.dev/images/docs/scientists/rN7hY6om.jpg',\n  alt: 'A black matte sculpture where the individual elements are initially indistinguishable.'\n}, {\n  name: 'Aureole',\n  artist: 'Ranjani Shettar',\n  description: 'Shettar merges the traditional and the modern, the natural and the industrial. Her art focuses on the relationship between man and nature. Her work was described as compelling both abstractly and figuratively, gravity defying, and a \"fine synthesis of unlikely materials.\"',\n  url: 'https://react.dev/images/docs/scientists/okTpbHhm.jpg',\n  alt: 'A pale wire-like sculpture mounted on concrete wall and descending on the floor. It appears light.'\n}, {\n  name: 'Hippos',\n  artist: 'Taipei Zoo',\n  description: 'The Taipei Zoo commissioned a Hippo Square featuring submerged hippos at play.',\n  url: 'https://react.dev/images/docs/scientists/6o5Vuyu.jpg',\n  alt: 'A group of bronze hippo sculptures emerging from the sett sidewalk as if they were swimming.'\n}];\n\n// Make UI match the initial state.\nupdateDOM();\n```\n\nExample:\n```text\nimport Gallery from './Gallery.js';\n\nexport default function Page() {\n  return (\n    <div className=\"Page\">\n      <Gallery />\n      <Gallery />\n    </div>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.880Z","totalSectionsIncluded":0,"totalCodeBlocksIncluded":9,"totalLines":318,"estimatedTokens":2670}}23{"id":"doc-scaling_up_with_reducer_and_context_react-0e8f1bba","source":"documentation","title":"Scaling Up with Reducer and Context – React","url":"https://react.dev/learn/scaling-up-with-reducer-and-context","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactManaging StateCopy pageCopyScaling Up with Reducer and ContextReducers let you consolidate a component’s state update logic. Context lets you pass information deep down to other components. You can combine reducers and context together to manage state of a complex screen. You will learn How to combine a reducer with context How to avoid passing state and dispatch through props How to keep context and state logic in a separate file Combining a reducer with context In this example from the introduction to reducers, the state is managed by a reducer. The reducer function contains all of the state update logic and is declared at the bottom of this { useReducer } from 'react'; import AddTask from './AddTask.js'; import TaskList from './TaskList.js'; export default function TaskApp() { const [tasks, dispatch] = useReducer( tasksReducer, initialTasks ); function handleAddTask(text) { dispatch({ type: 'added', ++, , }); } function handleChangeTask(task) { dispatch({ type: 'changed', }); } function handleDeleteTask(taskId) { dispatch({ type: 'deleted', }); } return ( <> <h1>Day off in Kyoto</h1> <AddTask onAddTask={handleAddTask} /> <TaskList tasks={tasks} onChangeTask={handleChangeTask} onDeleteTask={handleDeleteTask} /> </> ); } function tasksReducer(tasks, action) { switch (action.type) { case 'added': { return [...tasks, { , , }]; } case 'changed': { return tasks.map(t => { if (t.id === action.task.id) { return action.task; } else { return t; } }); } case 'deleted': { return tasks.filter(t => t.id !== action.id); } default: { throw Error('Unknown action: ' + action.type); } } } let nextId = 3; const initialTasks = [ { , text: 'Philosopher’s Path', }, { , text: 'Visit the temple', }, { , text: 'Drink matcha', } ]; Show more A reducer helps keep the event handlers short and concise. However, as your app grows, you might run into another difficulty. Currently, the tasks state and the dispatch function are only available in the top-level TaskApp component. To let other components read the list of tasks or change it, you have to explicitly pass down the current state and the event handlers that change it as props. For example, TaskApp passes a list of tasks and the event handlers to TaskList: <TaskList tasks={tasks} onChangeTask={handleChangeTask} onDeleteTask={handleDeleteTask}/> And TaskList passes the event handlers to Task: <Task task={task} onChange={onChangeTask} onDelete={onDeleteTask}/> In a small example like this, this works well, but if you have tens or hundreds of components in the middle, passing down all state and functions can be quite frustrating! This is why, as an alternative to passing them through props, you might want to put both the tasks state and the dispatch function into context. This way, any component below TaskApp in the tree can read the tasks and dispatch actions without the repetitive “prop drilling”. Here is how you can combine a reducer with the context. Put state and dispatch into context. Use context anywhere in the tree. Step the context The useReducer Hook returns the current tasks and the dispatch function that lets you update [tasks, dispatch] = useReducer(tasksReducer, initialTasks); To pass them down the tree, you will create two separate provides the current list of tasks. TasksDispatchContext provides the function that lets components dispatch actions. Export them from a separate file so that you can later import them from other { createContext } from 'react'; export const TasksContext = createContext(null); export const TasksDispatchContext = createContext(null); Here, you’re passing null as the default value to both contexts. The actual values will be provided by the TaskApp component. Step state and dispatch into context Now you can import both contexts in your TaskApp component. Take the tasks and dispatch returned by useReducer() and provide them to the entire tree { TasksContext, TasksDispatchContext } from './TasksContext.js';export default function TaskApp() { const [tasks, dispatch] = useReducer(tasksReducer, initialTasks); // ... return ( <TasksContext value={tasks}> <TasksDispatchContext value={dispatch}> ... </TasksDispatchContext> </TasksContext> );} For now, you pass the information both via props and in { useReducer } from 'react'; import AddTask from './AddTask.js'; import TaskList from './TaskList.js'; import { TasksContext, TasksDispatchContext } from './TasksContext.js'; export default function TaskApp() { const [tasks, dispatch] = useReducer( tasksReducer, initialTasks ); function handleAddTask(text) { dispatch({ type: 'added', ++, , }); } function handleChangeTask(task) { dispatch({ type: 'changed', }); } function handleDeleteTask(taskId) { dispatch({ type: 'deleted', }); } return ( <TasksContext value={tasks}> <TasksDispatchContext value={dispatch}> <h1>Day off in Kyoto</h1> <AddTask onAddTask={handleAddTask} /> <TaskList tasks={tasks} onChangeTask={handleChangeTask} onDeleteTask={handleDeleteTask} /> </TasksDispatchContext> </TasksContext> ); } function tasksReducer(tasks, action) { switch (action.type) { case 'added': { return [...tasks, { , , }]; } case 'changed': { return tasks.map(t => { if (t.id === action.task.id) { return action.task; } else { return t; } }); } case 'deleted': { return tasks.filter(t => t.id !== action.id); } default: { throw Error('Unknown action: ' + action.type); } } } let nextId = 3; const initialTasks = [ { , text: 'Philosopher’s Path', }, { , text: 'Visit the temple', }, { , text: 'Drink matcha', } ]; Show more In the next step, you will remove prop passing. Step context anywhere in the tree Now you don’t need to pass the list of tasks or the event handlers down the tree: <TasksContext value={tasks}> <TasksDispatchContext value={dispatch}> <h1>Day off in Kyoto</h1> <AddTask /> <TaskList /> </TasksDispatchContext></TasksContext> Instead, any component that needs the task list can read it from the default function TaskList() { const tasks = useContext(TasksContext); // ... To update the task list, any component can read the dispatch function from context and call default function AddTask() { const [text, setText] = useState(''); const dispatch = useContext(TasksDispatchContext); // ... return ( // ... <button onClick={() => { setText(''); dispatch({ type: 'added', ++, , }); }}>Add</button> // ... The TaskApp component does not pass any event handlers down, and the TaskList does not pass any event handlers to the Task component either. Each component reads the context that it { useState, useContext } from 'react'; import { TasksContext, TasksDispatchContext } from './TasksContext.js'; export default function TaskList() { const tasks = useContext(TasksContext); return ( <ul> {tasks.map(task => ( <li key={task.id}> <Task task={task} /> </li> ))} </ul> ); } function Task({ task }) { const [isEditing, setIsEditing] = useState(false); const dispatch = useContext(TasksDispatchContext); let taskContent; if (isEditing) { taskContent = ( <> <input value={task.text} onChange={e => { dispatch({ type: 'changed', task: { ...task, } }); }} /> <button onClick={() => setIsEditing(false)}> Save </button> </> ); } else { taskContent = ( <> {task.text} <button onClick={() => setIsEditing(true)}> Edit </button> </> ); } return ( <label> <input type=\"checkbox\" checked={task.done} onChange={e => { dispatch({ type: 'changed', task: { ...task, } }); }} /> {taskContent} <button onClick={() => { dispatch({ type: 'deleted', }); }}> Delete </button> </label> ); } Show more The state still “lives” in the top-level TaskApp component, managed with useReducer. But its tasks and dispatch are now available to every component below in the tree by importing and using these contexts. Moving all wiring into a single file You don’t have to do this, but you could further declutter the components by moving both reducer and context into a single file. Currently, TasksContext.js contains only two context { createContext } from 'react';export const TasksContext = createContext(null);export const TasksDispatchContext = createContext(null); This file is about to get crowded! You’ll move the reducer into that same file. Then you’ll declare a new TasksProvider component in the same file. This component will tie all the pieces will manage the state with a reducer. It will provide both contexts to components below. It will take children as a prop so you can pass JSX to it. export function TasksProvider({ children }) { const [tasks, dispatch] = useReducer(tasksReducer, initialTasks); return ( <TasksContext value={tasks}> <TasksDispatchContext value={dispatch}> {children} </TasksDispatchContext> </TasksContext> );} This removes all the complexity and wiring from your TaskApp AddTask from './AddTask.js'; import TaskList from './TaskList.js'; import { TasksProvider } from './TasksContext.js'; export default function TaskApp() { return ( <TasksProvider> <h1>Day off in Kyoto</h1> <AddTask /> <TaskList /> </TasksProvider> ); } You can also export functions that use the context from TasksContext.js: export function useTasks() { return useContext(TasksContext);}export function useTasksDispatch() { return useContext(TasksDispatchContext);} When a component needs to read context, it can do it through these tasks = useTasks();const dispatch = useTasksDispatch(); This doesn’t change the behavior in any way, but it lets you later split these contexts further or add some logic to these functions. Now all of the context and reducer wiring is in TasksContext.js. This keeps the components clean and uncluttered, focused on what they display rather than where they get the { useState } from 'react'; import { useTasks, useTasksDispatch } from './TasksContext.js'; export default function TaskList() { const tasks = useTasks(); return ( <ul> {tasks.map(task => ( <li key={task.id}> <Task task={task} /> </li> ))} </ul> ); } function Task({ task }) { const [isEditing, setIsEditing] = useState(false); const dispatch = useTasksDispatch(); let taskContent; if (isEditing) { taskContent = ( <> <input value={task.text} onChange={e => { dispatch({ type: 'changed', task: { ...task, } }); }} /> <button onClick={() => setIsEditing(false)}> Save </button> </> ); } else { taskContent = ( <> {task.text} <button onClick={() => setIsEditing(true)}> Edit </button> </> ); } return ( <label> <input type=\"checkbox\" checked={task.done} onChange={e => { dispatch({ type: 'changed', task: { ...task, } }); }} /> {taskContent} <button onClick={() => { dispatch({ type: 'deleted', }); }}> Delete </button> </label> ); } Show more You can think of TasksProvider as a part of the screen that knows how to deal with tasks, useTasks as a way to read them, and useTasksDispatch as a way to update them from any component below in the tree. NoteFunctions like useTasks and useTasksDispatch are called Custom Hooks. Your function is considered a custom Hook if its name starts with use. This lets you use other Hooks, like useContext, inside it. As your app grows, you may have many context-reducer pairs like this. This is a powerful way to scale your app and lift state up without too much work whenever you want to access the data deep in the tree. Recap You can combine reducer with context to let any component read and update state above it. To provide state and the dispatch function to components two contexts (for state and for dispatch functions). Provide both contexts from the component that uses the reducer. Use either context from components that need to read them. You can further declutter the components by moving all wiring into one file. You can export a component like TasksProvider that provides context. You can also export custom Hooks like useTasks and useTasksDispatch to read it. You can have many context-reducer pairs like this in your app. PreviousPassing Data Deeply with ContextNextEscape HatchesCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewCombining a reducer with context Step the context Step state and dispatch into context Step context anywhere in the tree Moving all wiring into a single file Recap\n\nExample:\n```text\nimport { useReducer } from 'react';\nimport AddTask from './AddTask.js';\nimport TaskList from './TaskList.js';\n\nexport default function TaskApp() {\n  const [tasks, dispatch] = useReducer(\n    tasksReducer,\n    initialTasks\n  );\n\n  function handleAddTask(text) {\n    dispatch({\n      type: 'added',\n      id: nextId++,\n      text: text,\n    });\n  }\n\n  function handleChangeTask(task) {\n    dispatch({\n      type: 'changed',\n      task: task\n    });\n  }\n\n  function handleDeleteTask(taskId) {\n    dispatch({\n      type: 'deleted',\n      id: taskId\n    });\n  }\n\n  return (\n    <>\n      <h1>Day off in Kyoto</h1>\n      <AddTask\n        onAddTask={handleAddTask}\n      />\n      <TaskList\n        tasks={tasks}\n        onChangeTask={handleChangeTask}\n        onDeleteTask={handleDeleteTask}\n      />\n    </>\n  );\n}\n\nfunction tasksReducer(tasks, action) {\n  switch (action.type) {\n    case 'added': {\n      return [...tasks, {\n        id: action.id,\n        text: action.text,\n        done: false\n      }];\n    }\n    case 'changed': {\n      return tasks.map(t => {\n        if (t.id === action.task.id) {\n          return action.task;\n        } else {\n          return t;\n        }\n      });\n    }\n    case 'deleted': {\n      return tasks.filter(t => t.id !== action.id);\n    }\n    default: {\n      throw Error('Unknown action: ' + action.type);\n    }\n  }\n}\n\nlet nextId = 3;\nconst initialTasks = [\n  { id: 0, text: 'Philosopher’s Path', done: true },\n  { id: 1, text: 'Visit the temple', done: false },\n  { id: 2, text: 'Drink matcha', done: false }\n];\n```\n\nExample:\n```javascript\n<TaskList  tasks={tasks}  onChangeTask={handleChangeTask}  onDeleteTask={handleDeleteTask}/>\n```\n\nExample:\n```javascript\n<Task  task={task}  onChange={onChangeTask}  onDelete={onDeleteTask}/>\n```\n\nExample:\n```javascript\nconst [tasks, dispatch] = useReducer(tasksReducer, initialTasks);\n```\n\nExample:\n```text\nimport { createContext } from 'react';\n\nexport const TasksContext = createContext(null);\nexport const TasksDispatchContext = createContext(null);\n```\n\nExample:\n```javascript\nimport { TasksContext, TasksDispatchContext } from './TasksContext.js';export default function TaskApp() {  const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);  // ...  return (    <TasksContext value={tasks}>      <TasksDispatchContext value={dispatch}>        ...      </TasksDispatchContext>    </TasksContext>  );}\n```\n\nExample:\n```text\nimport { useReducer } from 'react';\nimport AddTask from './AddTask.js';\nimport TaskList from './TaskList.js';\nimport { TasksContext, TasksDispatchContext } from './TasksContext.js';\n\nexport default function TaskApp() {\n  const [tasks, dispatch] = useReducer(\n    tasksReducer,\n    initialTasks\n  );\n\n  function handleAddTask(text) {\n    dispatch({\n      type: 'added',\n      id: nextId++,\n      text: text,\n    });\n  }\n\n  function handleChangeTask(task) {\n    dispatch({\n      type: 'changed',\n      task: task\n    });\n  }\n\n  function handleDeleteTask(taskId) {\n    dispatch({\n      type: 'deleted',\n      id: taskId\n    });\n  }\n\n  return (\n    <TasksContext value={tasks}>\n      <TasksDispatchContext value={dispatch}>\n        <h1>Day off in Kyoto</h1>\n        <AddTask\n          onAddTask={handleAddTask}\n        />\n        <TaskList\n          tasks={tasks}\n          onChangeTask={handleChangeTask}\n          onDeleteTask={handleDeleteTask}\n        />\n      </TasksDispatchContext>\n    </TasksContext>\n  );\n}\n\nfunction tasksReducer(tasks, action) {\n  switch (action.type) {\n    case 'added': {\n      return [...tasks, {\n        id: action.id,\n        text: action.text,\n        done: false\n      }];\n    }\n    case 'changed': {\n      return tasks.map(t => {\n        if (t.id === action.task.id) {\n          return action.task;\n        } else {\n          return t;\n        }\n      });\n    }\n    case 'deleted': {\n      return tasks.filter(t => t.id !== action.id);\n    }\n    default: {\n      throw Error('Unknown action: ' + action.type);\n    }\n  }\n}\n\nlet nextId = 3;\nconst initialTasks = [\n  { id: 0, text: 'Philosopher’s Path', done: true },\n  { id: 1, text: 'Visit the temple', done: false },\n  { id: 2, text: 'Drink matcha', done: false }\n];\n```\n\nExample:\n```javascript\n<TasksContext value={tasks}>  <TasksDispatchContext value={dispatch}>    <h1>Day off in Kyoto</h1>    <AddTask />    <TaskList />  </TasksDispatchContext></TasksContext>\n```\n\nExample:\n```javascript\nexport default function TaskList() {  const tasks = useContext(TasksContext);  // ...\n```\n\nExample:\n```javascript\nexport default function AddTask() {  const [text, setText] = useState('');  const dispatch = useContext(TasksDispatchContext);  // ...  return (    // ...    <button onClick={() => {      setText('');      dispatch({        type: 'added',        id: nextId++,        text: text,      });    }}>Add</button>    // ...\n```\n\nExample:\n```text\nimport { useState, useContext } from 'react';\nimport { TasksContext, TasksDispatchContext } from './TasksContext.js';\n\nexport default function TaskList() {\n  const tasks = useContext(TasksContext);\n  return (\n    <ul>\n      {tasks.map(task => (\n        <li key={task.id}>\n          <Task task={task} />\n        </li>\n      ))}\n    </ul>\n  );\n}\n\nfunction Task({ task }) {\n  const [isEditing, setIsEditing] = useState(false);\n  const dispatch = useContext(TasksDispatchContext);\n  let taskContent;\n  if (isEditing) {\n    taskContent = (\n      <>\n        <input\n          value={task.text}\n          onChange={e => {\n            dispatch({\n              type: 'changed',\n              task: {\n                ...task,\n                text: e.target.value\n              }\n            });\n          }} />\n        <button onClick={() => setIsEditing(false)}>\n          Save\n        </button>\n      </>\n    );\n  } else {\n    taskContent = (\n      <>\n        {task.text}\n        <button onClick={() => setIsEditing(true)}>\n          Edit\n        </button>\n      </>\n    );\n  }\n  return (\n    <label>\n      <input\n        type=\"checkbox\"\n        checked={task.done}\n        onChange={e => {\n          dispatch({\n            type: 'changed',\n            task: {\n              ...task,\n              done: e.target.checked\n            }\n          });\n        }}\n      />\n      {taskContent}\n      <button onClick={() => {\n        dispatch({\n          type: 'deleted',\n          id: task.id\n        });\n      }}>\n        Delete\n      </button>\n    </label>\n  );\n}\n```\n\nExample:\n```javascript\nimport { createContext } from 'react';export const TasksContext = createContext(null);export const TasksDispatchContext = createContext(null);\n```\n\nExample:\n```javascript\nexport function TasksProvider({ children }) {  const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);  return (    <TasksContext value={tasks}>      <TasksDispatchContext value={dispatch}>        {children}      </TasksDispatchContext>    </TasksContext>  );}\n```\n\nExample:\n```text\nimport AddTask from './AddTask.js';\nimport TaskList from './TaskList.js';\nimport { TasksProvider } from './TasksContext.js';\n\nexport default function TaskApp() {\n  return (\n    <TasksProvider>\n      <h1>Day off in Kyoto</h1>\n      <AddTask />\n      <TaskList />\n    </TasksProvider>\n  );\n}\n```\n\nExample:\n```javascript\nexport function useTasks() {  return useContext(TasksContext);}export function useTasksDispatch() {  return useContext(TasksDispatchContext);}\n```\n\nExample:\n```javascript\nconst tasks = useTasks();const dispatch = useTasksDispatch();\n```\n\nExample:\n```text\nimport { useState } from 'react';\nimport { useTasks, useTasksDispatch } from './TasksContext.js';\n\nexport default function TaskList() {\n  const tasks = useTasks();\n  return (\n    <ul>\n      {tasks.map(task => (\n        <li key={task.id}>\n          <Task task={task} />\n        </li>\n      ))}\n    </ul>\n  );\n}\n\nfunction Task({ task }) {\n  const [isEditing, setIsEditing] = useState(false);\n  const dispatch = useTasksDispatch();\n  let taskContent;\n  if (isEditing) {\n    taskContent = (\n      <>\n        <input\n          value={task.text}\n          onChange={e => {\n            dispatch({\n              type: 'changed',\n              task: {\n                ...task,\n                text: e.target.value\n              }\n            });\n          }} />\n        <button onClick={() => setIsEditing(false)}>\n          Save\n        </button>\n      </>\n    );\n  } else {\n    taskContent = (\n      <>\n        {task.text}\n        <button onClick={() => setIsEditing(true)}>\n          Edit\n        </button>\n      </>\n    );\n  }\n  return (\n    <label>\n      <input\n        type=\"checkbox\"\n        checked={task.done}\n        onChange={e => {\n          dispatch({\n            type: 'changed',\n            task: {\n              ...task,\n              done: e.target.checked\n            }\n          });\n        }}\n      />\n      {taskContent}\n      <button onClick={() => {\n        dispatch({\n          type: 'deleted',\n          id: task.id\n        });\n      }}>\n        Delete\n      </button>\n    </label>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.881Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":17,"totalLines":414,"estimatedTokens":5642}}24{"id":"doc-passing_data_deeply_with_context_react-63212042","source":"documentation","title":"Passing Data Deeply with Context – React","url":"https://react.dev/learn/passing-data-deeply-with-context","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactManaging StateCopy pageCopyPassing Data Deeply with ContextUsually, you will pass information from a parent component to a child component via props. But passing props can become verbose and inconvenient if you have to pass them through many components in the middle, or if many components in your app need the same information. Context lets the parent component make some information available to any component in the tree below it—no matter how deep—without passing it explicitly through props. You will learn What “prop drilling” is How to replace repetitive prop passing with context Common use cases for context Common alternatives to context The problem with passing props Passing props is a great way to explicitly pipe data through your UI tree to the components that use it. But passing props can become verbose and inconvenient when you need to pass some prop deeply through the tree, or if many components need the same prop. The nearest common ancestor could be far removed from the components that need data, and lifting state up that high can lead to a situation called “prop drilling”. Lifting state upProp drilling Wouldn’t it be great if there were a way to “teleport” data to the components in the tree that need it without passing props? With React’s context feature, there is! alternative to passing props Context lets a parent component provide data to the entire tree below it. There are many uses for context. Here is one example. Consider this Heading component that accepts a level for its Heading from './Heading.js'; import Section from './Section.js'; export default function Page() { return ( <Section> <Heading level={1}>Title</Heading> <Heading level={2}>Heading</Heading> <Heading level={3}>Sub-heading</Heading> <Heading level={4}>Sub-sub-heading</Heading> <Heading level={5}>Sub-sub-sub-heading</Heading> <Heading level={6}>Sub-sub-sub-sub-heading</Heading> </Section> ); } Let’s say you want multiple headings within the same Section to always have the same Heading from './Heading.js'; import Section from './Section.js'; export default function Page() { return ( <Section> <Heading level={1}>Title</Heading> <Section> <Heading level={2}>Heading</Heading> <Heading level={2}>Heading</Heading> <Heading level={2}>Heading</Heading> <Section> <Heading level={3}>Sub-heading</Heading> <Heading level={3}>Sub-heading</Heading> <Heading level={3}>Sub-heading</Heading> <Section> <Heading level={4}>Sub-sub-heading</Heading> <Heading level={4}>Sub-sub-heading</Heading> <Heading level={4}>Sub-sub-heading</Heading> </Section> </Section> </Section> </Section> ); } Show more Currently, you pass the level prop to each <Heading> separately: <Section> <Heading level={3}>About</Heading> <Heading level={3}>Photos</Heading> <Heading level={3}>Videos</Heading></Section> It would be nice if you could pass the level prop to the <Section> component instead and remove it from the <Heading>. This way you could enforce that all headings in the same section have the same size: <Section level={3}> <Heading>About</Heading> <Heading>Photos</Heading> <Heading>Videos</Heading></Section> But how can the <Heading> component know the level of its closest <Section>? That would require some way for a child to “ask” for data from somewhere above in the tree. You can’t do it with props alone. This is where context comes into play. You will do it in three a context. (You can call it LevelContext, since it’s for the heading level.) Use that context from the component that needs the data. (Heading will use LevelContext.) Provide that context from the component that specifies the data. (Section will provide LevelContext.) Context lets a parent—even a distant one!—provide some data to the entire tree inside of it. Using context in close childrenUsing context in distant children Step the context First, you need to create the context. You’ll need to export it from a file so that your components can use { createContext } from 'react'; export const LevelContext = createContext(1); The only argument to createContext is the default value. Here, 1 refers to the biggest heading level, but you could pass any kind of value (even an object). You will see the significance of the default value in the next step. Step the context Import the useContext Hook from React and your { useContext } from 'react';import { LevelContext } from './LevelContext.js'; Currently, the Heading component reads level from default function Heading({ level, children }) { // ...} Instead, remove the level prop and read the value from the context you just imported, default function Heading({ children }) { const level = useContext(LevelContext); // ...} useContext is a Hook. Just like useState and useReducer, you can only call a Hook immediately inside a React component (not inside loops or conditions). useContext tells React that the Heading component wants to read the LevelContext. Now that the Heading component doesn’t have a level prop, you don’t need to pass the level prop to Heading in your JSX like this anymore: <Section> <Heading level={4}>Sub-sub-heading</Heading> <Heading level={4}>Sub-sub-heading</Heading> <Heading level={4}>Sub-sub-heading</Heading></Section> Update the JSX so that it’s the Section that receives it instead: <Section level={4}> <Heading>Sub-sub-heading</Heading> <Heading>Sub-sub-heading</Heading> <Heading>Sub-sub-heading</Heading></Section> As a reminder, this is the markup that you were trying to get Heading from './Heading.js'; import Section from './Section.js'; export default function Page() { return ( <Section level={1}> <Heading>Title</Heading> <Section level={2}> <Heading>Heading</Heading> <Heading>Heading</Heading> <Heading>Heading</Heading> <Section level={3}> <Heading>Sub-heading</Heading> <Heading>Sub-heading</Heading> <Heading>Sub-heading</Heading> <Section level={4}> <Heading>Sub-sub-heading</Heading> <Heading>Sub-sub-heading</Heading> <Heading>Sub-sub-heading</Heading> </Section> </Section> </Section> </Section> ); } Show more Notice this example doesn’t quite work, yet! All the headings have the same size because even though you’re using the context, you have not provided it yet. React doesn’t know where to get it! If you don’t provide the context, React will use the default value you’ve specified in the previous step. In this example, you specified 1 as the argument to createContext, so useContext(LevelContext) returns 1, setting all those headings to <h1>. Let’s fix this problem by having each Section provide its own context. Step the context The Section component currently renders its default function Section({ children }) { return ( <section className=\"section\"> {children} </section> );} Wrap them with a context provider to provide the LevelContext to { LevelContext } from './LevelContext.js';export default function Section({ level, children }) { return ( <section className=\"section\"> <LevelContext value={level}> {children} </LevelContext> </section> );} This tells React: “if any component inside this <Section> asks for LevelContext, give them this level.” The component will use the value of the nearest <LevelContext> in the UI tree above it. App.jsSection.jsHeading.jsLevelContext.jsApp.jsReloadClearForkimport Heading from './Heading.js'; import Section from './Section.js'; export default function Page() { return ( <Section level={1}> <Heading>Title</Heading> <Section level={2}> <Heading>Heading</Heading> <Heading>Heading</Heading> <Heading>Heading</Heading> <Section level={3}> <Heading>Sub-heading</Heading> <Heading>Sub-heading</Heading> <Heading>Sub-heading</Heading> <Section level={4}> <Heading>Sub-sub-heading</Heading> <Heading>Sub-sub-heading</Heading> <Heading>Sub-sub-heading</Heading> </Section> </Section> </Section> </Section> ); } Show more It’s the same result as the original code, but you did not need to pass the level prop to each Heading component! Instead, it “figures out” its heading level by asking the closest Section pass a level prop to the <Section>. Section wraps its children into <LevelContext value={level}>. Heading asks the closest value of LevelContext above with useContext(LevelContext). Using and providing context from the same component Currently, you still have to specify each section’s level default function Page() { return ( <Section level={1}> ... <Section level={2}> ... <Section level={3}> ... Since context lets you read information from a component above, each Section could read the level from the Section above, and pass level + 1 down automatically. Here is how you could do { useContext } from 'react';import { LevelContext } from './LevelContext.js';export default function Section({ children }) { const level = useContext(LevelContext); return ( <section className=\"section\"> <LevelContext value={level + 1}> {children} </LevelContext> </section> );} With this change, you don’t need to pass the level prop either to the <Section> or to the <Heading>: App.jsSection.jsHeading.jsLevelContext.jsApp.jsReloadClearForkimport Heading from './Heading.js'; import Section from './Section.js'; export default function Page() { return ( <Section> <Heading>Title</Heading> <Section> <Heading>Heading</Heading> <Heading>Heading</Heading> <Heading>Heading</Heading> <Section> <Heading>Sub-heading</Heading> <Heading>Sub-heading</Heading> <Heading>Sub-heading</Heading> <Section> <Heading>Sub-sub-heading</Heading> <Heading>Sub-sub-heading</Heading> <Heading>Sub-sub-heading</Heading> </Section> </Section> </Section> </Section> ); } Show more Now both Heading and Section read the LevelContext to figure out how “deep” they are. And the Section wraps its children into the LevelContext to specify that anything inside of it is at a “deeper” level. NoteThis example uses heading levels because they show visually how nested components can override context. But context is useful for many other use cases too. You can pass down any information needed by the entire current color theme, the currently logged in user, and so on. Context passes through intermediate components You can insert as many components as you like between the component that provides context and the one that uses it. This includes both built-in components like <div> and components you might build yourself. In this example, the same Post component (with a dashed border) is rendered at two different nesting levels. Notice that the <Heading> inside of it gets its level automatically from the closest <Section>: App.jsSection.jsHeading.jsLevelContext.jsApp.jsReloadClearForkimport Heading from './Heading.js'; import Section from './Section.js'; export default function ProfilePage() { return ( <Section> <Heading>My Profile</Heading> <Post title=\"Hello traveller!\" body=\"Read about my adventures.\" /> <AllPosts /> </Section> ); } function AllPosts() { return ( <Section> <Heading>Posts</Heading> <RecentPosts /> </Section> ); } function RecentPosts() { return ( <Section> <Heading>Recent Posts</Heading> <Post title=\"Flavors of Lisbon\" body=\"...those pastéis de nata!\" /> <Post title=\"Buenos Aires in the rhythm of tango\" body=\"I loved it!\" /> </Section> ); } function Post({ title, body }) { return ( <Section isFancy={true}> <Heading> {title} </Heading> <p><i>{body}</i></p> </Section> ); } Show more You didn’t do anything special for this to work. A Section specifies the context for the tree inside it, so you can insert a <Heading> anywhere, and it will have the correct size. Try it in the sandbox above! Context lets you write components that “adapt to their surroundings” and display themselves differently depending on where (or, in other words, in which context) they are being rendered. How context works might remind you of CSS property inheritance. In CSS, you can specify for a <div>, and any DOM node inside of it, no matter how deep, will inherit that color unless some other DOM node in the middle overrides it with Similarly, in React, the only way to override some context coming from above is to wrap children into a context provider with a different value. In CSS, different properties like color and background-color don’t override each other. You can set all <div>’s color to red without impacting background-color. Similarly, different React contexts don’t override each other. Each context that you make with createContext() is completely separate from other ones, and ties together components using and providing that particular context. One component may use or provide many different contexts without a problem. Before you use context Context is very tempting to use! However, this also means it’s too easy to overuse it. Just because you need to pass some props several levels deep doesn’t mean you should put that information into context. Here’s a few alternatives you should consider before using by passing props. If your components are not trivial, it’s not unusual to pass a dozen props down through a dozen components. It may feel like a slog, but it makes it very clear which components use which data! The person maintaining your code will be glad you’ve made the data flow explicit with props. Extract components and pass JSX as children to them. If you pass some data through many layers of intermediate components that don’t use that data (and only pass it further down), this often means that you forgot to extract some components along the way. For example, maybe you pass data props like posts to visual components that don’t use them directly, like <Layout posts={posts} />. Instead, make Layout take children as a prop, and render <Layout><Posts posts={posts} /></Layout>. This reduces the number of layers between the component specifying the data and the one that needs it. If neither of these approaches works well for you, consider context. Use cases for context your app lets the user change its appearance (e.g. dark mode), you can put a context provider at the top of your app, and use that context in components that need to adjust their visual look. Current components might need to know the currently logged in user. Putting it in context makes it convenient to read it anywhere in the tree. Some apps also let you operate multiple accounts at the same time (e.g. to leave a comment as a different user). In those cases, it can be convenient to wrap a part of the UI into a nested provider with a different current account value. routing solutions use context internally to hold the current route. This is how every link “knows” whether it’s active or not. If you build your own router, you might want to do it too. Managing your app grows, you might end up with a lot of state closer to the top of your app. Many distant components below may want to change it. It is common to use a reducer together with context to manage complex state and pass it down to distant components without too much hassle. Context is not limited to static values. If you pass a different value on the next render, React will update all the components reading it below! This is why context is often used in combination with state. In general, if some information is needed by distant components in different parts of the tree, it’s a good indication that context will help you. Recap Context lets a component provide some information to the entire tree below it. To pass and export it with export const MyContext = createContext(defaultValue). Pass it to the useContext(MyContext) Hook to read it in any child component, no matter how deep. Wrap children into <MyContext value={...}> to provide it from a parent. Context passes through any components in the middle. Context lets you write components that “adapt to their surroundings”. Before you use context, try passing props or passing JSX as children. Try out some challengesChallenge 1 of prop drilling with context In this example, toggling the checkbox changes the imageSize prop passed to each <PlaceImage>. The checkbox state is held in the top-level App component, but each <PlaceImage> needs to be aware of it.Currently, App passes imageSize to List, which passes it to each Place, which passes it to the PlaceImage. Remove the imageSize prop, and instead pass it from the App component directly to PlaceImage.You can declare context in Context.js.App.jsContext.jsdata.jsutils.jsApp.jsReloadClearForkimport { useState } from 'react'; import { places } from './data.js'; import { getImageUrl } from './utils.js'; export default function App() { const [isLarge, setIsLarge] = useState(false); const imageSize = isLarge ? return ( <> <label> <input type=\"checkbox\" checked={isLarge} onChange={e => { setIsLarge(e.target.checked); }} /> Use large images </label> <hr /> <List imageSize={imageSize} /> </> ) } function List({ imageSize }) { const listItems = places.map(place => <li key={place.id}> <Place place={place} imageSize={imageSize} /> </li> ); return <ul>{listItems}</ul>; } function Place({ place, imageSize }) { return ( <> <PlaceImage place={place} imageSize={imageSize} /> <p> <b>{place.name}</b> {': ' + place.description} </p> </> ); } function PlaceImage({ place, imageSize }) { return ( <img src={getImageUrl(place)} alt={place.name} width={imageSize} height={imageSize} /> ); } Show more Show solutionPreviousExtracting State Logic into a ReducerNextScaling Up with Reducer and ContextCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewThe problem with passing props alternative to passing props Step the context Step the context Step the context Using and providing context from the same component Context passes through intermediate components Before you use context Use cases for context RecapChallenges\n\nExample:\n```text\nimport Heading from './Heading.js';\nimport Section from './Section.js';\n\nexport default function Page() {\n  return (\n    <Section>\n      <Heading level={1}>Title</Heading>\n      <Heading level={2}>Heading</Heading>\n      <Heading level={3}>Sub-heading</Heading>\n      <Heading level={4}>Sub-sub-heading</Heading>\n      <Heading level={5}>Sub-sub-sub-heading</Heading>\n      <Heading level={6}>Sub-sub-sub-sub-heading</Heading>\n    </Section>\n  );\n}\n```\n\nExample:\n```text\nimport Heading from './Heading.js';\nimport Section from './Section.js';\n\nexport default function Page() {\n  return (\n    <Section>\n      <Heading level={1}>Title</Heading>\n      <Section>\n        <Heading level={2}>Heading</Heading>\n        <Heading level={2}>Heading</Heading>\n        <Heading level={2}>Heading</Heading>\n        <Section>\n          <Heading level={3}>Sub-heading</Heading>\n          <Heading level={3}>Sub-heading</Heading>\n          <Heading level={3}>Sub-heading</Heading>\n          <Section>\n            <Heading level={4}>Sub-sub-heading</Heading>\n            <Heading level={4}>Sub-sub-heading</Heading>\n            <Heading level={4}>Sub-sub-heading</Heading>\n          </Section>\n        </Section>\n      </Section>\n    </Section>\n  );\n}\n```\n\nExample:\n```javascript\n<Section>  <Heading level={3}>About</Heading>  <Heading level={3}>Photos</Heading>  <Heading level={3}>Videos</Heading></Section>\n```\n\nExample:\n```javascript\n<Section level={3}>  <Heading>About</Heading>  <Heading>Photos</Heading>  <Heading>Videos</Heading></Section>\n```\n\nExample:\n```text\nimport { createContext } from 'react';\n\nexport const LevelContext = createContext(1);\n```\n\nExample:\n```javascript\nimport { useContext } from 'react';import { LevelContext } from './LevelContext.js';\n```\n\nExample:\n```javascript\nexport default function Heading({ level, children }) {  // ...}\n```\n\nExample:\n```javascript\nexport default function Heading({ children }) {  const level = useContext(LevelContext);  // ...}\n```\n\nExample:\n```javascript\n<Section>  <Heading level={4}>Sub-sub-heading</Heading>  <Heading level={4}>Sub-sub-heading</Heading>  <Heading level={4}>Sub-sub-heading</Heading></Section>\n```\n\nExample:\n```javascript\n<Section level={4}>  <Heading>Sub-sub-heading</Heading>  <Heading>Sub-sub-heading</Heading>  <Heading>Sub-sub-heading</Heading></Section>\n```\n\nExample:\n```text\nimport Heading from './Heading.js';\nimport Section from './Section.js';\n\nexport default function Page() {\n  return (\n    <Section level={1}>\n      <Heading>Title</Heading>\n      <Section level={2}>\n        <Heading>Heading</Heading>\n        <Heading>Heading</Heading>\n        <Heading>Heading</Heading>\n        <Section level={3}>\n          <Heading>Sub-heading</Heading>\n          <Heading>Sub-heading</Heading>\n          <Heading>Sub-heading</Heading>\n          <Section level={4}>\n            <Heading>Sub-sub-heading</Heading>\n            <Heading>Sub-sub-heading</Heading>\n            <Heading>Sub-sub-heading</Heading>\n          </Section>\n        </Section>\n      </Section>\n    </Section>\n  );\n}\n```\n\nExample:\n```javascript\nexport default function Section({ children }) {  return (    <section className=\"section\">      {children}    </section>  );}\n```\n\nExample:\n```javascript\nimport { LevelContext } from './LevelContext.js';export default function Section({ level, children }) {  return (    <section className=\"section\">      <LevelContext value={level}>        {children}      </LevelContext>    </section>  );}\n```\n\nExample:\n```javascript\nexport default function Page() {  return (    <Section level={1}>      ...      <Section level={2}>        ...        <Section level={3}>          ...\n```\n\nExample:\n```javascript\nimport { useContext } from 'react';import { LevelContext } from './LevelContext.js';export default function Section({ children }) {  const level = useContext(LevelContext);  return (    <section className=\"section\">      <LevelContext value={level + 1}>        {children}      </LevelContext>    </section>  );}\n```\n\nExample:\n```text\nimport Heading from './Heading.js';\nimport Section from './Section.js';\n\nexport default function Page() {\n  return (\n    <Section>\n      <Heading>Title</Heading>\n      <Section>\n        <Heading>Heading</Heading>\n        <Heading>Heading</Heading>\n        <Heading>Heading</Heading>\n        <Section>\n          <Heading>Sub-heading</Heading>\n          <Heading>Sub-heading</Heading>\n          <Heading>Sub-heading</Heading>\n          <Section>\n            <Heading>Sub-sub-heading</Heading>\n            <Heading>Sub-sub-heading</Heading>\n            <Heading>Sub-sub-heading</Heading>\n          </Section>\n        </Section>\n      </Section>\n    </Section>\n  );\n}\n```\n\nExample:\n```text\nimport Heading from './Heading.js';\nimport Section from './Section.js';\n\nexport default function ProfilePage() {\n  return (\n    <Section>\n      <Heading>My Profile</Heading>\n      <Post\n        title=\"Hello traveller!\"\n        body=\"Read about my adventures.\"\n      />\n      <AllPosts />\n    </Section>\n  );\n}\n\nfunction AllPosts() {\n  return (\n    <Section>\n      <Heading>Posts</Heading>\n      <RecentPosts />\n    </Section>\n  );\n}\n\nfunction RecentPosts() {\n  return (\n    <Section>\n      <Heading>Recent Posts</Heading>\n      <Post\n        title=\"Flavors of Lisbon\"\n        body=\"...those pastéis de nata!\"\n      />\n      <Post\n        title=\"Buenos Aires in the rhythm of tango\"\n        body=\"I loved it!\"\n      />\n    </Section>\n  );\n}\n\nfunction Post({ title, body }) {\n  return (\n    <Section isFancy={true}>\n      <Heading>\n        {title}\n      </Heading>\n      <p><i>{body}</i></p>\n    </Section>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\nimport { places } from './data.js';\nimport { getImageUrl } from './utils.js';\n\nexport default function App() {\n  const [isLarge, setIsLarge] = useState(false);\n  const imageSize = isLarge ? 150 : 100;\n  return (\n    <>\n      <label>\n        <input\n          type=\"checkbox\"\n          checked={isLarge}\n          onChange={e => {\n            setIsLarge(e.target.checked);\n          }}\n        />\n        Use large images\n      </label>\n      <hr />\n      <List imageSize={imageSize} />\n    </>\n  )\n}\n\nfunction List({ imageSize }) {\n  const listItems = places.map(place =>\n    <li key={place.id}>\n      <Place\n        place={place}\n        imageSize={imageSize}\n      />\n    </li>\n  );\n  return <ul>{listItems}</ul>;\n}\n\nfunction Place({ place, imageSize }) {\n  return (\n    <>\n      <PlaceImage\n        place={place}\n        imageSize={imageSize}\n      />\n      <p>\n        <b>{place.name}</b>\n        {': ' + place.description}\n      </p>\n    </>\n  );\n}\n\nfunction PlaceImage({ place, imageSize }) {\n  return (\n    <img\n      src={getImageUrl(place)}\n      alt={place.name}\n      width={imageSize}\n      height={imageSize}\n    />\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.884Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":18,"totalLines":292,"estimatedTokens":6482}}25{"id":"doc-managing_state_react-ac4ba8c1","source":"documentation","title":"Managing State – React","url":"https://react.dev/learn/managing-state","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactCopy pageCopyManaging StateIntermediateAs your application grows, it helps to be more intentional about how your state is organized and how the data flows between your components. Redundant or duplicate state is a common source of bugs. In this chapter, you’ll learn how to structure your state well, how to keep your state update logic maintainable, and how to share state between distant components. In this chapter How to think about UI changes as state changes How to structure state well How to “lift state up” to share it between components How to control whether the state gets preserved or reset How to consolidate complex state logic in a function How to pass information without “prop drilling” How to scale state management as your app grows Reacting to input with state With React, you won’t modify the UI from code directly. For example, you won’t write commands like “disable the button”, “enable the button”, “show the success message”, etc. Instead, you will describe the UI you want to see for the different visual states of your component (“initial state”, “typing state”, “success state”), and then trigger the state changes in response to user input. This is similar to how designers think about UI. Here is a quiz form built using React. Note how it uses the status state variable to determine whether to enable or disable the submit button, and whether to show the success message instead. App.jsApp.jsReloadClearForkimport { useState } from 'react'; export default function Form() { const [answer, setAnswer] = useState(''); const [error, setError] = useState(null); const [status, setStatus] = useState('typing'); if (status === 'success') { return <h1>That's right!</h1> } async function handleSubmit(e) { e.preventDefault(); setStatus('submitting'); try { await submitForm(answer); setStatus('success'); } catch (err) { setStatus('typing'); setError(err); } } function handleTextareaChange(e) { setAnswer(e.target.value); } return ( <> <h2>City quiz</h2> <p> In which city is there a billboard that turns air into drinkable water? </p> <form onSubmit={handleSubmit}> <textarea value={answer} onChange={handleTextareaChange} disabled={status === 'submitting'} /> <br /> <button disabled={ answer.length === 0 || status === 'submitting' }> Submit </button> {error !== null && <p className=\"Error\"> {error.message} </p> } </form> </> ); } function submitForm(answer) { // Pretend it's hitting the network. return new Promise((resolve, reject) => { setTimeout(() => { let shouldError = answer.toLowerCase() !== 'lima' if (shouldError) { reject(new Error('Good guess but a wrong answer. Try again!')); } else { resolve(); } }, 1500); }); } Show more Ready to learn this topic?Read Reacting to Input with State to learn how to approach interactions with a state-driven mindset.Read More Choosing the state structure Structuring state well can make a difference between a component that is pleasant to modify and debug, and one that is a constant source of bugs. The most important principle is that state shouldn’t contain redundant or duplicated information. If there’s unnecessary state, it’s easy to forget to update it, and introduce bugs! For example, this form has a redundant fullName state { useState } from 'react'; export default function Form() { const [firstName, setFirstName] = useState(''); const [lastName, setLastName] = useState(''); const [fullName, setFullName] = useState(''); function handleFirstNameChange(e) { setFirstName(e.target.value); setFullName(e.target.value + ' ' + lastName); } function handleLastNameChange(e) { setLastName(e.target.value); setFullName(firstName + ' ' + e.target.value); } return ( <> <h2>Let’s check you in</h2> <label> First name:{' '} <input value={firstName} onChange={handleFirstNameChange} /> </label> <label> Last name:{' '} <input value={lastName} onChange={handleLastNameChange} /> </label> <p> Your ticket will be issued to: <b>{fullName}</b> </p> </> ); } Show more You can remove it and simplify the code by calculating fullName while the component is { useState } from 'react'; export default function Form() { const [firstName, setFirstName] = useState(''); const [lastName, setLastName] = useState(''); const fullName = firstName + ' ' + lastName; function handleFirstNameChange(e) { setFirstName(e.target.value); } function handleLastNameChange(e) { setLastName(e.target.value); } return ( <> <h2>Let’s check you in</h2> <label> First name:{' '} <input value={firstName} onChange={handleFirstNameChange} /> </label> <label> Last name:{' '} <input value={lastName} onChange={handleLastNameChange} /> </label> <p> Your ticket will be issued to: <b>{fullName}</b> </p> </> ); } Show more This might seem like a small change, but many bugs in React apps are fixed this way. Ready to learn this topic?Read Choosing the State Structure to learn how to design the state shape to avoid bugs.Read More Sharing state between components Sometimes, you want the state of two components to always change together. To do it, remove state from both of them, move it to their closest common parent, and then pass it down to them via props. This is known as “lifting state up”, and it’s one of the most common things you will do writing React code. In this example, only one panel should be active at a time. To achieve this, instead of keeping the active state inside each individual panel, the parent component holds the state and specifies the props for its children. App.jsApp.jsReloadClearForkimport { useState } from 'react'; export default function Accordion() { const [activeIndex, setActiveIndex] = useState(0); return ( <> <h2>Almaty, Kazakhstan</h2> <Panel title=\"About\" isActive={activeIndex === 0} onShow={() => setActiveIndex(0)} > With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city. </Panel> <Panel title=\"Etymology\" isActive={activeIndex === 1} onShow={() => setActiveIndex(1)} > The name comes from <span lang=\"kk-KZ\">алма</span>, the Kazakh word for \"apple\" and is often translated as \"full of apples\". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang=\"la\">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple. </Panel> </> ); } function Panel({ title, children, isActive, onShow }) { return ( <section className=\"panel\"> <h3>{title}</h3> {isActive ? ( <p>{children}</p> ) : ( <button onClick={onShow}> Show </button> )} </section> ); } Show more Ready to learn this topic?Read Sharing State Between Components to learn how to lift state up and keep components in sync.Read More Preserving and resetting state When you re-render a component, React needs to decide which parts of the tree to keep (and update), and which parts to discard or re-create from scratch. In most cases, React’s automatic behavior works well enough. By default, React preserves the parts of the tree that “match up” with the previously rendered component tree. However, sometimes this is not what you want. In this chat app, typing a message and then switching the recipient does not reset the input. This can make the user accidentally send a message to the wrong { useState } from 'react'; import Chat from './Chat.js'; import ContactList from './ContactList.js'; export default function Messenger() { const [to, setTo] = useState(contacts[0]); return ( <div> <ContactList contacts={contacts} selectedContact={to} onSelect={contact => setTo(contact)} /> <Chat contact={to} /> </div> ) } const contacts = [ { name: 'Taylor', email: 'taylor@mail.com' }, { name: 'Alice', email: 'alice@mail.com' }, { name: 'Bob', email: 'bob@mail.com' } ]; Show more React lets you override the default behavior, and force a component to reset its state by passing it a different key, like <Chat key={email} />. This tells React that if the recipient is different, it should be considered a different Chat component that needs to be re-created from scratch with the new data (and UI like inputs). Now switching between the recipients resets the input field—even though you render the same component. App.jsContactList.jsChat.jsApp.jsReloadClearForkimport { useState } from 'react'; import Chat from './Chat.js'; import ContactList from './ContactList.js'; export default function Messenger() { const [to, setTo] = useState(contacts[0]); return ( <div> <ContactList contacts={contacts} selectedContact={to} onSelect={contact => setTo(contact)} /> <Chat key={to.email} contact={to} /> </div> ) } const contacts = [ { name: 'Taylor', email: 'taylor@mail.com' }, { name: 'Alice', email: 'alice@mail.com' }, { name: 'Bob', email: 'bob@mail.com' } ]; Show more Ready to learn this topic?Read Preserving and Resetting State to learn the lifetime of state and how to control it.Read More Extracting state logic into a reducer Components with many state updates spread across many event handlers can get overwhelming. For these cases, you can consolidate all the state update logic outside your component in a single function, called “reducer”. Your event handlers become concise because they only specify the user “actions”. At the bottom of the file, the reducer function specifies how the state should update in response to each action! App.jsApp.jsReloadClearForkimport { useReducer } from 'react'; import AddTask from './AddTask.js'; import TaskList from './TaskList.js'; export default function TaskApp() { const [tasks, dispatch] = useReducer( tasksReducer, initialTasks ); function handleAddTask(text) { dispatch({ type: 'added', ++, , }); } function handleChangeTask(task) { dispatch({ type: 'changed', }); } function handleDeleteTask(taskId) { dispatch({ type: 'deleted', }); } return ( <> <h1>Prague itinerary</h1> <AddTask onAddTask={handleAddTask} /> <TaskList tasks={tasks} onChangeTask={handleChangeTask} onDeleteTask={handleDeleteTask} /> </> ); } function tasksReducer(tasks, action) { switch (action.type) { case 'added': { return [...tasks, { , , }]; } case 'changed': { return tasks.map(t => { if (t.id === action.task.id) { return action.task; } else { return t; } }); } case 'deleted': { return tasks.filter(t => t.id !== action.id); } default: { throw Error('Unknown action: ' + action.type); } } } let nextId = 3; const initialTasks = [ { , text: 'Visit Kafka Museum', }, { , text: 'Watch a puppet show', }, { , text: 'Lennon Wall pic', } ]; Show more Ready to learn this topic?Read Extracting State Logic into a Reducer to learn how to consolidate logic in the reducer function.Read More Passing data deeply with context Usually, you will pass information from a parent component to a child component via props. But passing props can become inconvenient if you need to pass some prop through many components, or if many components need the same information. Context lets the parent component make some information available to any component in the tree below it—no matter how deep it is—without passing it explicitly through props. Here, the Heading component determines its heading level by “asking” the closest Section for its level. Each Section tracks its own level by asking the parent Section and adding one to it. Every Section provides information to all components below it without passing props—it does that through context. App.jsSection.jsHeading.jsLevelContext.jsApp.jsReloadClearForkimport Heading from './Heading.js'; import Section from './Section.js'; export default function Page() { return ( <Section> <Heading>Title</Heading> <Section> <Heading>Heading</Heading> <Heading>Heading</Heading> <Heading>Heading</Heading> <Section> <Heading>Sub-heading</Heading> <Heading>Sub-heading</Heading> <Heading>Sub-heading</Heading> <Section> <Heading>Sub-sub-heading</Heading> <Heading>Sub-sub-heading</Heading> <Heading>Sub-sub-heading</Heading> </Section> </Section> </Section> </Section> ); } Show more Ready to learn this topic?Read Passing Data Deeply with Context to learn about using context as an alternative to passing props.Read More Scaling up with reducer and context Reducers let you consolidate a component’s state update logic. Context lets you pass information deep down to other components. You can combine reducers and context together to manage state of a complex screen. With this approach, a parent component with complex state manages it with a reducer. Other components anywhere deep in the tree can read its state via context. They can also dispatch actions to update that state. App.jsTasksContext.jsAddTask.jsTaskList.jsApp.jsReloadClearForkimport AddTask from './AddTask.js'; import TaskList from './TaskList.js'; import { TasksProvider } from './TasksContext.js'; export default function TaskApp() { return ( <TasksProvider> <h1>Day off in Kyoto</h1> <AddTask /> <TaskList /> </TasksProvider> ); } Ready to learn this topic?Read Scaling Up with Reducer and Context to learn how state management scales in a growing app.Read More What’s next? Head over to Reacting to Input with State to start reading this chapter page by page! Or, if you’re already familiar with these topics, why not read about Escape Hatches?PreviousUpdating Arrays in StateNextReacting to Input with StateCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewReacting to input with state Choosing the state structure Sharing state between components Preserving and resetting state Extracting state logic into a reducer Passing data deeply with context Scaling up with reducer and context What’s next?\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Form() {\n  const [answer, setAnswer] = useState('');\n  const [error, setError] = useState(null);\n  const [status, setStatus] = useState('typing');\n\n  if (status === 'success') {\n    return <h1>That's right!</h1>\n  }\n\n  async function handleSubmit(e) {\n    e.preventDefault();\n    setStatus('submitting');\n    try {\n      await submitForm(answer);\n      setStatus('success');\n    } catch (err) {\n      setStatus('typing');\n      setError(err);\n    }\n  }\n\n  function handleTextareaChange(e) {\n    setAnswer(e.target.value);\n  }\n\n  return (\n    <>\n      <h2>City quiz</h2>\n      <p>\n        In which city is there a billboard that turns air into drinkable water?\n      </p>\n      <form onSubmit={handleSubmit}>\n        <textarea\n          value={answer}\n          onChange={handleTextareaChange}\n          disabled={status === 'submitting'}\n        />\n        <br />\n        <button disabled={\n          answer.length === 0 ||\n          status === 'submitting'\n        }>\n          Submit\n        </button>\n        {error !== null &&\n          <p className=\"Error\">\n            {error.message}\n          </p>\n        }\n      </form>\n    </>\n  );\n}\n\nfunction submitForm(answer) {\n  // Pretend it's hitting the network.\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      let shouldError = answer.toLowerCase() !== 'lima'\n      if (shouldError) {\n        reject(new Error('Good guess but a wrong answer. Try again!'));\n      } else {\n        resolve();\n      }\n    }, 1500);\n  });\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Form() {\n  const [firstName, setFirstName] = useState('');\n  const [lastName, setLastName] = useState('');\n  const [fullName, setFullName] = useState('');\n\n  function handleFirstNameChange(e) {\n    setFirstName(e.target.value);\n    setFullName(e.target.value + ' ' + lastName);\n  }\n\n  function handleLastNameChange(e) {\n    setLastName(e.target.value);\n    setFullName(firstName + ' ' + e.target.value);\n  }\n\n  return (\n    <>\n      <h2>Let’s check you in</h2>\n      <label>\n        First name:{' '}\n        <input\n          value={firstName}\n          onChange={handleFirstNameChange}\n        />\n      </label>\n      <label>\n        Last name:{' '}\n        <input\n          value={lastName}\n          onChange={handleLastNameChange}\n        />\n      </label>\n      <p>\n        Your ticket will be issued to: <b>{fullName}</b>\n      </p>\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Form() {\n  const [firstName, setFirstName] = useState('');\n  const [lastName, setLastName] = useState('');\n\n  const fullName = firstName + ' ' + lastName;\n\n  function handleFirstNameChange(e) {\n    setFirstName(e.target.value);\n  }\n\n  function handleLastNameChange(e) {\n    setLastName(e.target.value);\n  }\n\n  return (\n    <>\n      <h2>Let’s check you in</h2>\n      <label>\n        First name:{' '}\n        <input\n          value={firstName}\n          onChange={handleFirstNameChange}\n        />\n      </label>\n      <label>\n        Last name:{' '}\n        <input\n          value={lastName}\n          onChange={handleLastNameChange}\n        />\n      </label>\n      <p>\n        Your ticket will be issued to: <b>{fullName}</b>\n      </p>\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Accordion() {\n  const [activeIndex, setActiveIndex] = useState(0);\n  return (\n    <>\n      <h2>Almaty, Kazakhstan</h2>\n      <Panel\n        title=\"About\"\n        isActive={activeIndex === 0}\n        onShow={() => setActiveIndex(0)}\n      >\n        With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city.\n      </Panel>\n      <Panel\n        title=\"Etymology\"\n        isActive={activeIndex === 1}\n        onShow={() => setActiveIndex(1)}\n      >\n        The name comes from <span lang=\"kk-KZ\">алма</span>, the Kazakh word for \"apple\" and is often translated as \"full of apples\". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild <i lang=\"la\">Malus sieversii</i> is considered a likely candidate for the ancestor of the modern domestic apple.\n      </Panel>\n    </>\n  );\n}\n\nfunction Panel({\n  title,\n  children,\n  isActive,\n  onShow\n}) {\n  return (\n    <section className=\"panel\">\n      <h3>{title}</h3>\n      {isActive ? (\n        <p>{children}</p>\n      ) : (\n        <button onClick={onShow}>\n          Show\n        </button>\n      )}\n    </section>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\nimport Chat from './Chat.js';\nimport ContactList from './ContactList.js';\n\nexport default function Messenger() {\n  const [to, setTo] = useState(contacts[0]);\n  return (\n    <div>\n      <ContactList\n        contacts={contacts}\n        selectedContact={to}\n        onSelect={contact => setTo(contact)}\n      />\n      <Chat contact={to} />\n    </div>\n  )\n}\n\nconst contacts = [\n  { name: 'Taylor', email: 'taylor@mail.com' },\n  { name: 'Alice', email: 'alice@mail.com' },\n  { name: 'Bob', email: 'bob@mail.com' }\n];\n```\n\nExample:\n```text\nimport { useState } from 'react';\nimport Chat from './Chat.js';\nimport ContactList from './ContactList.js';\n\nexport default function Messenger() {\n  const [to, setTo] = useState(contacts[0]);\n  return (\n    <div>\n      <ContactList\n        contacts={contacts}\n        selectedContact={to}\n        onSelect={contact => setTo(contact)}\n      />\n      <Chat key={to.email} contact={to} />\n    </div>\n  )\n}\n\nconst contacts = [\n  { name: 'Taylor', email: 'taylor@mail.com' },\n  { name: 'Alice', email: 'alice@mail.com' },\n  { name: 'Bob', email: 'bob@mail.com' }\n];\n```\n\nExample:\n```text\nimport { useReducer } from 'react';\nimport AddTask from './AddTask.js';\nimport TaskList from './TaskList.js';\n\nexport default function TaskApp() {\n  const [tasks, dispatch] = useReducer(\n    tasksReducer,\n    initialTasks\n  );\n\n  function handleAddTask(text) {\n    dispatch({\n      type: 'added',\n      id: nextId++,\n      text: text,\n    });\n  }\n\n  function handleChangeTask(task) {\n    dispatch({\n      type: 'changed',\n      task: task\n    });\n  }\n\n  function handleDeleteTask(taskId) {\n    dispatch({\n      type: 'deleted',\n      id: taskId\n    });\n  }\n\n  return (\n    <>\n      <h1>Prague itinerary</h1>\n      <AddTask\n        onAddTask={handleAddTask}\n      />\n      <TaskList\n        tasks={tasks}\n        onChangeTask={handleChangeTask}\n        onDeleteTask={handleDeleteTask}\n      />\n    </>\n  );\n}\n\nfunction tasksReducer(tasks, action) {\n  switch (action.type) {\n    case 'added': {\n      return [...tasks, {\n        id: action.id,\n        text: action.text,\n        done: false\n      }];\n    }\n    case 'changed': {\n      return tasks.map(t => {\n        if (t.id === action.task.id) {\n          return action.task;\n        } else {\n          return t;\n        }\n      });\n    }\n    case 'deleted': {\n      return tasks.filter(t => t.id !== action.id);\n    }\n    default: {\n      throw Error('Unknown action: ' + action.type);\n    }\n  }\n}\n\nlet nextId = 3;\nconst initialTasks = [\n  { id: 0, text: 'Visit Kafka Museum', done: true },\n  { id: 1, text: 'Watch a puppet show', done: false },\n  { id: 2, text: 'Lennon Wall pic', done: false }\n];\n```\n\nExample:\n```text\nimport Heading from './Heading.js';\nimport Section from './Section.js';\n\nexport default function Page() {\n  return (\n    <Section>\n      <Heading>Title</Heading>\n      <Section>\n        <Heading>Heading</Heading>\n        <Heading>Heading</Heading>\n        <Heading>Heading</Heading>\n        <Section>\n          <Heading>Sub-heading</Heading>\n          <Heading>Sub-heading</Heading>\n          <Heading>Sub-heading</Heading>\n          <Section>\n            <Heading>Sub-sub-heading</Heading>\n            <Heading>Sub-sub-heading</Heading>\n            <Heading>Sub-sub-heading</Heading>\n          </Section>\n        </Section>\n      </Section>\n    </Section>\n  );\n}\n```\n\nExample:\n```text\nimport AddTask from './AddTask.js';\nimport TaskList from './TaskList.js';\nimport { TasksProvider } from './TasksContext.js';\n\nexport default function TaskApp() {\n  return (\n    <TasksProvider>\n      <h1>Day off in Kyoto</h1>\n      <AddTask />\n      <TaskList />\n    </TasksProvider>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.885Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":9,"totalLines":395,"estimatedTokens":5834}}26{"id":"doc-escape_hatches_react-21f56269","source":"documentation","title":"Escape Hatches – React","url":"https://react.dev/learn/escape-hatches","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactCopy pageCopyEscape HatchesAdvancedSome of your components may need to control and synchronize with systems outside of React. For example, you might need to focus an input using the browser API, play and pause a video player implemented without React, or connect and listen to messages from a remote server. In this chapter, you’ll learn the escape hatches that let you “step outside” React and connect to external systems. Most of your application logic and data flow should not rely on these features. In this chapter How to “remember” information without re-rendering How to access DOM elements managed by React How to synchronize components with external systems How to remove unnecessary Effects from your components How an Effect’s lifecycle is different from a component’s How to prevent some values from re-triggering Effects How to make your Effect re-run less often How to share logic between components Referencing values with refs When you want a component to “remember” some information, but you don’t want that information to trigger new renders, you can use a ref = useRef(0); Like state, refs are retained by React between re-renders. However, setting state re-renders a component. Changing a ref does not! You can access the current value of that ref through the ref.current property. App.jsApp.jsReloadClearForkimport { useRef } from 'react'; export default function Counter() { let ref = useRef(0); function handleClick() { ref.current = ref.current + 1; alert('You clicked ' + ref.current + ' times!'); } return ( <button onClick={handleClick}> Click me! </button> ); } Show more A ref is like a secret pocket of your component that React doesn’t track. For example, you can use refs to store timeout IDs, DOM elements, and other objects that don’t impact the component’s rendering output. Ready to learn this topic?Read Referencing Values with Refs to learn how to use refs to remember information.Read More Manipulating the DOM with refs React automatically updates the DOM to match your render output, so your components won’t often need to manipulate it. However, sometimes you might need access to the DOM elements managed by React—for example, to focus a node, scroll to it, or measure its size and position. There is no built-in way to do those things in React, so you will need a ref to the DOM node. For example, clicking the button will focus the input using a { useRef } from 'react'; export default function Form() { const inputRef = useRef(null); function handleClick() { inputRef.current.focus(); } return ( <> <input ref={inputRef} /> <button onClick={handleClick}> Focus the input </button> </> ); } Show more Ready to learn this topic?Read Manipulating the DOM with Refs to learn how to access DOM elements managed by React.Read More Synchronizing with Effects Some components need to synchronize with external systems. For example, you might want to control a non-React component based on the React state, set up a server connection, or send an analytics log when a component appears on the screen. Unlike event handlers, which let you handle particular events, Effects let you run some code after rendering. Use them to synchronize your component with a system outside of React. Press Play/Pause a few times and see how the video player stays synchronized to the isPlaying prop { useState, useRef, useEffect } from 'react'; function VideoPlayer({ src, isPlaying }) { const ref = useRef(null); useEffect(() => { if (isPlaying) { ref.current.play(); } else { ref.current.pause(); } }, [isPlaying]); return <video ref={ref} src={src} loop playsInline />; } export default function App() { const [isPlaying, setIsPlaying] = useState(false); return ( <> <button onClick={() => setIsPlaying(!isPlaying)}> {isPlaying ? 'Pause' : 'Play'} </button> <VideoPlayer isPlaying={isPlaying} src=\"https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4\" /> </> ); } Show more Many Effects also “clean up” after themselves. For example, an Effect that sets up a connection to a chat server should return a cleanup function that tells React how to disconnect your component from that { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; export default function ChatRoom() { useEffect(() => { const connection = createConnection(); connection.connect(); return () => connection.disconnect(); }, []); return <h1>Welcome to the chat!</h1>; } In development, React will immediately run and clean up your Effect one extra time. This is why you see \"✅ Connecting...\" printed twice. This ensures that you don’t forget to implement the cleanup function. Ready to learn this topic?Read Synchronizing with Effects to learn how to synchronize components with external systems.Read More You Might Not Need An Effect Effects are an escape hatch from the React paradigm. They let you “step outside” of React and synchronize your components with some external system. If there is no external system involved (for example, if you want to update a component’s state when some props or state change), you shouldn’t need an Effect. Removing unnecessary Effects will make your code easier to follow, faster to run, and less error-prone. There are two common cases in which you don’t need don’t need Effects to transform data for rendering. You don’t need Effects to handle user events. For example, you don’t need an Effect to adjust some state based on other Form() { const [firstName, setFirstName] = useState('Taylor'); const [lastName, setLastName] = useState('Swift'); // 🔴 state and unnecessary Effect const [fullName, setFullName] = useState(''); useEffect(() => { setFullName(firstName + ' ' + lastName); }, [firstName, lastName]); // ...} Instead, calculate as much as you can while Form() { const [firstName, setFirstName] = useState('Taylor'); const [lastName, setLastName] = useState('Swift'); // ✅ during rendering const fullName = firstName + ' ' + lastName; // ...} However, you do need Effects to synchronize with external systems. Ready to learn this topic?Read You Might Not Need an Effect to learn how to remove unnecessary Effects.Read More Lifecycle of reactive effects Effects have a different lifecycle from components. Components may mount, update, or unmount. An Effect can only do two start synchronizing something, and later to stop synchronizing it. This cycle can happen multiple times if your Effect depends on props and state that change over time. This Effect depends on the value of the roomId prop. Props are reactive values, which means they can change on a re-render. Notice that the Effect re-synchronizes (and re-connects to the server) if roomId { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); }, [roomId]); return <h1>Welcome to the {roomId} room!</h1>; } export default function App() { const [roomId, setRoomId] = useState('general'); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value=\"general\">general</option> <option value=\"travel\">travel</option> <option value=\"music\">music</option> </select> </label> <hr /> <ChatRoom roomId={roomId} /> </> ); } Show more React provides a linter rule to check that you’ve specified your Effect’s dependencies correctly. If you forget to specify roomId in the list of dependencies in the above example, the linter will find that bug automatically. Ready to learn this topic?Read Lifecycle of Reactive Events to learn how an Effect’s lifecycle is different from a component’s.Read More Separating events from Effects Event handlers only re-run when you perform the same interaction again. Unlike event handlers, Effects re-synchronize if any of the values they read, like props or state, are different than during last render. Sometimes, you want a mix of both Effect that re-runs in response to some values but not others. All code inside Effects is reactive. It will run again if some reactive value it reads has changed due to a re-render. For example, this Effect will re-connect to the chat if either roomId or theme have { useState, useEffect } from 'react'; import { createConnection, sendMessage } from './chat.js'; import { showNotification } from './notifications.js'; const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId, theme }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.on('connected', () => { showNotification('Connected!', theme); }); connection.connect(); return () => connection.disconnect(); }, [roomId, theme]); return <h1>Welcome to the {roomId} room!</h1> } export default function App() { const [roomId, setRoomId] = useState('general'); const [isDark, setIsDark] = useState(false); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value=\"general\">general</option> <option value=\"travel\">travel</option> <option value=\"music\">music</option> </select> </label> <label> <input type=\"checkbox\" checked={isDark} onChange={e => setIsDark(e.target.checked)} /> Use dark theme </label> <hr /> <ChatRoom roomId={roomId} theme={isDark ? 'dark' : 'light'} /> </> ); } Show more This is not ideal. You want to re-connect to the chat only if the roomId has changed. Switching the theme shouldn’t re-connect to the chat! Move the code reading theme out of your Effect into an Effect { useState, useEffect } from 'react'; import { useEffectEvent } from 'react'; import { createConnection, sendMessage } from './chat.js'; import { showNotification } from './notifications.js'; const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId, theme }) { const onConnected = useEffectEvent(() => { showNotification('Connected!', theme); }); useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.on('connected', () => { onConnected(); }); connection.connect(); return () => connection.disconnect(); }, [roomId]); return <h1>Welcome to the {roomId} room!</h1> } export default function App() { const [roomId, setRoomId] = useState('general'); const [isDark, setIsDark] = useState(false); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value=\"general\">general</option> <option value=\"travel\">travel</option> <option value=\"music\">music</option> </select> </label> <label> <input type=\"checkbox\" checked={isDark} onChange={e => setIsDark(e.target.checked)} /> Use dark theme </label> <hr /> <ChatRoom roomId={roomId} theme={isDark ? 'dark' : 'light'} /> </> ); } Show more Code inside Effect Events isn’t reactive, so changing the theme no longer makes your Effect re-connect. Ready to learn this topic?Read Separating Events from Effects to learn how to prevent some values from re-triggering Effects.Read More Removing Effect dependencies When you write an Effect, the linter will verify that you’ve included every reactive value (like props and state) that the Effect reads in the list of your Effect’s dependencies. This ensures that your Effect remains synchronized with the latest props and state of your component. Unnecessary dependencies may cause your Effect to run too often, or even create an infinite loop. The way you remove them depends on the case. For example, this Effect depends on the options object which gets re-created every time you edit the { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId }) { const [message, setMessage] = useState(''); const options = { , }; useEffect(() => { const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [options]); return ( <> <h1>Welcome to the {roomId} room!</h1> <input value={message} onChange={e => setMessage(e.target.value)} /> </> ); } export default function App() { const [roomId, setRoomId] = useState('general'); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value=\"general\">general</option> <option value=\"travel\">travel</option> <option value=\"music\">music</option> </select> </label> <hr /> <ChatRoom roomId={roomId} /> </> ); } Show more You don’t want the chat to re-connect every time you start typing a message in that chat. To fix this problem, move creation of the options object inside the Effect so that the Effect only depends on the roomId { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId }) { const [message, setMessage] = useState(''); useEffect(() => { const options = { , }; const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [roomId]); return ( <> <h1>Welcome to the {roomId} room!</h1> <input value={message} onChange={e => setMessage(e.target.value)} /> </> ); } export default function App() { const [roomId, setRoomId] = useState('general'); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value=\"general\">general</option> <option value=\"travel\">travel</option> <option value=\"music\">music</option> </select> </label> <hr /> <ChatRoom roomId={roomId} /> </> ); } Show more Notice that you didn’t start by editing the dependency list to remove the options dependency. That would be wrong. Instead, you changed the surrounding code so that the dependency became unnecessary. Think of the dependency list as a list of all the reactive values used by your Effect’s code. You don’t intentionally choose what to put on that list. The list describes your code. To change the dependency list, change the code. Ready to learn this topic?Read Removing Effect Dependencies to learn how to make your Effect re-run less often.Read More Reusing logic with custom Hooks React comes with built-in Hooks like useState, useContext, and useEffect. Sometimes, you’ll wish that there was a Hook for some more specific example, to fetch data, to keep track of whether the user is online, or to connect to a chat room. To do this, you can create your own Hooks for your application’s needs. In this example, the usePointerPosition custom Hook tracks the cursor position, while useDelayedValue custom Hook returns a value that’s “lagging behind” the value you passed by a certain number of milliseconds. Move the cursor over the sandbox preview area to see a moving trail of dots following the { usePointerPosition } from './usePointerPosition.js'; import { useDelayedValue } from './useDelayedValue.js'; export default function Canvas() { const pos1 = usePointerPosition(); const pos2 = useDelayedValue(pos1, 100); const pos3 = useDelayedValue(pos2, 200); const pos4 = useDelayedValue(pos3, 100); const pos5 = useDelayedValue(pos4, 50); return ( <> <Dot position={pos1} opacity={1} /> <Dot position={pos2} opacity={0.8} /> <Dot position={pos3} opacity={0.6} /> <Dot position={pos4} opacity={0.4} /> <Dot position={pos5} opacity={0.2} /> </> ); } function Dot({ position, opacity }) { return ( <div style={{ position: 'absolute', backgroundColor: 'pink', borderRadius: '50%', opacity, transform: `translate(${position.x}px, ${position.y}px)`, pointerEvents: 'none', , , , , }} /> ); } Show more You can create custom Hooks, compose them together, pass data between them, and reuse them between components. As your app grows, you will write fewer Effects by hand because you’ll be able to reuse custom Hooks you already wrote. There are also many excellent custom Hooks maintained by the React community. Ready to learn this topic?Read Reusing Logic with Custom Hooks to learn how to share logic between components.Read More What’s next? Head over to Referencing Values with Refs to start reading this chapter page by page!PreviousScaling Up with Reducer and ContextNextReferencing Values with RefsCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewReferencing values with refs Manipulating the DOM with refs Synchronizing with Effects You Might Not Need An Effect Lifecycle of reactive effects Separating events from Effects Removing Effect dependencies Reusing logic with custom Hooks What’s next?\n\nExample:\n```javascript\nconst ref = useRef(0);\n```\n\nExample:\n```text\nimport { useRef } from 'react';\n\nexport default function Counter() {\n  let ref = useRef(0);\n\n  function handleClick() {\n    ref.current = ref.current + 1;\n    alert('You clicked ' + ref.current + ' times!');\n  }\n\n  return (\n    <button onClick={handleClick}>\n      Click me!\n    </button>\n  );\n}\n```\n\nExample:\n```text\nimport { useRef } from 'react';\n\nexport default function Form() {\n  const inputRef = useRef(null);\n\n  function handleClick() {\n    inputRef.current.focus();\n  }\n\n  return (\n    <>\n      <input ref={inputRef} />\n      <button onClick={handleClick}>\n        Focus the input\n      </button>\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState, useRef, useEffect } from 'react';\n\nfunction VideoPlayer({ src, isPlaying }) {\n  const ref = useRef(null);\n\n  useEffect(() => {\n    if (isPlaying) {\n      ref.current.play();\n    } else {\n      ref.current.pause();\n    }\n  }, [isPlaying]);\n\n  return <video ref={ref} src={src} loop playsInline />;\n}\n\nexport default function App() {\n  const [isPlaying, setIsPlaying] = useState(false);\n  return (\n    <>\n      <button onClick={() => setIsPlaying(!isPlaying)}>\n        {isPlaying ? 'Pause' : 'Play'}\n      </button>\n      <VideoPlayer\n        isPlaying={isPlaying}\n        src=\"https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4\"\n      />\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';\n\nexport default function ChatRoom() {\n  useEffect(() => {\n    const connection = createConnection();\n    connection.connect();\n    return () => connection.disconnect();\n  }, []);\n  return <h1>Welcome to the chat!</h1>;\n}\n```\n\nExample:\n```javascript\nfunction Form() {  const [firstName, setFirstName] = useState('Taylor');  const [lastName, setLastName] = useState('Swift');  // 🔴 Avoid: redundant state and unnecessary Effect  const [fullName, setFullName] = useState('');  useEffect(() => {    setFullName(firstName + ' ' + lastName);  }, [firstName, lastName]);  // ...}\n```\n\nExample:\n```javascript\nfunction Form() {  const [firstName, setFirstName] = useState('Taylor');  const [lastName, setLastName] = useState('Swift');  // ✅ Good: calculated during rendering  const fullName = firstName + ' ' + lastName;  // ...}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';\n\nconst serverUrl = 'https://localhost:1234';\n\nfunction ChatRoom({ roomId }) {\n  useEffect(() => {\n    const connection = createConnection(serverUrl, roomId);\n    connection.connect();\n    return () => connection.disconnect();\n  }, [roomId]);\n\n  return <h1>Welcome to the {roomId} room!</h1>;\n}\n\nexport default function App() {\n  const [roomId, setRoomId] = useState('general');\n  return (\n    <>\n      <label>\n        Choose the chat room:{' '}\n        <select\n          value={roomId}\n          onChange={e => setRoomId(e.target.value)}\n        >\n          <option value=\"general\">general</option>\n          <option value=\"travel\">travel</option>\n          <option value=\"music\">music</option>\n        </select>\n      </label>\n      <hr />\n      <ChatRoom roomId={roomId} />\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { createConnection, sendMessage } from './chat.js';\nimport { showNotification } from './notifications.js';\n\nconst serverUrl = 'https://localhost:1234';\n\nfunction ChatRoom({ roomId, theme }) {\n  useEffect(() => {\n    const connection = createConnection(serverUrl, roomId);\n    connection.on('connected', () => {\n      showNotification('Connected!', theme);\n    });\n    connection.connect();\n    return () => connection.disconnect();\n  }, [roomId, theme]);\n\n  return <h1>Welcome to the {roomId} room!</h1>\n}\n\nexport default function App() {\n  const [roomId, setRoomId] = useState('general');\n  const [isDark, setIsDark] = useState(false);\n  return (\n    <>\n      <label>\n        Choose the chat room:{' '}\n        <select\n          value={roomId}\n          onChange={e => setRoomId(e.target.value)}\n        >\n          <option value=\"general\">general</option>\n          <option value=\"travel\">travel</option>\n          <option value=\"music\">music</option>\n        </select>\n      </label>\n      <label>\n        <input\n          type=\"checkbox\"\n          checked={isDark}\n          onChange={e => setIsDark(e.target.checked)}\n        />\n        Use dark theme\n      </label>\n      <hr />\n      <ChatRoom\n        roomId={roomId}\n        theme={isDark ? 'dark' : 'light'}\n      />\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { useEffectEvent } from 'react';\nimport { createConnection, sendMessage } from './chat.js';\nimport { showNotification } from './notifications.js';\n\nconst serverUrl = 'https://localhost:1234';\n\nfunction ChatRoom({ roomId, theme }) {\n  const onConnected = useEffectEvent(() => {\n    showNotification('Connected!', theme);\n  });\n\n  useEffect(() => {\n    const connection = createConnection(serverUrl, roomId);\n    connection.on('connected', () => {\n      onConnected();\n    });\n    connection.connect();\n    return () => connection.disconnect();\n  }, [roomId]);\n\n  return <h1>Welcome to the {roomId} room!</h1>\n}\n\nexport default function App() {\n  const [roomId, setRoomId] = useState('general');\n  const [isDark, setIsDark] = useState(false);\n  return (\n    <>\n      <label>\n        Choose the chat room:{' '}\n        <select\n          value={roomId}\n          onChange={e => setRoomId(e.target.value)}\n        >\n          <option value=\"general\">general</option>\n          <option value=\"travel\">travel</option>\n          <option value=\"music\">music</option>\n        </select>\n      </label>\n      <label>\n        <input\n          type=\"checkbox\"\n          checked={isDark}\n          onChange={e => setIsDark(e.target.checked)}\n        />\n        Use dark theme\n      </label>\n      <hr />\n      <ChatRoom\n        roomId={roomId}\n        theme={isDark ? 'dark' : 'light'}\n      />\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';\n\nconst serverUrl = 'https://localhost:1234';\n\nfunction ChatRoom({ roomId }) {\n  const [message, setMessage] = useState('');\n\n  const options = {\n    serverUrl: serverUrl,\n    roomId: roomId\n  };\n\n  useEffect(() => {\n    const connection = createConnection(options);\n    connection.connect();\n    return () => connection.disconnect();\n  }, [options]);\n\n  return (\n    <>\n      <h1>Welcome to the {roomId} room!</h1>\n      <input value={message} onChange={e => setMessage(e.target.value)} />\n    </>\n  );\n}\n\nexport default function App() {\n  const [roomId, setRoomId] = useState('general');\n  return (\n    <>\n      <label>\n        Choose the chat room:{' '}\n        <select\n          value={roomId}\n          onChange={e => setRoomId(e.target.value)}\n        >\n          <option value=\"general\">general</option>\n          <option value=\"travel\">travel</option>\n          <option value=\"music\">music</option>\n        </select>\n      </label>\n      <hr />\n      <ChatRoom roomId={roomId} />\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';\n\nconst serverUrl = 'https://localhost:1234';\n\nfunction ChatRoom({ roomId }) {\n  const [message, setMessage] = useState('');\n\n  useEffect(() => {\n    const options = {\n      serverUrl: serverUrl,\n      roomId: roomId\n    };\n    const connection = createConnection(options);\n    connection.connect();\n    return () => connection.disconnect();\n  }, [roomId]);\n\n  return (\n    <>\n      <h1>Welcome to the {roomId} room!</h1>\n      <input value={message} onChange={e => setMessage(e.target.value)} />\n    </>\n  );\n}\n\nexport default function App() {\n  const [roomId, setRoomId] = useState('general');\n  return (\n    <>\n      <label>\n        Choose the chat room:{' '}\n        <select\n          value={roomId}\n          onChange={e => setRoomId(e.target.value)}\n        >\n          <option value=\"general\">general</option>\n          <option value=\"travel\">travel</option>\n          <option value=\"music\">music</option>\n        </select>\n      </label>\n      <hr />\n      <ChatRoom roomId={roomId} />\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { usePointerPosition } from './usePointerPosition.js';\nimport { useDelayedValue } from './useDelayedValue.js';\n\nexport default function Canvas() {\n  const pos1 = usePointerPosition();\n  const pos2 = useDelayedValue(pos1, 100);\n  const pos3 = useDelayedValue(pos2, 200);\n  const pos4 = useDelayedValue(pos3, 100);\n  const pos5 = useDelayedValue(pos4, 50);\n  return (\n    <>\n      <Dot position={pos1} opacity={1} />\n      <Dot position={pos2} opacity={0.8} />\n      <Dot position={pos3} opacity={0.6} />\n      <Dot position={pos4} opacity={0.4} />\n      <Dot position={pos5} opacity={0.2} />\n    </>\n  );\n}\n\nfunction Dot({ position, opacity }) {\n  return (\n    <div style={{\n      position: 'absolute',\n      backgroundColor: 'pink',\n      borderRadius: '50%',\n      opacity,\n      transform: `translate(${position.x}px, ${position.y}px)`,\n      pointerEvents: 'none',\n      left: -20,\n      top: -20,\n      width: 40,\n      height: 40,\n    }} />\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.888Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":13,"totalLines":404,"estimatedTokens":6830}}27{"id":"doc-manipulating_the_dom_with_refs_react-2472a2b1","source":"documentation","title":"Manipulating the DOM with Refs – React","url":"https://react.dev/learn/manipulating-the-dom-with-refs","text":"Example:\n```javascript\nimport { useRef } from 'react';\n```\n\nExample:\n```javascript\nconst myRef = useRef(null);\n```\n\nExample:\n```javascript\n<div ref={myRef}>\n```\n\nExample:\n```javascript\n// You can use any browser APIs, for example:myRef.current.scrollIntoView();\n```\n\nExample:\n```text\nimport { useRef } from 'react';\n\nexport default function Form() {\n  const inputRef = useRef(null);\n\n  function handleClick() {\n    inputRef.current.focus();\n  }\n\n  return (\n    <>\n      <input ref={inputRef} />\n      <button onClick={handleClick}>\n        Focus the input\n      </button>\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useRef } from 'react';\n\nexport default function CatFriends() {\n  const firstCatRef = useRef(null);\n  const secondCatRef = useRef(null);\n  const thirdCatRef = useRef(null);\n\n  function handleScrollToFirstCat() {\n    firstCatRef.current.scrollIntoView({\n      behavior: 'smooth',\n      block: 'nearest',\n      inline: 'center'\n    });\n  }\n\n  function handleScrollToSecondCat() {\n    secondCatRef.current.scrollIntoView({\n      behavior: 'smooth',\n      block: 'nearest',\n      inline: 'center'\n    });\n  }\n\n  function handleScrollToThirdCat() {\n    thirdCatRef.current.scrollIntoView({\n      behavior: 'smooth',\n      block: 'nearest',\n      inline: 'center'\n    });\n  }\n\n  return (\n    <>\n      <nav>\n        <button onClick={handleScrollToFirstCat}>\n          Neo\n        </button>\n        <button onClick={handleScrollToSecondCat}>\n          Millie\n        </button>\n        <button onClick={handleScrollToThirdCat}>\n          Bella\n        </button>\n      </nav>\n      <div>\n        <ul>\n          <li>\n            <img\n              src=\"https://placecats.com/neo/300/200\"\n              alt=\"Neo\"\n              ref={firstCatRef}\n            />\n          </li>\n          <li>\n            <img\n              src=\"https://placecats.com/millie/200/200\"\n              alt=\"Millie\"\n              ref={secondCatRef}\n            />\n          </li>\n          <li>\n            <img\n              src=\"https://placecats.com/bella/199/200\"\n              alt=\"Bella\"\n              ref={thirdCatRef}\n            />\n          </li>\n        </ul>\n      </div>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\n<ul>  {items.map((item) => {    // Doesn't work!    const ref = useRef(null);    return <li ref={ref} />;  })}</ul>\n```\n\nExample:\n```text\nimport { useRef, useState } from \"react\";\n\nexport default function CatFriends() {\n  const itemsRef = useRef(null);\n  const [catList, setCatList] = useState(setupCatList);\n\n  function scrollToCat(cat) {\n    const map = getMap();\n    const node = map.get(cat);\n    node.scrollIntoView({\n      behavior: \"smooth\",\n      block: \"nearest\",\n      inline: \"center\",\n    });\n  }\n\n  function getMap() {\n    if (!itemsRef.current) {\n      // Initialize the Map on first usage.\n      itemsRef.current = new Map();\n    }\n    return itemsRef.current;\n  }\n\n  return (\n    <>\n      <nav>\n        <button onClick={() => scrollToCat(catList[0])}>Neo</button>\n        <button onClick={() => scrollToCat(catList[5])}>Millie</button>\n        <button onClick={() => scrollToCat(catList[8])}>Bella</button>\n      </nav>\n      <div>\n        <ul>\n          {catList.map((cat) => (\n            <li\n              key={cat.id}\n              ref={(node) => {\n                const map = getMap();\n                map.set(cat, node);\n\n                return () => {\n                  map.delete(cat);\n                };\n              }}\n            >\n              <img src={cat.imageUrl} />\n            </li>\n          ))}\n        </ul>\n      </div>\n    </>\n  );\n}\n\nfunction setupCatList() {\n  const catCount = 10;\n  const catList = new Array(catCount)\n  for (let i = 0; i < catCount; i++) {\n    let imageUrl = '';\n    if (i < 5) {\n      imageUrl = \"https://placecats.com/neo/320/240\";\n    } else if (i < 8) {\n      imageUrl = \"https://placecats.com/millie/320/240\";\n    } else {\n      imageUrl = \"https://placecats.com/bella/320/240\";\n    }\n    catList[i] = {\n      id: i,\n      imageUrl,\n    };\n  }\n  return catList;\n}\n```\n\nExample:\n```javascript\n<li  key={cat.id}  ref={node => {    const map = getMap();    // Add to the Map    map.set(cat, node);    return () => {      // Remove from the Map      map.delete(cat);    };  }}>\n```\n\nExample:\n```javascript\nimport { useRef } from 'react';function MyInput({ ref }) {  return <input ref={ref} />;}function MyForm() {  const inputRef = useRef(null);  return <MyInput ref={inputRef} />}\n```\n\nExample:\n```text\nimport { useRef } from 'react';\n\nfunction MyInput({ ref }) {\n  return <input ref={ref} />;\n}\n\nexport default function MyForm() {\n  const inputRef = useRef(null);\n\n  function handleClick() {\n    inputRef.current.focus();\n  }\n\n  return (\n    <>\n      <MyInput ref={inputRef} />\n      <button onClick={handleClick}>\n        Focus the input\n      </button>\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useRef, useImperativeHandle } from \"react\";\n\nfunction MyInput({ ref }) {\n  const realInputRef = useRef(null);\n  useImperativeHandle(ref, () => ({\n    // Only expose focus and nothing else\n    focus() {\n      realInputRef.current.focus();\n    },\n  }));\n  return <input ref={realInputRef} />;\n};\n\nexport default function Form() {\n  const inputRef = useRef(null);\n\n  function handleClick() {\n    inputRef.current.focus();\n  }\n\n  return (\n    <>\n      <MyInput ref={inputRef} />\n      <button onClick={handleClick}>Focus the input</button>\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState, useRef } from 'react';\n\nexport default function TodoList() {\n  const listRef = useRef(null);\n  const [text, setText] = useState('');\n  const [todos, setTodos] = useState(\n    initialTodos\n  );\n\n  function handleAdd() {\n    const newTodo = { id: nextId++, text: text };\n    setText('');\n    setTodos([ ...todos, newTodo]);\n    listRef.current.lastChild.scrollIntoView({\n      behavior: 'smooth',\n      block: 'nearest'\n    });\n  }\n\n  return (\n    <>\n      <button onClick={handleAdd}>\n        Add\n      </button>\n      <input\n        value={text}\n        onChange={e => setText(e.target.value)}\n      />\n      <ul ref={listRef}>\n        {todos.map(todo => (\n          <li key={todo.id}>{todo.text}</li>\n        ))}\n      </ul>\n    </>\n  );\n}\n\nlet nextId = 0;\nlet initialTodos = [];\nfor (let i = 0; i < 20; i++) {\n  initialTodos.push({\n    id: nextId++,\n    text: 'Todo #' + (i + 1)\n  });\n}\n```\n\nExample:\n```javascript\nsetTodos([ ...todos, newTodo]);listRef.current.lastChild.scrollIntoView();\n```\n\nExample:\n```javascript\nflushSync(() => {  setTodos([ ...todos, newTodo]);});listRef.current.lastChild.scrollIntoView();\n```\n\nExample:\n```text\nimport { useState, useRef } from 'react';\nimport { flushSync } from 'react-dom';\n\nexport default function TodoList() {\n  const listRef = useRef(null);\n  const [text, setText] = useState('');\n  const [todos, setTodos] = useState(\n    initialTodos\n  );\n\n  function handleAdd() {\n    const newTodo = { id: nextId++, text: text };\n    flushSync(() => {\n      setText('');\n      setTodos([ ...todos, newTodo]);\n    });\n    listRef.current.lastChild.scrollIntoView({\n      behavior: 'smooth',\n      block: 'nearest'\n    });\n  }\n\n  return (\n    <>\n      <button onClick={handleAdd}>\n        Add\n      </button>\n      <input\n        value={text}\n        onChange={e => setText(e.target.value)}\n      />\n      <ul ref={listRef}>\n        {todos.map(todo => (\n          <li key={todo.id}>{todo.text}</li>\n        ))}\n      </ul>\n    </>\n  );\n}\n\nlet nextId = 0;\nlet initialTodos = [];\nfor (let i = 0; i < 20; i++) {\n  initialTodos.push({\n    id: nextId++,\n    text: 'Todo #' + (i + 1)\n  });\n}\n```\n\nExample:\n```text\nimport { useState, useRef } from 'react';\n\nexport default function Counter() {\n  const [show, setShow] = useState(true);\n  const ref = useRef(null);\n\n  return (\n    <div>\n      <button\n        onClick={() => {\n          setShow(!show);\n        }}>\n        Toggle with setState\n      </button>\n      <button\n        onClick={() => {\n          ref.current.remove();\n        }}>\n        Remove from the DOM\n      </button>\n      {show && <p ref={ref}>Hello world</p>}\n    </div>\n  );\n}\n```\n\nExample:\n```text\nimport { useState, useRef } from 'react';\n\nexport default function VideoPlayer() {\n  const [isPlaying, setIsPlaying] = useState(false);\n\n  function handleClick() {\n    const nextIsPlaying = !isPlaying;\n    setIsPlaying(nextIsPlaying);\n  }\n\n  return (\n    <>\n      <button onClick={handleClick}>\n        {isPlaying ? 'Pause' : 'Play'}\n      </button>\n      <video width=\"250\">\n        <source\n          src=\"https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4\"\n          type=\"video/mp4\"\n        />\n      </video>\n    </>\n  )\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.889Z","totalSectionsIncluded":0,"totalCodeBlocksIncluded":18,"totalLines":435,"estimatedTokens":2170}}28{"id":"doc-extracting_state_logic_into_a_reducer_react-0e83d210","source":"documentation","title":"Extracting State Logic into a Reducer – React","url":"https://react.dev/learn/extracting-state-logic-into-a-reducer","text":"Example:\n```text\nimport { useState } from 'react';\nimport AddTask from './AddTask.js';\nimport TaskList from './TaskList.js';\n\nexport default function TaskApp() {\n  const [tasks, setTasks] = useState(initialTasks);\n\n  function handleAddTask(text) {\n    setTasks([\n      ...tasks,\n      {\n        id: nextId++,\n        text: text,\n        done: false,\n      },\n    ]);\n  }\n\n  function handleChangeTask(task) {\n    setTasks(\n      tasks.map((t) => {\n        if (t.id === task.id) {\n          return task;\n        } else {\n          return t;\n        }\n      })\n    );\n  }\n\n  function handleDeleteTask(taskId) {\n    setTasks(tasks.filter((t) => t.id !== taskId));\n  }\n\n  return (\n    <>\n      <h1>Prague itinerary</h1>\n      <AddTask onAddTask={handleAddTask} />\n      <TaskList\n        tasks={tasks}\n        onChangeTask={handleChangeTask}\n        onDeleteTask={handleDeleteTask}\n      />\n    </>\n  );\n}\n\nlet nextId = 3;\nconst initialTasks = [\n  {id: 0, text: 'Visit Kafka Museum', done: true},\n  {id: 1, text: 'Watch a puppet show', done: false},\n  {id: 2, text: 'Lennon Wall pic', done: false},\n];\n```\n\nExample:\n```javascript\nfunction handleAddTask(text) {  setTasks([    ...tasks,    {      id: nextId++,      text: text,      done: false,    },  ]);}function handleChangeTask(task) {  setTasks(    tasks.map((t) => {      if (t.id === task.id) {        return task;      } else {        return t;      }    })  );}function handleDeleteTask(taskId) {  setTasks(tasks.filter((t) => t.id !== taskId));}\n```\n\nExample:\n```javascript\nfunction handleAddTask(text) {  dispatch({    type: 'added',    id: nextId++,    text: text,  });}function handleChangeTask(task) {  dispatch({    type: 'changed',    task: task,  });}function handleDeleteTask(taskId) {  dispatch({    type: 'deleted',    id: taskId,  });}\n```\n\nExample:\n```javascript\nfunction handleDeleteTask(taskId) {  dispatch(    // \"action\" object:    {      type: 'deleted',      id: taskId,    }  );}\n```\n\nExample:\n```javascript\ndispatch({  // specific to component  type: 'what_happened',  // other fields go here});\n```\n\nExample:\n```javascript\nfunction yourReducer(state, action) {  // return next state for React to set}\n```\n\nExample:\n```javascript\nfunction tasksReducer(tasks, action) {  if (action.type === 'added') {    return [      ...tasks,      {        id: action.id,        text: action.text,        done: false,      },    ];  } else if (action.type === 'changed') {    return tasks.map((t) => {      if (t.id === action.task.id) {        return action.task;      } else {        return t;      }    });  } else if (action.type === 'deleted') {    return tasks.filter((t) => t.id !== action.id);  } else {    throw Error('Unknown action: ' + action.type);  }}\n```\n\nExample:\n```javascript\nfunction tasksReducer(tasks, action) {  switch (action.type) {    case 'added': {      return [        ...tasks,        {          id: action.id,          text: action.text,          done: false,        },      ];    }    case 'changed': {      return tasks.map((t) => {        if (t.id === action.task.id) {          return action.task;        } else {          return t;        }      });    }    case 'deleted': {      return tasks.filter((t) => t.id !== action.id);    }    default: {      throw Error('Unknown action: ' + action.type);    }  }}\n```\n\nExample:\n```javascript\nconst arr = [1, 2, 3, 4, 5];const sum = arr.reduce(  (result, number) => result + number); // 1 + 2 + 3 + 4 + 5\n```\n\nExample:\n```text\nimport tasksReducer from './tasksReducer.js';\n\nlet initialState = [];\nlet actions = [\n  {type: 'added', id: 1, text: 'Visit Kafka Museum'},\n  {type: 'added', id: 2, text: 'Watch a puppet show'},\n  {type: 'deleted', id: 1},\n  {type: 'added', id: 3, text: 'Lennon Wall pic'},\n];\n\nlet finalState = actions.reduce(tasksReducer, initialState);\n\nconst output = document.getElementById('output');\noutput.textContent = JSON.stringify(finalState, null, 2);\n```\n\nExample:\n```javascript\nimport { useReducer } from 'react';\n```\n\nExample:\n```javascript\nconst [tasks, setTasks] = useState(initialTasks);\n```\n\nExample:\n```javascript\nconst [tasks, dispatch] = useReducer(tasksReducer, initialTasks);\n```\n\nExample:\n```text\nimport { useReducer } from 'react';\nimport AddTask from './AddTask.js';\nimport TaskList from './TaskList.js';\n\nexport default function TaskApp() {\n  const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);\n\n  function handleAddTask(text) {\n    dispatch({\n      type: 'added',\n      id: nextId++,\n      text: text,\n    });\n  }\n\n  function handleChangeTask(task) {\n    dispatch({\n      type: 'changed',\n      task: task,\n    });\n  }\n\n  function handleDeleteTask(taskId) {\n    dispatch({\n      type: 'deleted',\n      id: taskId,\n    });\n  }\n\n  return (\n    <>\n      <h1>Prague itinerary</h1>\n      <AddTask onAddTask={handleAddTask} />\n      <TaskList\n        tasks={tasks}\n        onChangeTask={handleChangeTask}\n        onDeleteTask={handleDeleteTask}\n      />\n    </>\n  );\n}\n\nfunction tasksReducer(tasks, action) {\n  switch (action.type) {\n    case 'added': {\n      return [\n        ...tasks,\n        {\n          id: action.id,\n          text: action.text,\n          done: false,\n        },\n      ];\n    }\n    case 'changed': {\n      return tasks.map((t) => {\n        if (t.id === action.task.id) {\n          return action.task;\n        } else {\n          return t;\n        }\n      });\n    }\n    case 'deleted': {\n      return tasks.filter((t) => t.id !== action.id);\n    }\n    default: {\n      throw Error('Unknown action: ' + action.type);\n    }\n  }\n}\n\nlet nextId = 3;\nconst initialTasks = [\n  {id: 0, text: 'Visit Kafka Museum', done: true},\n  {id: 1, text: 'Watch a puppet show', done: false},\n  {id: 2, text: 'Lennon Wall pic', done: false},\n];\n```\n\nExample:\n```text\nimport { useReducer } from 'react';\nimport AddTask from './AddTask.js';\nimport TaskList from './TaskList.js';\nimport tasksReducer from './tasksReducer.js';\n\nexport default function TaskApp() {\n  const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);\n\n  function handleAddTask(text) {\n    dispatch({\n      type: 'added',\n      id: nextId++,\n      text: text,\n    });\n  }\n\n  function handleChangeTask(task) {\n    dispatch({\n      type: 'changed',\n      task: task,\n    });\n  }\n\n  function handleDeleteTask(taskId) {\n    dispatch({\n      type: 'deleted',\n      id: taskId,\n    });\n  }\n\n  return (\n    <>\n      <h1>Prague itinerary</h1>\n      <AddTask onAddTask={handleAddTask} />\n      <TaskList\n        tasks={tasks}\n        onChangeTask={handleChangeTask}\n        onDeleteTask={handleDeleteTask}\n      />\n    </>\n  );\n}\n\nlet nextId = 3;\nconst initialTasks = [\n  {id: 0, text: 'Visit Kafka Museum', done: true},\n  {id: 1, text: 'Watch a puppet show', done: false},\n  {id: 2, text: 'Lennon Wall pic', done: false},\n];\n```\n\nExample:\n```text\n{\n  \"dependencies\": {\n    \"immer\": \"1.7.3\",\n    \"react\": \"latest\",\n    \"react-dom\": \"latest\",\n    \"react-scripts\": \"latest\",\n    \"use-immer\": \"0.5.1\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"test\": \"react-scripts test --env=jsdom\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"devDependencies\": {}\n}\n```\n\nExample:\n```text\nimport { useReducer } from 'react';\nimport Chat from './Chat.js';\nimport ContactList from './ContactList.js';\nimport { initialState, messengerReducer } from './messengerReducer';\n\nexport default function Messenger() {\n  const [state, dispatch] = useReducer(messengerReducer, initialState);\n  const message = state.message;\n  const contact = contacts.find((c) => c.id === state.selectedId);\n  return (\n    <div>\n      <ContactList\n        contacts={contacts}\n        selectedId={state.selectedId}\n        dispatch={dispatch}\n      />\n      <Chat\n        key={contact.id}\n        message={message}\n        contact={contact}\n        dispatch={dispatch}\n      />\n    </div>\n  );\n}\n\nconst contacts = [\n  {id: 0, name: 'Taylor', email: 'taylor@mail.com'},\n  {id: 1, name: 'Alice', email: 'alice@mail.com'},\n  {id: 2, name: 'Bob', email: 'bob@mail.com'},\n];\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.892Z","totalSectionsIncluded":0,"totalCodeBlocksIncluded":17,"totalLines":321,"estimatedTokens":2012}}29{"id":"doc-lifecycle_of_reactive_effects_react-41c5633b","source":"documentation","title":"Lifecycle of Reactive Effects – React","url":"https://react.dev/learn/lifecycle-of-reactive-effects","text":"Example:\n```javascript\nconst serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) {  useEffect(() => {    const connection = createConnection(serverUrl, roomId);    connection.connect();    return () => {      connection.disconnect();    };  }, [roomId]);  // ...}\n```\n\nExample:\n```javascript\n// ...    const connection = createConnection(serverUrl, roomId);    connection.connect();    return () => {      connection.disconnect();    };    // ...\n```\n\nExample:\n```javascript\nconst serverUrl = 'https://localhost:1234';function ChatRoom({ roomId /* \"general\" */ }) {  // ...  return <h1>Welcome to the {roomId} room!</h1>;}\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId /* \"general\" */ }) {  useEffect(() => {    const connection = createConnection(serverUrl, roomId); // Connects to the \"general\" room    connection.connect();    return () => {      connection.disconnect(); // Disconnects from the \"general\" room    };  }, [roomId]);  // ...\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId /* \"travel\" */ }) {  // ...  return <h1>Welcome to the {roomId} room!</h1>;}\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId /* \"general\" */ }) {  useEffect(() => {    const connection = createConnection(serverUrl, roomId); // Connects to the \"general\" room    connection.connect();    return () => {      connection.disconnect(); // Disconnects from the \"general\" room    };    // ...\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId /* \"travel\" */ }) {  useEffect(() => {    const connection = createConnection(serverUrl, roomId); // Connects to the \"travel\" room    connection.connect();    // ...\n```\n\nExample:\n```javascript\nuseEffect(() => {    // Your Effect connected to the room specified with roomId...    const connection = createConnection(serverUrl, roomId);    connection.connect();    return () => {      // ...until it disconnected      connection.disconnect();    };  }, [roomId]);\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';\n\nconst serverUrl = 'https://localhost:1234';\n\nfunction ChatRoom({ roomId }) {\n  useEffect(() => {\n    const connection = createConnection(serverUrl, roomId);\n    connection.connect();\n    return () => connection.disconnect();\n  }, [roomId]);\n  return <h1>Welcome to the {roomId} room!</h1>;\n}\n\nexport default function App() {\n  const [roomId, setRoomId] = useState('general');\n  const [show, setShow] = useState(false);\n  return (\n    <>\n      <label>\n        Choose the chat room:{' '}\n        <select\n          value={roomId}\n          onChange={e => setRoomId(e.target.value)}\n        >\n          <option value=\"general\">general</option>\n          <option value=\"travel\">travel</option>\n          <option value=\"music\">music</option>\n        </select>\n      </label>\n      <button onClick={() => setShow(!show)}>\n        {show ? 'Close chat' : 'Open chat'}\n      </button>\n      {show && <hr />}\n      {show && <ChatRoom roomId={roomId} />}\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId }) { // The roomId prop may change over time  useEffect(() => {    const connection = createConnection(serverUrl, roomId); // This Effect reads roomId    connection.connect();    return () => {      connection.disconnect();    };  }, [roomId]); // So you tell React that this Effect \"depends on\" roomId  // ...\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId }) {  useEffect(() => {    logVisit(roomId);    const connection = createConnection(serverUrl, roomId);    connection.connect();    return () => {      connection.disconnect();    };  }, [roomId]);  // ...}\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId }) {  useEffect(() => {    logVisit(roomId);  }, [roomId]);  useEffect(() => {    const connection = createConnection(serverUrl, roomId);    // ...  }, [roomId]);  // ...}\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId }) { // Props change over time  const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // State may change over time  useEffect(() => {    const connection = createConnection(serverUrl, roomId); // Your Effect reads props and state    connection.connect();    return () => {      connection.disconnect();    };  }, [roomId, serverUrl]); // So you tell React that this Effect \"depends on\" on props and state  // ...}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';\n\nfunction ChatRoom({ roomId }) {\n  const [serverUrl, setServerUrl] = useState('https://localhost:1234');\n\n  useEffect(() => {\n    const connection = createConnection(serverUrl, roomId);\n    connection.connect();\n    return () => connection.disconnect();\n  }, [roomId, serverUrl]);\n\n  return (\n    <>\n      <label>\n        Server URL:{' '}\n        <input\n          value={serverUrl}\n          onChange={e => setServerUrl(e.target.value)}\n        />\n      </label>\n      <h1>Welcome to the {roomId} room!</h1>\n    </>\n  );\n}\n\nexport default function App() {\n  const [roomId, setRoomId] = useState('general');\n  return (\n    <>\n      <label>\n        Choose the chat room:{' '}\n        <select\n          value={roomId}\n          onChange={e => setRoomId(e.target.value)}\n        >\n          <option value=\"general\">general</option>\n          <option value=\"travel\">travel</option>\n          <option value=\"music\">music</option>\n        </select>\n      </label>\n      <hr />\n      <ChatRoom roomId={roomId} />\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nconst serverUrl = 'https://localhost:1234';const roomId = 'general';function ChatRoom() {  useEffect(() => {    const connection = createConnection(serverUrl, roomId);    connection.connect();    return () => {      connection.disconnect();    };  }, []); // ✅ All dependencies declared  // ...}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';\n\nconst serverUrl = 'https://localhost:1234';\nconst roomId = 'general';\n\nfunction ChatRoom() {\n  useEffect(() => {\n    const connection = createConnection(serverUrl, roomId);\n    connection.connect();\n    return () => connection.disconnect();\n  }, []);\n  return <h1>Welcome to the {roomId} room!</h1>;\n}\n\nexport default function App() {\n  const [show, setShow] = useState(false);\n  return (\n    <>\n      <button onClick={() => setShow(!show)}>\n        {show ? 'Close chat' : 'Open chat'}\n      </button>\n      {show && <hr />}\n      {show && <ChatRoom />}\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId, selectedServerUrl }) { // roomId is reactive  const settings = useContext(SettingsContext); // settings is reactive  const serverUrl = selectedServerUrl ?? settings.defaultServerUrl; // serverUrl is reactive  useEffect(() => {    const connection = createConnection(serverUrl, roomId); // Your Effect reads roomId and serverUrl    connection.connect();    return () => {      connection.disconnect();    };  }, [roomId, serverUrl]); // So it needs to re-synchronize when either of them changes!  // ...}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';\n\nfunction ChatRoom({ roomId }) { // roomId is reactive\n  const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // serverUrl is reactive\n\n  useEffect(() => {\n    const connection = createConnection(serverUrl, roomId);\n    connection.connect();\n    return () => connection.disconnect();\n  }, []); // <-- Something's wrong here!\n\n  return (\n    <>\n      <label>\n        Server URL:{' '}\n        <input\n          value={serverUrl}\n          onChange={e => setServerUrl(e.target.value)}\n        />\n      </label>\n      <h1>Welcome to the {roomId} room!</h1>\n    </>\n  );\n}\n\nexport default function App() {\n  const [roomId, setRoomId] = useState('general');\n  return (\n    <>\n      <label>\n        Choose the chat room:{' '}\n        <select\n          value={roomId}\n          onChange={e => setRoomId(e.target.value)}\n        >\n          <option value=\"general\">general</option>\n          <option value=\"travel\">travel</option>\n          <option value=\"music\">music</option>\n        </select>\n      </label>\n      <hr />\n      <ChatRoom roomId={roomId} />\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId }) { // roomId is reactive  const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // serverUrl is reactive  useEffect(() => {    const connection = createConnection(serverUrl, roomId);    connection.connect();    return () => {      connection.disconnect();    };  }, [serverUrl, roomId]); // ✅ All dependencies declared  // ...}\n```\n\nExample:\n```javascript\nconst serverUrl = 'https://localhost:1234'; // serverUrl is not reactiveconst roomId = 'general'; // roomId is not reactivefunction ChatRoom() {  useEffect(() => {    const connection = createConnection(serverUrl, roomId);    connection.connect();    return () => {      connection.disconnect();    };  }, []); // ✅ All dependencies declared  // ...}\n```\n\nExample:\n```javascript\nfunction ChatRoom() {  useEffect(() => {    const serverUrl = 'https://localhost:1234'; // serverUrl is not reactive    const roomId = 'general'; // roomId is not reactive    const connection = createConnection(serverUrl, roomId);    connection.connect();    return () => {      connection.disconnect();    };  }, []); // ✅ All dependencies declared  // ...}\n```\n\nExample:\n```javascript\nuseEffect(() => {  // ...  // 🔴 Avoid suppressing the linter like this:  // eslint-ignore-next-line react-hooks/exhaustive-deps}, []);\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';\n\nconst serverUrl = 'https://localhost:1234';\n\nfunction ChatRoom({ roomId }) {\n  const [message, setMessage] = useState('');\n\n  useEffect(() => {\n    const connection = createConnection(serverUrl, roomId);\n    connection.connect();\n    return () => connection.disconnect();\n  });\n\n  return (\n    <>\n      <h1>Welcome to the {roomId} room!</h1>\n      <input\n        value={message}\n        onChange={e => setMessage(e.target.value)}\n      />\n    </>\n  );\n}\n\nexport default function App() {\n  const [roomId, setRoomId] = useState('general');\n  return (\n    <>\n      <label>\n        Choose the chat room:{' '}\n        <select\n          value={roomId}\n          onChange={e => setRoomId(e.target.value)}\n        >\n          <option value=\"general\">general</option>\n          <option value=\"travel\">travel</option>\n          <option value=\"music\">music</option>\n        </select>\n      </label>\n      <hr />\n      <ChatRoom roomId={roomId} />\n    </>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.894Z","totalSectionsIncluded":0,"totalCodeBlocksIncluded":23,"totalLines":313,"estimatedTokens":2664}}30{"id":"doc-updating_arrays_in_state_react-780ad74e","source":"documentation","title":"Updating Arrays in State – React","url":"https://react.dev/learn/updating-arrays-in-state","text":"Example:\n```text\nimport { useState } from 'react';\n\nlet nextId = 0;\n\nexport default function List() {\n  const [name, setName] = useState('');\n  const [artists, setArtists] = useState([]);\n\n  return (\n    <>\n      <h1>Inspiring sculptors:</h1>\n      <input\n        value={name}\n        onChange={e => setName(e.target.value)}\n      />\n      <button onClick={() => {\n        artists.push({\n          id: nextId++,\n          name: name,\n        });\n      }}>Add</button>\n      <ul>\n        {artists.map(artist => (\n          <li key={artist.id}>{artist.name}</li>\n        ))}\n      </ul>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nsetArtists( // Replace the state  [ // with a new array    ...artists, // that contains all the old items    { id: nextId++, name: name } // and one new item at the end  ]);\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nlet nextId = 0;\n\nexport default function List() {\n  const [name, setName] = useState('');\n  const [artists, setArtists] = useState([]);\n\n  return (\n    <>\n      <h1>Inspiring sculptors:</h1>\n      <input\n        value={name}\n        onChange={e => setName(e.target.value)}\n      />\n      <button onClick={() => {\n        setArtists([\n          ...artists,\n          { id: nextId++, name: name }\n        ]);\n      }}>Add</button>\n      <ul>\n        {artists.map(artist => (\n          <li key={artist.id}>{artist.name}</li>\n        ))}\n      </ul>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nsetArtists([  { id: nextId++, name: name },  ...artists // Put old items at the end]);\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nlet initialArtists = [\n  { id: 0, name: 'Marta Colvin Andrade' },\n  { id: 1, name: 'Lamidi Olonade Fakeye'},\n  { id: 2, name: 'Louise Nevelson'},\n];\n\nexport default function List() {\n  const [artists, setArtists] = useState(\n    initialArtists\n  );\n\n  return (\n    <>\n      <h1>Inspiring sculptors:</h1>\n      <ul>\n        {artists.map(artist => (\n          <li key={artist.id}>\n            {artist.name}{' '}\n            <button onClick={() => {\n              setArtists(\n                artists.filter(a =>\n                  a.id !== artist.id\n                )\n              );\n            }}>\n              Delete\n            </button>\n          </li>\n        ))}\n      </ul>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nsetArtists(  artists.filter(a => a.id !== artist.id));\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nlet initialShapes = [\n  { id: 0, type: 'circle', x: 50, y: 100 },\n  { id: 1, type: 'square', x: 150, y: 100 },\n  { id: 2, type: 'circle', x: 250, y: 100 },\n];\n\nexport default function ShapeEditor() {\n  const [shapes, setShapes] = useState(\n    initialShapes\n  );\n\n  function handleClick() {\n    const nextShapes = shapes.map(shape => {\n      if (shape.type === 'square') {\n        // No change\n        return shape;\n      } else {\n        // Return a new circle 50px below\n        return {\n          ...shape,\n          y: shape.y + 50,\n        };\n      }\n    });\n    // Re-render with the new array\n    setShapes(nextShapes);\n  }\n\n  return (\n    <>\n      <button onClick={handleClick}>\n        Move circles down!\n      </button>\n      {shapes.map(shape => (\n        <div\n          key={shape.id}\n          style={{\n          background: 'purple',\n          position: 'absolute',\n          left: shape.x,\n          top: shape.y,\n          borderRadius:\n            shape.type === 'circle'\n              ? '50%' : '',\n          width: 20,\n          height: 20,\n        }} />\n      ))}\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nlet initialCounters = [\n  0, 0, 0\n];\n\nexport default function CounterList() {\n  const [counters, setCounters] = useState(\n    initialCounters\n  );\n\n  function handleIncrementClick(index) {\n    const nextCounters = counters.map((c, i) => {\n      if (i === index) {\n        // Increment the clicked counter\n        return c + 1;\n      } else {\n        // The rest haven't changed\n        return c;\n      }\n    });\n    setCounters(nextCounters);\n  }\n\n  return (\n    <ul>\n      {counters.map((counter, i) => (\n        <li key={i}>\n          {counter}\n          <button onClick={() => {\n            handleIncrementClick(i);\n          }}>+1</button>\n        </li>\n      ))}\n    </ul>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nlet nextId = 3;\nconst initialArtists = [\n  { id: 0, name: 'Marta Colvin Andrade' },\n  { id: 1, name: 'Lamidi Olonade Fakeye'},\n  { id: 2, name: 'Louise Nevelson'},\n];\n\nexport default function List() {\n  const [name, setName] = useState('');\n  const [artists, setArtists] = useState(\n    initialArtists\n  );\n\n  function handleClick() {\n    const insertAt = 1; // Could be any index\n    const nextArtists = [\n      // Items before the insertion point:\n      ...artists.slice(0, insertAt),\n      // New item:\n      { id: nextId++, name: name },\n      // Items after the insertion point:\n      ...artists.slice(insertAt)\n    ];\n    setArtists(nextArtists);\n    setName('');\n  }\n\n  return (\n    <>\n      <h1>Inspiring sculptors:</h1>\n      <input\n        value={name}\n        onChange={e => setName(e.target.value)}\n      />\n      <button onClick={handleClick}>\n        Insert\n      </button>\n      <ul>\n        {artists.map(artist => (\n          <li key={artist.id}>{artist.name}</li>\n        ))}\n      </ul>\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nconst initialList = [\n  { id: 0, title: 'Big Bellies' },\n  { id: 1, title: 'Lunar Landscape' },\n  { id: 2, title: 'Terracotta Army' },\n];\n\nexport default function List() {\n  const [list, setList] = useState(initialList);\n\n  function handleClick() {\n    const nextList = [...list];\n    nextList.reverse();\n    setList(nextList);\n  }\n\n  return (\n    <>\n      <button onClick={handleClick}>\n        Reverse\n      </button>\n      <ul>\n        {list.map(artwork => (\n          <li key={artwork.id}>{artwork.title}</li>\n        ))}\n      </ul>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nconst nextList = [...list];nextList[0].seen = true; // Problem: mutates list[0]setList(nextList);\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nlet nextId = 3;\nconst initialList = [\n  { id: 0, title: 'Big Bellies', seen: false },\n  { id: 1, title: 'Lunar Landscape', seen: false },\n  { id: 2, title: 'Terracotta Army', seen: true },\n];\n\nexport default function BucketList() {\n  const [myList, setMyList] = useState(initialList);\n  const [yourList, setYourList] = useState(\n    initialList\n  );\n\n  function handleToggleMyList(artworkId, nextSeen) {\n    const myNextList = [...myList];\n    const artwork = myNextList.find(\n      a => a.id === artworkId\n    );\n    artwork.seen = nextSeen;\n    setMyList(myNextList);\n  }\n\n  function handleToggleYourList(artworkId, nextSeen) {\n    const yourNextList = [...yourList];\n    const artwork = yourNextList.find(\n      a => a.id === artworkId\n    );\n    artwork.seen = nextSeen;\n    setYourList(yourNextList);\n  }\n\n  return (\n    <>\n      <h1>Art Bucket List</h1>\n      <h2>My list of art to see:</h2>\n      <ItemList\n        artworks={myList}\n        onToggle={handleToggleMyList} />\n      <h2>Your list of art to see:</h2>\n      <ItemList\n        artworks={yourList}\n        onToggle={handleToggleYourList} />\n    </>\n  );\n}\n\nfunction ItemList({ artworks, onToggle }) {\n  return (\n    <ul>\n      {artworks.map(artwork => (\n        <li key={artwork.id}>\n          <label>\n            <input\n              type=\"checkbox\"\n              checked={artwork.seen}\n              onChange={e => {\n                onToggle(\n                  artwork.id,\n                  e.target.checked\n                );\n              }}\n            />\n            {artwork.title}\n          </label>\n        </li>\n      ))}\n    </ul>\n  );\n}\n```\n\nExample:\n```javascript\nconst myNextList = [...myList];const artwork = myNextList.find(a => a.id === artworkId);artwork.seen = nextSeen; // Problem: mutates an existing itemsetMyList(myNextList);\n```\n\nExample:\n```javascript\nsetMyList(myList.map(artwork => {  if (artwork.id === artworkId) {    // Create a *new* object with changes    return { ...artwork, seen: nextSeen };  } else {    // No changes    return artwork;  }}));\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nlet nextId = 3;\nconst initialList = [\n  { id: 0, title: 'Big Bellies', seen: false },\n  { id: 1, title: 'Lunar Landscape', seen: false },\n  { id: 2, title: 'Terracotta Army', seen: true },\n];\n\nexport default function BucketList() {\n  const [myList, setMyList] = useState(initialList);\n  const [yourList, setYourList] = useState(\n    initialList\n  );\n\n  function handleToggleMyList(artworkId, nextSeen) {\n    setMyList(myList.map(artwork => {\n      if (artwork.id === artworkId) {\n        // Create a *new* object with changes\n        return { ...artwork, seen: nextSeen };\n      } else {\n        // No changes\n        return artwork;\n      }\n    }));\n  }\n\n  function handleToggleYourList(artworkId, nextSeen) {\n    setYourList(yourList.map(artwork => {\n      if (artwork.id === artworkId) {\n        // Create a *new* object with changes\n        return { ...artwork, seen: nextSeen };\n      } else {\n        // No changes\n        return artwork;\n      }\n    }));\n  }\n\n  return (\n    <>\n      <h1>Art Bucket List</h1>\n      <h2>My list of art to see:</h2>\n      <ItemList\n        artworks={myList}\n        onToggle={handleToggleMyList} />\n      <h2>Your list of art to see:</h2>\n      <ItemList\n        artworks={yourList}\n        onToggle={handleToggleYourList} />\n    </>\n  );\n}\n\nfunction ItemList({ artworks, onToggle }) {\n  return (\n    <ul>\n      {artworks.map(artwork => (\n        <li key={artwork.id}>\n          <label>\n            <input\n              type=\"checkbox\"\n              checked={artwork.seen}\n              onChange={e => {\n                onToggle(\n                  artwork.id,\n                  e.target.checked\n                );\n              }}\n            />\n            {artwork.title}\n          </label>\n        </li>\n      ))}\n    </ul>\n  );\n}\n```\n\nExample:\n```text\n{\n  \"dependencies\": {\n    \"immer\": \"1.7.3\",\n    \"react\": \"latest\",\n    \"react-dom\": \"latest\",\n    \"react-scripts\": \"latest\",\n    \"use-immer\": \"0.5.1\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"test\": \"react-scripts test --env=jsdom\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"devDependencies\": {}\n}\n```\n\nExample:\n```javascript\nupdateMyTodos(draft => {  const artwork = draft.find(a => a.id === artworkId);  artwork.seen = nextSeen;});\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nconst initialProducts = [{\n  id: 0,\n  name: 'Baklava',\n  count: 1,\n}, {\n  id: 1,\n  name: 'Cheese',\n  count: 5,\n}, {\n  id: 2,\n  name: 'Spaghetti',\n  count: 2,\n}];\n\nexport default function ShoppingCart() {\n  const [\n    products,\n    setProducts\n  ] = useState(initialProducts)\n\n  function handleIncreaseClick(productId) {\n\n  }\n\n  return (\n    <ul>\n      {products.map(product => (\n        <li key={product.id}>\n          {product.name}\n          {' '}\n          (<b>{product.count}</b>)\n          <button onClick={() => {\n            handleIncreaseClick(product.id);\n          }}>\n            +\n          </button>\n        </li>\n      ))}\n    </ul>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.895Z","totalSectionsIncluded":0,"totalCodeBlocksIncluded":18,"totalLines":547,"estimatedTokens":2814}}31{"id":"doc-preserving_and_resetting_state_react-f16e9dc5","source":"documentation","title":"Preserving and Resetting State – React","url":"https://react.dev/learn/preserving-and-resetting-state","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactManaging StateCopy pageCopyPreserving and Resetting StateState is isolated between components. React keeps track of which state belongs to which component based on their place in the UI tree. You can control when to preserve state and when to reset it between re-renders. You will learn When React chooses to preserve or reset the state How to force React to reset component’s state How keys and types affect whether the state is preserved State is tied to a position in the render tree React builds render trees for the component structure in your UI. When you give a component state, you might think the state “lives” inside the component. But the state is actually held inside React. React associates each piece of state it’s holding with the correct component by where that component sits in the render tree. Here, there is only one <Counter /> JSX tag, but it’s rendered at two different { useState } from 'react'; export default function App() { const counter = <Counter />; return ( <div> {counter} {counter} </div> ); } function Counter() { const [score, setScore] = useState(0); const [hover, setHover] = useState(false); let className = 'counter'; if (hover) { className += ' hover'; } return ( <div className={className} onPointerEnter={() => setHover(true)} onPointerLeave={() => setHover(false)} > <h1>{score}</h1> <button onClick={() => setScore(score + 1)}> Add one </button> </div> ); } Show more Here’s how these look as a tree These are two separate counters because each is rendered at its own position in the tree. You don’t usually have to think about these positions to use React, but it can be useful to understand how it works. In React, each component on the screen has fully isolated state. For example, if you render two Counter components side by side, each of them will get its own, independent, score and hover states. Try clicking both counters and notice they don’t affect each { useState } from 'react'; export default function App() { return ( <div> <Counter /> <Counter /> </div> ); } function Counter() { const [score, setScore] = useState(0); const [hover, setHover] = useState(false); let className = 'counter'; if (hover) { className += ' hover'; } return ( <div className={className} onPointerEnter={() => setHover(true)} onPointerLeave={() => setHover(false)} > <h1>{score}</h1> <button onClick={() => setScore(score + 1)}> Add one </button> </div> ); } Show more As you can see, when one counter is updated, only the state for that component is state React will keep the state around for as long as you render the same component at the same position in the tree. To see this, increment both counters, then remove the second component by unchecking “Render the second counter” checkbox, and then add it back by ticking it { useState } from 'react'; export default function App() { const [showB, setShowB] = useState(true); return ( <div> <Counter /> {showB && <Counter />} <label> <input type=\"checkbox\" checked={showB} onChange={e => { setShowB(e.target.checked) }} /> Render the second counter </label> </div> ); } function Counter() { const [score, setScore] = useState(0); const [hover, setHover] = useState(false); let className = 'counter'; if (hover) { className += ' hover'; } return ( <div className={className} onPointerEnter={() => setHover(true)} onPointerLeave={() => setHover(false)} > <h1>{score}</h1> <button onClick={() => setScore(score + 1)}> Add one </button> </div> ); } Show more Notice how the moment you stop rendering the second counter, its state disappears completely. That’s because when React removes a component, it destroys its state. Deleting a component When you tick “Render the second counter”, a second Counter and its state are initialized from scratch (score = 0) and added to the DOM. Adding a component React preserves a component’s state for as long as it’s being rendered at its position in the UI tree. If it gets removed, or a different component gets rendered at the same position, React discards its state. Same component at the same position preserves state In this example, there are two different <Counter /> { useState } from 'react'; export default function App() { const [isFancy, setIsFancy] = useState(false); return ( <div> {isFancy ? ( <Counter isFancy={true} /> ) : ( <Counter isFancy={false} /> )} <label> <input type=\"checkbox\" checked={isFancy} onChange={e => { setIsFancy(e.target.checked) }} /> Use fancy styling </label> </div> ); } function Counter({ isFancy }) { const [score, setScore] = useState(0); const [hover, setHover] = useState(false); let className = 'counter'; if (hover) { className += ' hover'; } if (isFancy) { className += ' fancy'; } return ( <div className={className} onPointerEnter={() => setHover(true)} onPointerLeave={() => setHover(false)} > <h1>{score}</h1> <button onClick={() => setScore(score + 1)}> Add one </button> </div> ); } Show more When you tick or clear the checkbox, the counter state does not get reset. Whether isFancy is true or false, you always have a <Counter /> as the first child of the div returned from the root App the App state does not reset the Counter because Counter stays in the same position It’s the same component at the same position, so from React’s perspective, it’s the same counter. PitfallRemember that it’s the position in the UI tree—not in the JSX markup—that matters to React! This component has two return clauses with different <Counter /> JSX tags inside and outside the { useState } from 'react'; export default function App() { const [isFancy, setIsFancy] = useState(false); if (isFancy) { return ( <div> <Counter isFancy={true} /> <label> <input type=\"checkbox\" checked={isFancy} onChange={e => { setIsFancy(e.target.checked) }} /> Use fancy styling </label> </div> ); } return ( <div> <Counter isFancy={false} /> <label> <input type=\"checkbox\" checked={isFancy} onChange={e => { setIsFancy(e.target.checked) }} /> Use fancy styling </label> </div> ); } function Counter({ isFancy }) { const [score, setScore] = useState(0); const [hover, setHover] = useState(false); let className = 'counter'; if (hover) { className += ' hover'; } if (isFancy) { className += ' fancy'; } return ( <div className={className} onPointerEnter={() => setHover(true)} onPointerLeave={() => setHover(false)} > <h1>{score}</h1> <button onClick={() => setScore(score + 1)}> Add one </button> </div> ); } Show moreYou might expect the state to reset when you tick checkbox, but it doesn’t! This is because both of these <Counter /> tags are rendered at the same position. React doesn’t know where you place the conditions in your function. All it “sees” is the tree you return.In both cases, the App component returns a <div> with <Counter /> as a first child. To React, these two counters have the same “address”: the first child of the first child of the root. This is how React matches them up between the previous and next renders, regardless of how you structure your logic. Different components at the same position reset state In this example, ticking the checkbox will replace <Counter> with a <p>: App.jsApp.jsReloadClearForkimport { useState } from 'react'; export default function App() { const [isPaused, setIsPaused] = useState(false); return ( <div> {isPaused ? ( <p>See you later!</p> ) : ( <Counter /> )} <label> <input type=\"checkbox\" checked={isPaused} onChange={e => { setIsPaused(e.target.checked) }} /> Take a break </label> </div> ); } function Counter() { const [score, setScore] = useState(0); const [hover, setHover] = useState(false); let className = 'counter'; if (hover) { className += ' hover'; } return ( <div className={className} onPointerEnter={() => setHover(true)} onPointerLeave={() => setHover(false)} > <h1>{score}</h1> <button onClick={() => setScore(score + 1)}> Add one </button> </div> ); } Show more Here, you switch between different component types at the same position. Initially, the first child of the <div> contained a Counter. But when you swapped in a p, React removed the Counter from the UI tree and destroyed its state. When Counter changes to p, the Counter is deleted and the p is added When switching back, the p is deleted and the Counter is added Also, when you render a different component in the same position, it resets the state of its entire subtree. To see how this works, increment the counter and then tick the { useState } from 'react'; export default function App() { const [isFancy, setIsFancy] = useState(false); return ( <div> {isFancy ? ( <div> <Counter isFancy={true} /> </div> ) : ( <section> <Counter isFancy={false} /> </section> )} <label> <input type=\"checkbox\" checked={isFancy} onChange={e => { setIsFancy(e.target.checked) }} /> Use fancy styling </label> </div> ); } function Counter({ isFancy }) { const [score, setScore] = useState(0); const [hover, setHover] = useState(false); let className = 'counter'; if (hover) { className += ' hover'; } if (isFancy) { className += ' fancy'; } return ( <div className={className} onPointerEnter={() => setHover(true)} onPointerLeave={() => setHover(false)} > <h1>{score}</h1> <button onClick={() => setScore(score + 1)}> Add one </button> </div> ); } Show more The counter state gets reset when you click the checkbox. Although you render a Counter, the first child of the div changes from a section to a div. When the child section was removed from the DOM, the whole tree below it (including the Counter and its state) was destroyed as well. When section changes to div, the section is deleted and the new div is added When switching back, the div is deleted and the new section is added As a rule of thumb, if you want to preserve the state between re-renders, the structure of your tree needs to “match up” from one render to another. If the structure is different, the state gets destroyed because React destroys state when it removes a component from the tree. PitfallThis is why you should not nest component function definitions.Here, the MyTextField component function is defined inside { useState } from 'react'; export default function MyComponent() { const [counter, setCounter] = useState(0); function MyTextField() { const [text, setText] = useState(''); return ( <input value={text} onChange={e => setText(e.target.value)} /> ); } return ( <> <MyTextField /> <button onClick={() => { setCounter(counter + 1) }}>Clicked {counter} times</button> </> ); } Show moreEvery time you click the button, the input state disappears! This is because a different MyTextField function is created for every render of MyComponent. You’re rendering a different component in the same position, so React resets all state below. This leads to bugs and performance problems. To avoid this problem, always declare component functions at the top level, and don’t nest their definitions. Resetting state at the same position By default, React preserves state of a component while it stays at the same position. Usually, this is exactly what you want, so it makes sense as the default behavior. But sometimes, you may want to reset a component’s state. Consider this app that lets two players keep track of their scores during each { useState } from 'react'; export default function Scoreboard() { const [isPlayerA, setIsPlayerA] = useState(true); return ( <div> {isPlayerA ? ( <Counter person=\"Taylor\" /> ) : ( <Counter person=\"Sarah\" /> )} <button onClick={() => { setIsPlayerA(!isPlayerA); }}> Next player! </button> </div> ); } function Counter({ person }) { const [score, setScore] = useState(0); const [hover, setHover] = useState(false); let className = 'counter'; if (hover) { className += ' hover'; } return ( <div className={className} onPointerEnter={() => setHover(true)} onPointerLeave={() => setHover(false)} > <h1>{person}'s score: {score}</h1> <button onClick={() => setScore(score + 1)}> Add one </button> </div> ); } Show more Currently, when you change the player, the score is preserved. The two Counters appear in the same position, so React sees them as the same Counter whose person prop has changed. But conceptually, in this app they should be two separate counters. They might appear in the same place in the UI, but one is a counter for Taylor, and another is a counter for Sarah. There are two ways to reset state when switching between components in different positions Give each component an explicit identity with key Option a component in different positions If you want these two Counters to be independent, you can render them in two different { useState } from 'react'; export default function Scoreboard() { const [isPlayerA, setIsPlayerA] = useState(true); return ( <div> {isPlayerA && <Counter person=\"Taylor\" /> } {!isPlayerA && <Counter person=\"Sarah\" /> } <button onClick={() => { setIsPlayerA(!isPlayerA); }}> Next player! </button> </div> ); } function Counter({ person }) { const [score, setScore] = useState(0); const [hover, setHover] = useState(false); let className = 'counter'; if (hover) { className += ' hover'; } return ( <div className={className} onPointerEnter={() => setHover(true)} onPointerLeave={() => setHover(false)} > <h1>{person}'s score: {score}</h1> <button onClick={() => setScore(score + 1)}> Add one </button> </div> ); } Show more Initially, isPlayerA is true. So the first position contains Counter state, and the second one is empty. When you click the “Next player” button the first position clears but the second one now contains a Counter. Initial stateClicking “next”Clicking “next” again Each Counter’s state gets destroyed each time it’s removed from the DOM. This is why they reset every time you click the button. This solution is convenient when you only have a few independent components rendered in the same place. In this example, you only have two, so it’s not a hassle to render both separately in the JSX. Option state with a key There is also another, more generic, way to reset a component’s state. You might have seen keys when rendering lists. Keys aren’t just for lists! You can use keys to make React distinguish between any components. By default, React uses order within the parent (“first counter”, “second counter”) to discern between components. But keys let you tell React that this is not just a first counter, or a second counter, but a specific counter—for example, Taylor’s counter. This way, React will know Taylor’s counter wherever it appears in the tree! In this example, the two <Counter />s don’t share state even though they appear in the same place in { useState } from 'react'; export default function Scoreboard() { const [isPlayerA, setIsPlayerA] = useState(true); return ( <div> {isPlayerA ? ( <Counter key=\"Taylor\" person=\"Taylor\" /> ) : ( <Counter key=\"Sarah\" person=\"Sarah\" /> )} <button onClick={() => { setIsPlayerA(!isPlayerA); }}> Next player! </button> </div> ); } function Counter({ person }) { const [score, setScore] = useState(0); const [hover, setHover] = useState(false); let className = 'counter'; if (hover) { className += ' hover'; } return ( <div className={className} onPointerEnter={() => setHover(true)} onPointerLeave={() => setHover(false)} > <h1>{person}'s score: {score}</h1> <button onClick={() => setScore(score + 1)}> Add one </button> </div> ); } Show more Switching between Taylor and Sarah does not preserve the state. This is because you gave them different keys: {isPlayerA ? ( <Counter key=\"Taylor\" person=\"Taylor\" />) : ( <Counter key=\"Sarah\" person=\"Sarah\" />)} Specifying a key tells React to use the key itself as part of the position, instead of their order within the parent. This is why, even though you render them in the same place in JSX, React sees them as two different counters, and so they will never share state. Every time a counter appears on the screen, its state is created. Every time it is removed, its state is destroyed. Toggling between them resets their state over and over. NoteRemember that keys are not globally unique. They only specify the position within the parent. Resetting a form with a key Resetting state with a key is particularly useful when dealing with forms. In this chat app, the <Chat> component contains the text input { useState } from 'react'; import Chat from './Chat.js'; import ContactList from './ContactList.js'; export default function Messenger() { const [to, setTo] = useState(contacts[0]); return ( <div> <ContactList contacts={contacts} selectedContact={to} onSelect={contact => setTo(contact)} /> <Chat contact={to} /> </div> ) } const contacts = [ { , name: 'Taylor', email: 'taylor@mail.com' }, { , name: 'Alice', email: 'alice@mail.com' }, { , name: 'Bob', email: 'bob@mail.com' } ]; Show more Try entering something into the input, and then press “Alice” or “Bob” to choose a different recipient. You will notice that the input state is preserved because the <Chat> is rendered at the same position in the tree. In many apps, this may be the desired behavior, but not in a chat app! You don’t want to let the user send a message they already typed to a wrong person due to an accidental click. To fix it, add a key: <Chat key={to.id} contact={to} /> This ensures that when you select a different recipient, the Chat component will be recreated from scratch, including any state in the tree below it. React will also re-create the DOM elements instead of reusing them. Now switching the recipient always clears the text { useState } from 'react'; import Chat from './Chat.js'; import ContactList from './ContactList.js'; export default function Messenger() { const [to, setTo] = useState(contacts[0]); return ( <div> <ContactList contacts={contacts} selectedContact={to} onSelect={contact => setTo(contact)} /> <Chat key={to.id} contact={to} /> </div> ) } const contacts = [ { , name: 'Taylor', email: 'taylor@mail.com' }, { , name: 'Alice', email: 'alice@mail.com' }, { , name: 'Bob', email: 'bob@mail.com' } ]; Show more Deep DivePreserving state for removed components Show DetailsIn a real chat app, you’d probably want to recover the input state when the user selects the previous recipient again. There are a few ways to keep the state “alive” for a component that’s no longer could render all chats instead of just the current one, but hide all the others with CSS. The chats would not get removed from the tree, so their local state would be preserved. This solution works great for simple UIs. But it can get very slow if the hidden trees are large and contain a lot of DOM nodes. You could lift the state up and hold the pending message for each recipient in the parent component. This way, when the child components get removed, it doesn’t matter, because it’s the parent that keeps the important information. This is the most common solution. You might also use a different source in addition to React state. For example, you probably want a message draft to persist even if the user accidentally closes the page. To implement this, you could have the Chat component initialize its state by reading from the localStorage, and save the drafts there too. No matter which strategy you pick, a chat with Alice is conceptually distinct from a chat with Bob, so it makes sense to give a key to the <Chat> tree based on the current recipient. Recap React keeps state for as long as the same component is rendered at the same position. State is not kept in JSX tags. It’s associated with the tree position in which you put that JSX. You can force a subtree to reset its state by giving it a different key. Don’t nest component definitions, or you’ll reset state by accident. Try out some challenges1. Fix disappearing input text 2. Swap two form fields 3. Reset a detail form 4. Clear an image while it’s loading 5. Fix misplaced state in the list Challenge 1 of disappearing input text This example shows a message when you press the button. However, pressing the button also accidentally resets the input. Why does this happen? Fix it so that pressing the button does not reset the input text.App.jsApp.jsReloadClearForkimport { useState } from 'react'; export default function App() { const [showHint, setShowHint] = useState(false); if (showHint) { return ( <div> <p><i>Hint: Your favorite city?</i></p> <Form /> <button onClick={() => { setShowHint(false); }}>Hide hint</button> </div> ); } return ( <div> <Form /> <button onClick={() => { setShowHint(true); }}>Show hint</button> </div> ); } function Form() { const [text, setText] = useState(''); return ( <textarea value={text} onChange={e => setText(e.target.value)} /> ); } Show more Show solutionNext ChallengePreviousSharing State Between ComponentsNextExtracting State Logic into a ReducerCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewState is tied to a position in the render tree Same component at the same position preserves state Different components at the same position reset state Resetting state at the same position Option a component in different positions Option state with a key Resetting a form with a key RecapChallenges\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function App() {\n  const counter = <Counter />;\n  return (\n    <div>\n      {counter}\n      {counter}\n    </div>\n  );\n}\n\nfunction Counter() {\n  const [score, setScore] = useState(0);\n  const [hover, setHover] = useState(false);\n\n  let className = 'counter';\n  if (hover) {\n    className += ' hover';\n  }\n\n  return (\n    <div\n      className={className}\n      onPointerEnter={() => setHover(true)}\n      onPointerLeave={() => setHover(false)}\n    >\n      <h1>{score}</h1>\n      <button onClick={() => setScore(score + 1)}>\n        Add one\n      </button>\n    </div>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function App() {\n  return (\n    <div>\n      <Counter />\n      <Counter />\n    </div>\n  );\n}\n\nfunction Counter() {\n  const [score, setScore] = useState(0);\n  const [hover, setHover] = useState(false);\n\n  let className = 'counter';\n  if (hover) {\n    className += ' hover';\n  }\n\n  return (\n    <div\n      className={className}\n      onPointerEnter={() => setHover(true)}\n      onPointerLeave={() => setHover(false)}\n    >\n      <h1>{score}</h1>\n      <button onClick={() => setScore(score + 1)}>\n        Add one\n      </button>\n    </div>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function App() {\n  const [showB, setShowB] = useState(true);\n  return (\n    <div>\n      <Counter />\n      {showB && <Counter />}\n      <label>\n        <input\n          type=\"checkbox\"\n          checked={showB}\n          onChange={e => {\n            setShowB(e.target.checked)\n          }}\n        />\n        Render the second counter\n      </label>\n    </div>\n  );\n}\n\nfunction Counter() {\n  const [score, setScore] = useState(0);\n  const [hover, setHover] = useState(false);\n\n  let className = 'counter';\n  if (hover) {\n    className += ' hover';\n  }\n\n  return (\n    <div\n      className={className}\n      onPointerEnter={() => setHover(true)}\n      onPointerLeave={() => setHover(false)}\n    >\n      <h1>{score}</h1>\n      <button onClick={() => setScore(score + 1)}>\n        Add one\n      </button>\n    </div>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function App() {\n  const [isFancy, setIsFancy] = useState(false);\n  return (\n    <div>\n      {isFancy ? (\n        <Counter isFancy={true} />\n      ) : (\n        <Counter isFancy={false} />\n      )}\n      <label>\n        <input\n          type=\"checkbox\"\n          checked={isFancy}\n          onChange={e => {\n            setIsFancy(e.target.checked)\n          }}\n        />\n        Use fancy styling\n      </label>\n    </div>\n  );\n}\n\nfunction Counter({ isFancy }) {\n  const [score, setScore] = useState(0);\n  const [hover, setHover] = useState(false);\n\n  let className = 'counter';\n  if (hover) {\n    className += ' hover';\n  }\n  if (isFancy) {\n    className += ' fancy';\n  }\n\n  return (\n    <div\n      className={className}\n      onPointerEnter={() => setHover(true)}\n      onPointerLeave={() => setHover(false)}\n    >\n      <h1>{score}</h1>\n      <button onClick={() => setScore(score + 1)}>\n        Add one\n      </button>\n    </div>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function App() {\n  const [isFancy, setIsFancy] = useState(false);\n  if (isFancy) {\n    return (\n      <div>\n        <Counter isFancy={true} />\n        <label>\n          <input\n            type=\"checkbox\"\n            checked={isFancy}\n            onChange={e => {\n              setIsFancy(e.target.checked)\n            }}\n          />\n          Use fancy styling\n        </label>\n      </div>\n    );\n  }\n  return (\n    <div>\n      <Counter isFancy={false} />\n      <label>\n        <input\n          type=\"checkbox\"\n          checked={isFancy}\n          onChange={e => {\n            setIsFancy(e.target.checked)\n          }}\n        />\n        Use fancy styling\n      </label>\n    </div>\n  );\n}\n\nfunction Counter({ isFancy }) {\n  const [score, setScore] = useState(0);\n  const [hover, setHover] = useState(false);\n\n  let className = 'counter';\n  if (hover) {\n    className += ' hover';\n  }\n  if (isFancy) {\n    className += ' fancy';\n  }\n\n  return (\n    <div\n      className={className}\n      onPointerEnter={() => setHover(true)}\n      onPointerLeave={() => setHover(false)}\n    >\n      <h1>{score}</h1>\n      <button onClick={() => setScore(score + 1)}>\n        Add one\n      </button>\n    </div>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function App() {\n  const [isPaused, setIsPaused] = useState(false);\n  return (\n    <div>\n      {isPaused ? (\n        <p>See you later!</p>\n      ) : (\n        <Counter />\n      )}\n      <label>\n        <input\n          type=\"checkbox\"\n          checked={isPaused}\n          onChange={e => {\n            setIsPaused(e.target.checked)\n          }}\n        />\n        Take a break\n      </label>\n    </div>\n  );\n}\n\nfunction Counter() {\n  const [score, setScore] = useState(0);\n  const [hover, setHover] = useState(false);\n\n  let className = 'counter';\n  if (hover) {\n    className += ' hover';\n  }\n\n  return (\n    <div\n      className={className}\n      onPointerEnter={() => setHover(true)}\n      onPointerLeave={() => setHover(false)}\n    >\n      <h1>{score}</h1>\n      <button onClick={() => setScore(score + 1)}>\n        Add one\n      </button>\n    </div>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function App() {\n  const [isFancy, setIsFancy] = useState(false);\n  return (\n    <div>\n      {isFancy ? (\n        <div>\n          <Counter isFancy={true} />\n        </div>\n      ) : (\n        <section>\n          <Counter isFancy={false} />\n        </section>\n      )}\n      <label>\n        <input\n          type=\"checkbox\"\n          checked={isFancy}\n          onChange={e => {\n            setIsFancy(e.target.checked)\n          }}\n        />\n        Use fancy styling\n      </label>\n    </div>\n  );\n}\n\nfunction Counter({ isFancy }) {\n  const [score, setScore] = useState(0);\n  const [hover, setHover] = useState(false);\n\n  let className = 'counter';\n  if (hover) {\n    className += ' hover';\n  }\n  if (isFancy) {\n    className += ' fancy';\n  }\n\n  return (\n    <div\n      className={className}\n      onPointerEnter={() => setHover(true)}\n      onPointerLeave={() => setHover(false)}\n    >\n      <h1>{score}</h1>\n      <button onClick={() => setScore(score + 1)}>\n        Add one\n      </button>\n    </div>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function MyComponent() {\n  const [counter, setCounter] = useState(0);\n\n  function MyTextField() {\n    const [text, setText] = useState('');\n\n    return (\n      <input\n        value={text}\n        onChange={e => setText(e.target.value)}\n      />\n    );\n  }\n\n  return (\n    <>\n      <MyTextField />\n      <button onClick={() => {\n        setCounter(counter + 1)\n      }}>Clicked {counter} times</button>\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Scoreboard() {\n  const [isPlayerA, setIsPlayerA] = useState(true);\n  return (\n    <div>\n      {isPlayerA ? (\n        <Counter person=\"Taylor\" />\n      ) : (\n        <Counter person=\"Sarah\" />\n      )}\n      <button onClick={() => {\n        setIsPlayerA(!isPlayerA);\n      }}>\n        Next player!\n      </button>\n    </div>\n  );\n}\n\nfunction Counter({ person }) {\n  const [score, setScore] = useState(0);\n  const [hover, setHover] = useState(false);\n\n  let className = 'counter';\n  if (hover) {\n    className += ' hover';\n  }\n\n  return (\n    <div\n      className={className}\n      onPointerEnter={() => setHover(true)}\n      onPointerLeave={() => setHover(false)}\n    >\n      <h1>{person}'s score: {score}</h1>\n      <button onClick={() => setScore(score + 1)}>\n        Add one\n      </button>\n    </div>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Scoreboard() {\n  const [isPlayerA, setIsPlayerA] = useState(true);\n  return (\n    <div>\n      {isPlayerA &&\n        <Counter person=\"Taylor\" />\n      }\n      {!isPlayerA &&\n        <Counter person=\"Sarah\" />\n      }\n      <button onClick={() => {\n        setIsPlayerA(!isPlayerA);\n      }}>\n        Next player!\n      </button>\n    </div>\n  );\n}\n\nfunction Counter({ person }) {\n  const [score, setScore] = useState(0);\n  const [hover, setHover] = useState(false);\n\n  let className = 'counter';\n  if (hover) {\n    className += ' hover';\n  }\n\n  return (\n    <div\n      className={className}\n      onPointerEnter={() => setHover(true)}\n      onPointerLeave={() => setHover(false)}\n    >\n      <h1>{person}'s score: {score}</h1>\n      <button onClick={() => setScore(score + 1)}>\n        Add one\n      </button>\n    </div>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Scoreboard() {\n  const [isPlayerA, setIsPlayerA] = useState(true);\n  return (\n    <div>\n      {isPlayerA ? (\n        <Counter key=\"Taylor\" person=\"Taylor\" />\n      ) : (\n        <Counter key=\"Sarah\" person=\"Sarah\" />\n      )}\n      <button onClick={() => {\n        setIsPlayerA(!isPlayerA);\n      }}>\n        Next player!\n      </button>\n    </div>\n  );\n}\n\nfunction Counter({ person }) {\n  const [score, setScore] = useState(0);\n  const [hover, setHover] = useState(false);\n\n  let className = 'counter';\n  if (hover) {\n    className += ' hover';\n  }\n\n  return (\n    <div\n      className={className}\n      onPointerEnter={() => setHover(true)}\n      onPointerLeave={() => setHover(false)}\n    >\n      <h1>{person}'s score: {score}</h1>\n      <button onClick={() => setScore(score + 1)}>\n        Add one\n      </button>\n    </div>\n  );\n}\n```\n\nExample:\n```javascript\n{isPlayerA ? (  <Counter key=\"Taylor\" person=\"Taylor\" />) : (  <Counter key=\"Sarah\" person=\"Sarah\" />)}\n```\n\nExample:\n```text\nimport { useState } from 'react';\nimport Chat from './Chat.js';\nimport ContactList from './ContactList.js';\n\nexport default function Messenger() {\n  const [to, setTo] = useState(contacts[0]);\n  return (\n    <div>\n      <ContactList\n        contacts={contacts}\n        selectedContact={to}\n        onSelect={contact => setTo(contact)}\n      />\n      <Chat contact={to} />\n    </div>\n  )\n}\n\nconst contacts = [\n  { id: 0, name: 'Taylor', email: 'taylor@mail.com' },\n  { id: 1, name: 'Alice', email: 'alice@mail.com' },\n  { id: 2, name: 'Bob', email: 'bob@mail.com' }\n];\n```\n\nExample:\n```javascript\n<Chat key={to.id} contact={to} />\n```\n\nExample:\n```text\nimport { useState } from 'react';\nimport Chat from './Chat.js';\nimport ContactList from './ContactList.js';\n\nexport default function Messenger() {\n  const [to, setTo] = useState(contacts[0]);\n  return (\n    <div>\n      <ContactList\n        contacts={contacts}\n        selectedContact={to}\n        onSelect={contact => setTo(contact)}\n      />\n      <Chat key={to.id} contact={to} />\n    </div>\n  )\n}\n\nconst contacts = [\n  { id: 0, name: 'Taylor', email: 'taylor@mail.com' },\n  { id: 1, name: 'Alice', email: 'alice@mail.com' },\n  { id: 2, name: 'Bob', email: 'bob@mail.com' }\n];\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function App() {\n  const [showHint, setShowHint] = useState(false);\n  if (showHint) {\n    return (\n      <div>\n        <p><i>Hint: Your favorite city?</i></p>\n        <Form />\n        <button onClick={() => {\n          setShowHint(false);\n        }}>Hide hint</button>\n      </div>\n    );\n  }\n  return (\n    <div>\n      <Form />\n      <button onClick={() => {\n        setShowHint(true);\n      }}>Show hint</button>\n    </div>\n  );\n}\n\nfunction Form() {\n  const [text, setText] = useState('');\n  return (\n    <textarea\n      value={text}\n      onChange={e => setText(e.target.value)}\n    />\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.898Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":16,"totalLines":626,"estimatedTokens":8544}}32{"id":"doc-synchronizing_with_effects_react-a781b5db","source":"documentation","title":"Synchronizing with Effects – React","url":"https://react.dev/learn/synchronizing-with-effects","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactEscape HatchesCopy pageCopySynchronizing with EffectsSome components need to synchronize with external systems. For example, you might want to control a non-React component based on the React state, set up a server connection, or send an analytics log when a component appears on the screen. Effects let you run some code after rendering so that you can synchronize your component with some system outside of React. You will learn What Effects are How Effects are different from events How to declare an Effect in your component How to skip re-running an Effect unnecessarily Why Effects run twice in development and how to fix them What are Effects and how are they different from events? Before getting to Effects, you need to be familiar with two types of logic inside React code (introduced in Describing the UI) lives at the top level of your component. This is where you take the props and state, transform them, and return the JSX you want to see on the screen. Rendering code must be pure. Like a math formula, it should only calculate the result, but not do anything else. Event handlers (introduced in Adding Interactivity) are nested functions inside your components that do things rather than just calculate them. An event handler might update an input field, submit an HTTP POST request to buy a product, or navigate the user to another screen. Event handlers contain “side effects” (they change the program’s state) caused by a specific user action (for example, a button click or typing). Sometimes this isn’t enough. Consider a ChatRoom component that must connect to the chat server whenever it’s visible on the screen. Connecting to a server is not a pure calculation (it’s a side effect) so it can’t happen during rendering. However, there is no single particular event like a click that causes ChatRoom to be displayed. Effects let you specify side effects that are caused by rendering itself, rather than by a particular event. Sending a message in the chat is an event because it is directly caused by the user clicking a specific button. However, setting up a server connection is an Effect because it should happen no matter which interaction caused the component to appear. Effects run at the end of a commit after the screen updates. This is a good time to synchronize the React components with some external system (like network or a third-party library). NoteHere and later in this text, capitalized “Effect” refers to the React-specific definition above, i.e. a side effect caused by rendering. To refer to the broader programming concept, we’ll say “side effect”. You might not need an Effect Don’t rush to add Effects to your components. Keep in mind that Effects are typically used to “step out” of your React code and synchronize with some external system. This includes browser APIs, third-party widgets, network, and so on. If your Effect only adjusts some state based on other state, you might not need an Effect. How to write an Effect To write an Effect, follow these three an Effect. By default, your Effect will run after every commit. Specify the Effect dependencies. Most Effects should only re-run when needed rather than after every render. For example, a fade-in animation should only trigger when a component appears. Connecting and disconnecting to a chat room should only happen when the component appears and disappears, or when the chat room changes. You will learn how to control this by specifying dependencies. Add cleanup if needed. Some Effects need to specify how to stop, undo, or clean up whatever they were doing. For example, “connect” needs “disconnect”, “subscribe” needs “unsubscribe”, and “fetch” needs either “cancel” or “ignore”. You will learn how to do this by returning a cleanup function. Let’s look at each of these steps in detail. Step an Effect To declare an Effect in your component, import the useEffect Hook from { useEffect } from 'react'; Then, call it at the top level of your component and put some code inside your MyComponent() { useEffect(() => { // Code here will run after *every* render }); return <div />;} Every time your component renders, React will update the screen and then run the code inside useEffect. In other words, useEffect “delays” a piece of code from running until that render is reflected on the screen. Let’s see how you can use an Effect to synchronize with an external system. Consider a <VideoPlayer> React component. It would be nice to control whether it’s playing or paused by passing an isPlaying prop to it: <VideoPlayer isPlaying={isPlaying} />; Your custom VideoPlayer component renders the built-in browser <video> VideoPlayer({ src, isPlaying }) { // something with isPlaying return <video src={src} />;} However, the browser <video> tag does not have an isPlaying prop. The only way to control it is to manually call the play() and pause() methods on the DOM element. You need to synchronize the value of isPlaying prop, which tells whether the video should currently be playing, with calls like play() and pause(). We’ll need to first get a ref to the <video> DOM node. You might be tempted to try to call play() or pause() during rendering, but that isn’t { useState, useRef, useEffect } from 'react'; function VideoPlayer({ src, isPlaying }) { const ref = useRef(null); if (isPlaying) { ref.current.play(); // Calling these while rendering isn't allowed. } else { ref.current.pause(); // Also, this crashes. } return <video ref={ref} src={src} loop playsInline />; } export default function App() { const [isPlaying, setIsPlaying] = useState(false); return ( <> <button onClick={() => setIsPlaying(!isPlaying)}> {isPlaying ? 'Pause' : 'Play'} </button> <VideoPlayer isPlaying={isPlaying} src=\"https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4\" /> </> ); } Show more The reason this code isn’t correct is that it tries to do something with the DOM node during rendering. In React, rendering should be a pure calculation of JSX and should not contain side effects like modifying the DOM. Moreover, when VideoPlayer is called for the first time, its DOM does not exist yet! There isn’t a DOM node yet to call play() or pause() on, because React doesn’t know what DOM to create until you return the JSX. The solution here is to wrap the side effect with useEffect to move it out of the rendering { useEffect, useRef } from 'react';function VideoPlayer({ src, isPlaying }) { const ref = useRef(null); useEffect(() => { if (isPlaying) { ref.current.play(); } else { ref.current.pause(); } }); return <video ref={ref} src={src} loop playsInline />;} By wrapping the DOM update in an Effect, you let React update the screen first. Then your Effect runs. When your VideoPlayer component renders (either the first time or if it re-renders), a few things will happen. First, React will update the screen, ensuring the <video> tag is in the DOM with the right props. Then React will run your Effect. Finally, your Effect will call play() or pause() depending on the value of isPlaying. Press Play/Pause multiple times and see how the video player stays synchronized to the isPlaying { useState, useRef, useEffect } from 'react'; function VideoPlayer({ src, isPlaying }) { const ref = useRef(null); useEffect(() => { if (isPlaying) { ref.current.play(); } else { ref.current.pause(); } }); return <video ref={ref} src={src} loop playsInline />; } export default function App() { const [isPlaying, setIsPlaying] = useState(false); return ( <> <button onClick={() => setIsPlaying(!isPlaying)}> {isPlaying ? 'Pause' : 'Play'} </button> <VideoPlayer isPlaying={isPlaying} src=\"https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4\" /> </> ); } Show more In this example, the “external system” you synchronized to React state was the browser media API. You can use a similar approach to wrap legacy non-React code (like jQuery plugins) into declarative React components. Note that controlling a video player is much more complex in practice. Calling play() may fail, the user might play or pause using the built-in browser controls, and so on. This example is very simplified and incomplete. PitfallBy default, Effects run after every render. This is why code like this will produce an infinite [count, setCount] = useState(0);useEffect(() => { setCount(count + 1);});Effects run as a result of rendering. Setting state triggers rendering. Setting state immediately in an Effect is like plugging a power outlet into itself. The Effect runs, it sets the state, which causes a re-render, which causes the Effect to run, it sets the state again, this causes another re-render, and so on.Effects should usually synchronize your components with an external system. If there’s no external system and you only want to adjust some state based on other state, you might not need an Effect. Step the Effect dependencies By default, Effects run after every render. Often, this is not what you , it’s slow. Synchronizing with an external system is not always instant, so you might want to skip doing it unless it’s necessary. For example, you don’t want to reconnect to the chat server on every keystroke. Sometimes, it’s wrong. For example, you don’t want to trigger a component fade-in animation on every keystroke. The animation should only play once when the component appears for the first time. To demonstrate the issue, here is the previous example with a few console.log calls and a text input that updates the parent component’s state. Notice how typing causes the Effect to { useState, useRef, useEffect } from 'react'; function VideoPlayer({ src, isPlaying }) { const ref = useRef(null); useEffect(() => { if (isPlaying) { console.log('Calling video.play()'); ref.current.play(); } else { console.log('Calling video.pause()'); ref.current.pause(); } }); return <video ref={ref} src={src} loop playsInline />; } export default function App() { const [isPlaying, setIsPlaying] = useState(false); const [text, setText] = useState(''); return ( <> <input value={text} onChange={e => setText(e.target.value)} /> <button onClick={() => setIsPlaying(!isPlaying)}> {isPlaying ? 'Pause' : 'Play'} </button> <VideoPlayer isPlaying={isPlaying} src=\"https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4\" /> </> ); } Show more You can tell React to skip unnecessarily re-running the Effect by specifying an array of dependencies as the second argument to the useEffect call. Start by adding an empty [] array to the above example on line (() => { // ... }, []); You should see an error saying React Hook useEffect has a missing dependency: 'isPlaying': App.jsApp.jsReloadClearForkimport { useState, useRef, useEffect } from 'react'; function VideoPlayer({ src, isPlaying }) { const ref = useRef(null); useEffect(() => { if (isPlaying) { console.log('Calling video.play()'); ref.current.play(); } else { console.log('Calling video.pause()'); ref.current.pause(); } }, []); // This causes an error return <video ref={ref} src={src} loop playsInline />; } export default function App() { const [isPlaying, setIsPlaying] = useState(false); const [text, setText] = useState(''); return ( <> <input value={text} onChange={e => setText(e.target.value)} /> <button onClick={() => setIsPlaying(!isPlaying)}> {isPlaying ? 'Pause' : 'Play'} </button> <VideoPlayer isPlaying={isPlaying} src=\"https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4\" /> </> ); } Show more The problem is that the code inside of your Effect depends on the isPlaying prop to decide what to do, but this dependency was not explicitly declared. To fix this issue, add isPlaying to the dependency (() => { if (isPlaying) { // It's used here... // ... } else { // ... } }, [isPlaying]); // ...so it must be declared here! Now all dependencies are declared, so there is no error. Specifying [isPlaying] as the dependency array tells React that it should skip re-running your Effect if isPlaying is the same as it was during the previous render. With this change, typing into the input doesn’t cause the Effect to re-run, but pressing Play/Pause { useState, useRef, useEffect } from 'react'; function VideoPlayer({ src, isPlaying }) { const ref = useRef(null); useEffect(() => { if (isPlaying) { console.log('Calling video.play()'); ref.current.play(); } else { console.log('Calling video.pause()'); ref.current.pause(); } }, [isPlaying]); return <video ref={ref} src={src} loop playsInline />; } export default function App() { const [isPlaying, setIsPlaying] = useState(false); const [text, setText] = useState(''); return ( <> <input value={text} onChange={e => setText(e.target.value)} /> <button onClick={() => setIsPlaying(!isPlaying)}> {isPlaying ? 'Pause' : 'Play'} </button> <VideoPlayer isPlaying={isPlaying} src=\"https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4\" /> </> ); } Show more The dependency array can contain multiple dependencies. React will only skip re-running the Effect if all of the dependencies you specify have exactly the same values as they had during the previous render. React compares the dependency values using the Object.is comparison. See the useEffect reference for details. Notice that you can’t “choose” your dependencies. You will get a lint error if the dependencies you specified don’t match what React expects based on the code inside your Effect. This helps catch many bugs in your code. If you don’t want some code to re-run, edit the Effect code itself to not “need” that dependency. PitfallThe behaviors without the dependency array and with an empty [] dependency array are (() => { // This runs after every render});useEffect(() => { // This runs only on mount (when the component appears)}, []);useEffect(() => { // This runs on mount *and also* if either a or b have changed since the last render}, [a, b]);We’ll take a close look at what “mount” means in the next step. Deep DiveWhy was the ref omitted from the dependency array? Show DetailsThis Effect uses both ref and isPlaying, but only isPlaying is declared as a VideoPlayer({ src, isPlaying }) { const ref = useRef(null); useEffect(() => { if (isPlaying) { ref.current.play(); } else { ref.current.pause(); } }, [isPlaying]);This is because the ref object has a stable guarantees you’ll always get the same object from the same useRef call on every render. It never changes, so it will never by itself cause the Effect to re-run. Therefore, it does not matter whether you include it or not. Including it is fine VideoPlayer({ src, isPlaying }) { const ref = useRef(null); useEffect(() => { if (isPlaying) { ref.current.play(); } else { ref.current.pause(); } }, [isPlaying, ref]);The set functions returned by useState also have stable identity, so you will often see them omitted from the dependencies too. If the linter lets you omit a dependency without errors, it is safe to do.Omitting always-stable dependencies only works when the linter can “see” that the object is stable. For example, if ref was passed from a parent component, you would have to specify it in the dependency array. However, this is good because you can’t know whether the parent component always passes the same ref, or passes one of several refs conditionally. So your Effect would depend on which ref is passed. Step cleanup if needed Consider a different example. You’re writing a ChatRoom component that needs to connect to the chat server when it appears. You are given a createConnection() API that returns an object with connect() and disconnect() methods. How do you keep the component connected while it is displayed to the user? Start by writing the Effect (() => { const connection = createConnection(); connection.connect();}); It would be slow to connect to the chat after every re-render, so you add the dependency (() => { const connection = createConnection(); connection.connect();}, []); The code inside the Effect does not use any props or state, so your dependency array is [] (empty). This tells React to only run this code when the component “mounts”, i.e. appears on the screen for the first time. Let’s try running this { useEffect } from 'react'; import { createConnection } from './chat.js'; export default function ChatRoom() { useEffect(() => { const connection = createConnection(); connection.connect(); }, []); return <h1>Welcome to the chat!</h1>; } This Effect only runs on mount, so you might expect \"✅ Connecting...\" to be printed once in the console. However, if you check the console, \"✅ Connecting...\" gets printed twice. Why does it happen? Imagine the ChatRoom component is a part of a larger app with many different screens. The user starts their journey on the ChatRoom page. The component mounts and calls connection.connect(). Then imagine the user navigates to another screen—for example, to the Settings page. The ChatRoom component unmounts. Finally, the user clicks Back and ChatRoom mounts again. This would set up a second connection—but the first connection was never destroyed! As the user navigates across the app, the connections would keep piling up. Bugs like this are easy to miss without extensive manual testing. To help you spot them quickly, in development React remounts every component once immediately after its initial mount. Seeing the \"✅ Connecting...\" log twice helps you notice the real code doesn’t close the connection when the component unmounts. To fix the issue, return a cleanup function from your (() => { const connection = createConnection(); connection.connect(); return () => { connection.disconnect(); }; }, []); React will call your cleanup function each time before the Effect runs again, and one final time when the component unmounts (gets removed). Let’s see what happens when the cleanup function is { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; export default function ChatRoom() { useEffect(() => { const connection = createConnection(); connection.connect(); return () => connection.disconnect(); }, []); return <h1>Welcome to the chat!</h1>; } Now you get three console logs in development: \"✅ Connecting...\" \"❌ Disconnected.\" \"✅ Connecting...\" This is the correct behavior in development. By remounting your component, React verifies that navigating away and back would not break your code. Disconnecting and then connecting again is exactly what should happen! When you implement the cleanup well, there should be no user-visible difference between running the Effect once vs running it, cleaning it up, and running it again. There’s an extra connect/disconnect call pair because React is probing your code for bugs in development. This is normal—don’t try to make it go away! In production, you would only see \"✅ Connecting...\" printed once. Remounting components only happens in development to help you find Effects that need cleanup. You can turn off Strict Mode to opt out of the development behavior, but we recommend keeping it on. This lets you find many bugs like the one above. How to handle the Effect firing twice in development? React intentionally remounts your components in development to find bugs like in the last example. The right question isn’t “how to run an Effect once”, but “how to fix my Effect so that it works after remounting”. Usually, the answer is to implement the cleanup function. The cleanup function should stop or undo whatever the Effect was doing. The rule of thumb is that the user shouldn’t be able to distinguish between the Effect running once (as in production) and a setup → cleanup → setup sequence (as you’d see in development). Most of the Effects you’ll write will fit into one of the common patterns below. PitfallDon’t use refs to prevent Effects from firing A common pitfall for preventing Effects firing twice in development is to use a ref to prevent the Effect from running more than once. For example, you could “fix” the above bug with a connectionRef = useRef(null); useEffect(() => { // 🚩 This wont fix the bug!!! if (!connectionRef.current) { connectionRef.current = createConnection(); connectionRef.current.connect(); } }, []);This makes it so you only see \"✅ Connecting...\" once in development, but it doesn’t fix the bug.When the user navigates away, the connection still isn’t closed and when they navigate back, a new connection is created. As the user navigates across the app, the connections would keep piling up, the same as it would before the “fix”.To fix the bug, it is not enough to just make the Effect run once. The effect needs to work after re-mounting, which means the connection needs to be cleaned up like in the solution above.See the examples below for how to handle common patterns. Controlling non-React widgets Sometimes you need to add UI widgets that aren’t written in React. For example, let’s say you’re adding a map component to your page. It has a setZoomLevel() method, and you’d like to keep the zoom level in sync with a zoomLevel state variable in your React code. Your Effect would look similar to (() => { const map = mapRef.current; map.setZoomLevel(zoomLevel);}, [zoomLevel]); Note that there is no cleanup needed in this case. In development, React will call the Effect twice, but this is not a problem because calling setZoomLevel twice with the same value does not do anything. It may be slightly slower, but this doesn’t matter because it won’t remount needlessly in production. Some APIs may not allow you to call them twice in a row. For example, the showModal method of the built-in <dialog> element throws if you call it twice. Implement the cleanup function and make it close the (() => { const dialog = dialogRef.current; dialog.showModal(); return () => dialog.close();}, []); In development, your Effect will call showModal(), then immediately close(), and then showModal() again. This has the same user-visible behavior as calling showModal() once, as you would see in production. Subscribing to events If your Effect subscribes to something, the cleanup function should (() => { function handleScroll(e) { console.log(window.scrollX, window.scrollY); } window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll);}, []); In development, your Effect will call addEventListener(), then immediately removeEventListener(), and then addEventListener() again with the same handler. So there would be only one active subscription at a time. This has the same user-visible behavior as calling addEventListener() once, as in production. Triggering animations If your Effect animates something in, the cleanup function should reset the animation to the initial (() => { const node = ref.current; node.style.opacity = 1; // Trigger the animation return () => { node.style.opacity = 0; // Reset to the initial value };}, []); In development, opacity will be set to 1, then to 0, and then to 1 again. This should have the same user-visible behavior as setting it to 1 directly, which is what would happen in production. If you use a third-party animation library with support for tweening, your cleanup function should reset the timeline to its initial state. Fetching data If your Effect fetches something, the cleanup function should either abort the fetch or ignore its (() => { let ignore = false; async function startFetching() { const json = await fetchTodos(userId); if (!ignore) { setTodos(json); } } startFetching(); return () => { ignore = true; };}, [userId]); You can’t “undo” a network request that already happened, but your cleanup function should ensure that the fetch that’s not relevant anymore does not keep affecting your application. If the userId changes from 'Alice' to 'Bob', cleanup ensures that the 'Alice' response is ignored even if it arrives after 'Bob'. In development, you will see two fetches in the Network tab. There is nothing wrong with that. With the approach above, the first Effect will immediately get cleaned up so its copy of the ignore variable will be set to true. So even though there is an extra request, it won’t affect the state thanks to the if (!ignore) check. In production, there will only be one request. If the second request in development is bothering you, the best approach is to use a solution that deduplicates requests and caches their responses between TodoList() { const todos = useSomeDataLibrary(`/api/user/${userId}/todos`); // ... This will not only improve the development experience, but also make your application feel faster. For example, the user pressing the Back button won’t have to wait for some data to load again because it will be cached. You can either build such a cache yourself or use one of the many alternatives to manual fetching in Effects. Deep DiveWhat are good alternatives to data fetching in Effects? Show DetailsWriting fetch calls inside Effects is a popular way to fetch data, especially in fully client-side apps. This is, however, a very manual approach and it has significant don’t run on the server. This means that the initial server-rendered HTML will only include a loading state with no data. The client computer will have to download all JavaScript and render your app only to discover that now it needs to load the data. This is not very efficient. Fetching directly in Effects makes it easy to create “network waterfalls”. You render the parent component, it fetches some data, renders the child components, and then they start fetching their data. If the network is not very fast, this is significantly slower than fetching all data in parallel. Fetching directly in Effects usually means you don’t preload or cache data. For example, if the component unmounts and then mounts again, it would have to fetch the data again. It’s not very ergonomic. There’s quite a bit of boilerplate code involved when writing fetch calls in a way that doesn’t suffer from bugs like race conditions. This list of downsides is not specific to React. It applies to fetching data on mount with any library. Like with routing, data fetching is not trivial to do well, so we recommend the following you use a framework, use its built-in data fetching mechanism. Modern React frameworks have integrated data fetching mechanisms that are efficient and don’t suffer from the above pitfalls. Otherwise, consider using or building a client-side cache. Popular open source solutions include TanStack Query, useSWR, and React Router 6.4+. You can build your own solution too, in which case you would use Effects under the hood, but add logic for deduplicating requests, caching responses, and avoiding network waterfalls (by preloading data or hoisting data requirements to routes). You can continue fetching data directly in Effects if neither of these approaches suit you. Sending analytics Consider this code that sends an analytics event on the page (() => { logVisit(url); // Sends a POST request}, [url]); In development, logVisit will be called twice for every URL, so you might be tempted to try to fix that. We recommend keeping this code as is. Like with earlier examples, there is no user-visible behavior difference between running it once and running it twice. From a practical point of view, logVisit should not do anything in development because you don’t want the logs from the development machines to skew the production metrics. Your component remounts every time you save its file, so it logs extra visits in development anyway. In production, there will be no duplicate visit logs. To debug the analytics events you’re sending, you can deploy your app to a staging environment (which runs in production mode) or temporarily opt out of Strict Mode and its development-only remounting checks. You may also send analytics from the route change event handlers instead of Effects. For more precise analytics, intersection observers can help track which components are in the viewport and how long they remain visible. Not an the application Some logic should only run once when the application starts. You can put it outside your (typeof window !== 'undefined') { // Check if we're running in the browser. checkAuthToken(); loadDataFromLocalStorage();}function App() { // ...} This guarantees that such logic only runs once after the browser loads the page. Not an a product Sometimes, even if you write a cleanup function, there’s no way to prevent user-visible consequences of running the Effect twice. For example, maybe your Effect sends a POST request like buying a (() => { // 🔴 Effect fires twice in development, exposing a problem in the code. fetch('/api/buy', { method: 'POST' });}, []); You wouldn’t want to buy the product twice. However, this is also why you shouldn’t put this logic in an Effect. What if the user goes to another page and then presses Back? Your Effect would run again. You don’t want to buy the product when the user visits a page; you want to buy it when the user clicks the Buy button. Buying is not caused by rendering; it’s caused by a specific interaction. It should run only when the user presses the button. Delete the Effect and move your /api/buy request into the Buy button event handleClick() { // ✅ Buying is an event because it is caused by a particular interaction. fetch('/api/buy', { method: 'POST' }); } This illustrates that if remounting breaks the logic of your application, this usually uncovers existing bugs. From a user’s perspective, visiting a page shouldn’t be different from visiting it, clicking a link, then pressing Back to view the page again. React verifies that your components abide by this principle by remounting them once in development. Putting it all together This playground can help you “get a feel” for how Effects work in practice. This example uses setTimeout to schedule a console log with the input text to appear three seconds after the Effect runs. The cleanup function cancels the pending timeout. Start by pressing “Mount the component”: App.jsApp.jsReloadClearForkimport { useState, useEffect } from 'react'; function Playground() { const [text, setText] = useState('a'); useEffect(() => { function onTimeout() { console.log('⏰ ' + text); } console.log('🔵 Schedule \"' + text + '\" log'); const timeoutId = setTimeout(onTimeout, 3000); return () => { console.log('🟡 Cancel \"' + text + '\" log'); clearTimeout(timeoutId); }; }, [text]); return ( <> <label> What to log:{' '} <input value={text} onChange={e => setText(e.target.value)} /> </label> <h1>{text}</h1> </> ); } export default function App() { const [show, setShow] = useState(false); return ( <> <button onClick={() => setShow(!show)}> {show ? 'Unmount' : 'Mount'} the component </button> {show && <hr />} {show && <Playground />} </> ); } Show more You will see three logs at \"a\" log, Cancel \"a\" log, and Schedule \"a\" log again. Three second later there will also be a log saying a. As you learned earlier, the extra schedule/cancel pair is because React remounts the component once in development to verify that you’ve implemented cleanup well. Now edit the input to say abc. If you do it fast enough, you’ll see Schedule \"ab\" log immediately followed by Cancel \"ab\" log and Schedule \"abc\" log. React always cleans up the previous render’s Effect before the next render’s Effect. This is why even if you type into the input fast, there is at most one timeout scheduled at a time. Edit the input a few times and watch the console to get a feel for how Effects get cleaned up. Type something into the input and then immediately press “Unmount the component”. Notice how unmounting cleans up the last render’s Effect. Here, it clears the last timeout before it has a chance to fire. Finally, edit the component above and comment out the cleanup function so that the timeouts don’t get cancelled. Try typing abcde fast. What do you expect to happen in three seconds? Will console.log(text) inside the timeout print the latest text and produce five abcde logs? Give it a try to check your intuition! Three seconds later, you should see a sequence of logs (a, ab, abc, abcd, and abcde) rather than five abcde logs. Each Effect “captures” the text value from its corresponding render. It doesn’t matter that the text state Effect from the render with text = 'ab' will always see 'ab'. In other words, Effects from each render are isolated from each other. If you’re curious how this works, you can read about closures. Deep DiveEach render has its own Effects Show DetailsYou can think of useEffect as “attaching” a piece of behavior to the render output. Consider this default function ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(roomId); connection.connect(); return () => connection.disconnect(); }, [roomId]); return <h1>Welcome to {roomId}!</h1>;}Let’s see what exactly happens as the user navigates around the app.Initial render The user visits <ChatRoom roomId=\"general\" />. Let’s mentally substitute roomId with 'general': // JSX for the first render (roomId = \"general\") return <h1>Welcome to general!</h1>;The Effect is also a part of the rendering output. The first render’s Effect becomes: // Effect for the first render (roomId = \"general\") () => { const connection = createConnection('general'); connection.connect(); return () => connection.disconnect(); }, // Dependencies for the first render (roomId = \"general\") ['general']React runs this Effect, which connects to the 'general' chat room.Re-render with same dependencies Let’s say <ChatRoom roomId=\"general\" /> re-renders. The JSX output is the same: // JSX for the second render (roomId = \"general\") return <h1>Welcome to general!</h1>;React sees that the rendering output has not changed, so it doesn’t update the DOM.The Effect from the second render looks like this: // Effect for the second render (roomId = \"general\") () => { const connection = createConnection('general'); connection.connect(); return () => connection.disconnect(); }, // Dependencies for the second render (roomId = \"general\") ['general']React compares ['general'] from the second render with ['general'] from the first render. Because all dependencies are the same, React ignores the Effect from the second render. It never gets called.Re-render with different dependencies Then, the user visits <ChatRoom roomId=\"travel\" />. This time, the component returns different JSX: // JSX for the third render (roomId = \"travel\") return <h1>Welcome to travel!</h1>;React updates the DOM to change \"Welcome to general\" into \"Welcome to travel\".The Effect from the third render looks like this: // Effect for the third render (roomId = \"travel\") () => { const connection = createConnection('travel'); connection.connect(); return () => connection.disconnect(); }, // Dependencies for the third render (roomId = \"travel\") ['travel']React compares ['travel'] from the third render with ['general'] from the second render. One dependency is ('travel', 'general') is false. The Effect can’t be skipped.Before React can apply the Effect from the third render, it needs to clean up the last Effect that did run. The second render’s Effect was skipped, so React needs to clean up the first render’s Effect. If you scroll up to the first render, you’ll see that its cleanup calls disconnect() on the connection that was created with createConnection('general'). This disconnects the app from the 'general' chat room.After that, React runs the third render’s Effect. It connects to the 'travel' chat room.Unmount Finally, let’s say the user navigates away, and the ChatRoom component unmounts. React runs the last Effect’s cleanup function. The last Effect was from the third render. The third render’s cleanup destroys the createConnection('travel') connection. So the app disconnects from the 'travel' room.Development-only behaviors When Strict Mode is on, React remounts every component once after mount (state and DOM are preserved). This helps you find Effects that need cleanup and exposes bugs like race conditions early. Additionally, React will remount the Effects whenever you save a file in development. Both of these behaviors are development-only. Recap Unlike events, Effects are caused by rendering itself rather than a particular interaction. Effects let you synchronize a component with some external system (third-party API, network, etc). By default, Effects run after every render (including the initial one). React will skip the Effect if all of its dependencies have the same values as during the last render. You can’t “choose” your dependencies. They are determined by the code inside the Effect. Empty dependency array ([]) corresponds to the component “mounting”, i.e. being added to the screen. In Strict Mode, React mounts components twice (in development only!) to stress-test your Effects. If your Effect breaks because of remounting, you need to implement a cleanup function. React will call your cleanup function before the Effect runs next time, and during the unmount. Try out some challenges1. Focus a field on mount 2. Focus a field conditionally 3. Fix an interval that fires twice 4. Fix fetching inside an Effect Challenge 1 of a field on mount In this example, the form renders a <MyInput /> component.Use the input’s focus() method to make MyInput automatically focus when it appears on the screen. There is already a commented out implementation, but it doesn’t quite work. Figure out why it doesn’t work, and fix it. (If you’re familiar with the autoFocus attribute, pretend that it does not are reimplementing the same functionality from scratch.)MyInput.jsMyInput.jsReloadClearForkimport { useEffect, useRef } from 'react'; export default function MyInput({ value, onChange }) { const ref = useRef(null); // doesn't quite work. Fix it. // ref.current.focus() return ( <input ref={ref} value={value} onChange={onChange} /> ); } Show moreTo verify that your solution works, press “Show form” and verify that the input receives focus (becomes highlighted and the cursor is placed inside). Press “Hide form” and “Show form” again. Verify the input is highlighted again.MyInput should only focus on mount rather than after every render. To verify that the behavior is right, press “Show form” and then repeatedly press the “Make it uppercase” checkbox. Clicking the checkbox should not focus the input above it. Show solutionNext ChallengePreviousManipulating the DOM with RefsNextYou Might Not Need an EffectCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewWhat are Effects and how are they different from events? You might not need an Effect How to write an Effect Step an Effect Step the Effect dependencies Step cleanup if needed How to handle the Effect firing twice in development? Controlling non-React widgets Subscribing to events Triggering animations Fetching data Sending analytics Not an the application Not an a product Putting it all together RecapChallenges\n\nExample:\n```javascript\nimport { useEffect } from 'react';\n```\n\nExample:\n```javascript\nfunction MyComponent() {  useEffect(() => {    // Code here will run after *every* render  });  return <div />;}\n```\n\nExample:\n```javascript\n<VideoPlayer isPlaying={isPlaying} />;\n```\n\nExample:\n```javascript\nfunction VideoPlayer({ src, isPlaying }) {  // TODO: do something with isPlaying  return <video src={src} />;}\n```\n\nExample:\n```text\nimport { useState, useRef, useEffect } from 'react';\n\nfunction VideoPlayer({ src, isPlaying }) {\n  const ref = useRef(null);\n\n  if (isPlaying) {\n    ref.current.play();  // Calling these while rendering isn't allowed.\n  } else {\n    ref.current.pause(); // Also, this crashes.\n  }\n\n  return <video ref={ref} src={src} loop playsInline />;\n}\n\nexport default function App() {\n  const [isPlaying, setIsPlaying] = useState(false);\n  return (\n    <>\n      <button onClick={() => setIsPlaying(!isPlaying)}>\n        {isPlaying ? 'Pause' : 'Play'}\n      </button>\n      <VideoPlayer\n        isPlaying={isPlaying}\n        src=\"https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4\"\n      />\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nimport { useEffect, useRef } from 'react';function VideoPlayer({ src, isPlaying }) {  const ref = useRef(null);  useEffect(() => {    if (isPlaying) {      ref.current.play();    } else {      ref.current.pause();    }  });  return <video ref={ref} src={src} loop playsInline />;}\n```\n\nExample:\n```text\nimport { useState, useRef, useEffect } from 'react';\n\nfunction VideoPlayer({ src, isPlaying }) {\n  const ref = useRef(null);\n\n  useEffect(() => {\n    if (isPlaying) {\n      ref.current.play();\n    } else {\n      ref.current.pause();\n    }\n  });\n\n  return <video ref={ref} src={src} loop playsInline />;\n}\n\nexport default function App() {\n  const [isPlaying, setIsPlaying] = useState(false);\n  return (\n    <>\n      <button onClick={() => setIsPlaying(!isPlaying)}>\n        {isPlaying ? 'Pause' : 'Play'}\n      </button>\n      <VideoPlayer\n        isPlaying={isPlaying}\n        src=\"https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4\"\n      />\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nconst [count, setCount] = useState(0);useEffect(() => {  setCount(count + 1);});\n```\n\nExample:\n```text\nimport { useState, useRef, useEffect } from 'react';\n\nfunction VideoPlayer({ src, isPlaying }) {\n  const ref = useRef(null);\n\n  useEffect(() => {\n    if (isPlaying) {\n      console.log('Calling video.play()');\n      ref.current.play();\n    } else {\n      console.log('Calling video.pause()');\n      ref.current.pause();\n    }\n  });\n\n  return <video ref={ref} src={src} loop playsInline />;\n}\n\nexport default function App() {\n  const [isPlaying, setIsPlaying] = useState(false);\n  const [text, setText] = useState('');\n  return (\n    <>\n      <input value={text} onChange={e => setText(e.target.value)} />\n      <button onClick={() => setIsPlaying(!isPlaying)}>\n        {isPlaying ? 'Pause' : 'Play'}\n      </button>\n      <VideoPlayer\n        isPlaying={isPlaying}\n        src=\"https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4\"\n      />\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nuseEffect(() => {    // ...  }, []);\n```\n\nExample:\n```text\nimport { useState, useRef, useEffect } from 'react';\n\nfunction VideoPlayer({ src, isPlaying }) {\n  const ref = useRef(null);\n\n  useEffect(() => {\n    if (isPlaying) {\n      console.log('Calling video.play()');\n      ref.current.play();\n    } else {\n      console.log('Calling video.pause()');\n      ref.current.pause();\n    }\n  }, []); // This causes an error\n\n  return <video ref={ref} src={src} loop playsInline />;\n}\n\nexport default function App() {\n  const [isPlaying, setIsPlaying] = useState(false);\n  const [text, setText] = useState('');\n  return (\n    <>\n      <input value={text} onChange={e => setText(e.target.value)} />\n      <button onClick={() => setIsPlaying(!isPlaying)}>\n        {isPlaying ? 'Pause' : 'Play'}\n      </button>\n      <VideoPlayer\n        isPlaying={isPlaying}\n        src=\"https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4\"\n      />\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nuseEffect(() => {    if (isPlaying) { // It's used here...      // ...    } else {      // ...    }  }, [isPlaying]); // ...so it must be declared here!\n```\n\nExample:\n```text\nimport { useState, useRef, useEffect } from 'react';\n\nfunction VideoPlayer({ src, isPlaying }) {\n  const ref = useRef(null);\n\n  useEffect(() => {\n    if (isPlaying) {\n      console.log('Calling video.play()');\n      ref.current.play();\n    } else {\n      console.log('Calling video.pause()');\n      ref.current.pause();\n    }\n  }, [isPlaying]);\n\n  return <video ref={ref} src={src} loop playsInline />;\n}\n\nexport default function App() {\n  const [isPlaying, setIsPlaying] = useState(false);\n  const [text, setText] = useState('');\n  return (\n    <>\n      <input value={text} onChange={e => setText(e.target.value)} />\n      <button onClick={() => setIsPlaying(!isPlaying)}>\n        {isPlaying ? 'Pause' : 'Play'}\n      </button>\n      <VideoPlayer\n        isPlaying={isPlaying}\n        src=\"https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4\"\n      />\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nuseEffect(() => {  // This runs after every render});useEffect(() => {  // This runs only on mount (when the component appears)}, []);useEffect(() => {  // This runs on mount *and also* if either a or b have changed since the last render}, [a, b]);\n```\n\nExample:\n```javascript\nfunction VideoPlayer({ src, isPlaying }) {  const ref = useRef(null);  useEffect(() => {    if (isPlaying) {      ref.current.play();    } else {      ref.current.pause();    }  }, [isPlaying]);\n```\n\nExample:\n```javascript\nfunction VideoPlayer({ src, isPlaying }) {  const ref = useRef(null);  useEffect(() => {    if (isPlaying) {      ref.current.play();    } else {      ref.current.pause();    }  }, [isPlaying, ref]);\n```\n\nExample:\n```javascript\nuseEffect(() => {  const connection = createConnection();  connection.connect();});\n```\n\nExample:\n```javascript\nuseEffect(() => {  const connection = createConnection();  connection.connect();}, []);\n```\n\nExample:\n```text\nimport { useEffect } from 'react';\nimport { createConnection } from './chat.js';\n\nexport default function ChatRoom() {\n  useEffect(() => {\n    const connection = createConnection();\n    connection.connect();\n  }, []);\n  return <h1>Welcome to the chat!</h1>;\n}\n```\n\nExample:\n```javascript\nuseEffect(() => {    const connection = createConnection();    connection.connect();    return () => {      connection.disconnect();    };  }, []);\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';\n\nexport default function ChatRoom() {\n  useEffect(() => {\n    const connection = createConnection();\n    connection.connect();\n    return () => connection.disconnect();\n  }, []);\n  return <h1>Welcome to the chat!</h1>;\n}\n```\n\nExample:\n```javascript\nconst connectionRef = useRef(null);  useEffect(() => {    // 🚩 This wont fix the bug!!!    if (!connectionRef.current) {      connectionRef.current = createConnection();      connectionRef.current.connect();    }  }, []);\n```\n\nExample:\n```javascript\nuseEffect(() => {  const map = mapRef.current;  map.setZoomLevel(zoomLevel);}, [zoomLevel]);\n```\n\nExample:\n```javascript\nuseEffect(() => {  const dialog = dialogRef.current;  dialog.showModal();  return () => dialog.close();}, []);\n```\n\nExample:\n```javascript\nuseEffect(() => {  function handleScroll(e) {    console.log(window.scrollX, window.scrollY);  }  window.addEventListener('scroll', handleScroll);  return () => window.removeEventListener('scroll', handleScroll);}, []);\n```\n\nExample:\n```javascript\nuseEffect(() => {  const node = ref.current;  node.style.opacity = 1; // Trigger the animation  return () => {    node.style.opacity = 0; // Reset to the initial value  };}, []);\n```\n\nExample:\n```javascript\nuseEffect(() => {  let ignore = false;  async function startFetching() {    const json = await fetchTodos(userId);    if (!ignore) {      setTodos(json);    }  }  startFetching();  return () => {    ignore = true;  };}, [userId]);\n```\n\nExample:\n```javascript\nfunction TodoList() {  const todos = useSomeDataLibrary(`/api/user/${userId}/todos`);  // ...\n```\n\nExample:\n```javascript\nuseEffect(() => {  logVisit(url); // Sends a POST request}, [url]);\n```\n\nExample:\n```javascript\nif (typeof window !== 'undefined') { // Check if we're running in the browser.  checkAuthToken();  loadDataFromLocalStorage();}function App() {  // ...}\n```\n\nExample:\n```javascript\nuseEffect(() => {  // 🔴 Wrong: This Effect fires twice in development, exposing a problem in the code.  fetch('/api/buy', { method: 'POST' });}, []);\n```\n\nExample:\n```javascript\nfunction handleClick() {    // ✅ Buying is an event because it is caused by a particular interaction.    fetch('/api/buy', { method: 'POST' });  }\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\n\nfunction Playground() {\n  const [text, setText] = useState('a');\n\n  useEffect(() => {\n    function onTimeout() {\n      console.log('⏰ ' + text);\n    }\n\n    console.log('🔵 Schedule \"' + text + '\" log');\n    const timeoutId = setTimeout(onTimeout, 3000);\n\n    return () => {\n      console.log('🟡 Cancel \"' + text + '\" log');\n      clearTimeout(timeoutId);\n    };\n  }, [text]);\n\n  return (\n    <>\n      <label>\n        What to log:{' '}\n        <input\n          value={text}\n          onChange={e => setText(e.target.value)}\n        />\n      </label>\n      <h1>{text}</h1>\n    </>\n  );\n}\n\nexport default function App() {\n  const [show, setShow] = useState(false);\n  return (\n    <>\n      <button onClick={() => setShow(!show)}>\n        {show ? 'Unmount' : 'Mount'} the component\n      </button>\n      {show && <hr />}\n      {show && <Playground />}\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nexport default function ChatRoom({ roomId }) {  useEffect(() => {    const connection = createConnection(roomId);    connection.connect();    return () => connection.disconnect();  }, [roomId]);  return <h1>Welcome to {roomId}!</h1>;}\n```\n\nExample:\n```javascript\n// JSX for the first render (roomId = \"general\")  return <h1>Welcome to general!</h1>;\n```\n\nExample:\n```javascript\n// Effect for the first render (roomId = \"general\")  () => {    const connection = createConnection('general');    connection.connect();    return () => connection.disconnect();  },  // Dependencies for the first render (roomId = \"general\")  ['general']\n```\n\nExample:\n```javascript\n// JSX for the second render (roomId = \"general\")  return <h1>Welcome to general!</h1>;\n```\n\nExample:\n```javascript\n// Effect for the second render (roomId = \"general\")  () => {    const connection = createConnection('general');    connection.connect();    return () => connection.disconnect();  },  // Dependencies for the second render (roomId = \"general\")  ['general']\n```\n\nExample:\n```javascript\n// JSX for the third render (roomId = \"travel\")  return <h1>Welcome to travel!</h1>;\n```\n\nExample:\n```javascript\n// Effect for the third render (roomId = \"travel\")  () => {    const connection = createConnection('travel');    connection.connect();    return () => connection.disconnect();  },  // Dependencies for the third render (roomId = \"travel\")  ['travel']\n```\n\nExample:\n```text\nimport { useEffect, useRef } from 'react';\n\nexport default function MyInput({ value, onChange }) {\n  const ref = useRef(null);\n\n  // TODO: This doesn't quite work. Fix it.\n  // ref.current.focus()\n\n  return (\n    <input\n      ref={ref}\n      value={value}\n      onChange={onChange}\n    />\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.902Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":41,"totalLines":441,"estimatedTokens":12996}}33{"id":"doc-separating_events_from_effects_react-b8f94195","source":"documentation","title":"Separating Events from Effects – React","url":"https://react.dev/learn/separating-events-from-effects","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactEscape HatchesCopy pageCopySeparating Events from EffectsEvent handlers only re-run when you perform the same interaction again. Unlike event handlers, Effects re-synchronize if some value they read, like a prop or a state variable, is different from what it was during the last render. Sometimes, you also want a mix of both Effect that re-runs in response to some values but not others. This page will teach you how to do that. You will learn How to choose between an event handler and an Effect Why Effects are reactive, and event handlers are not What to do when you want a part of your Effect’s code to not be reactive What Effect Events are, and how to extract them from your Effects How to read the latest props and state from Effects using Effect Events Choosing between event handlers and Effects First, let’s recap the difference between event handlers and Effects. Imagine you’re implementing a chat room component. Your requirements look like component should automatically connect to the selected chat room. When you click the “Send” button, it should send a message to the chat. Let’s say you’ve already implemented the code for them, but you’re not sure where to put it. Should you use event handlers or Effects? Every time you need to answer this question, consider why the code needs to run. Event handlers run in response to specific interactions From the user’s perspective, sending a message should happen because the particular “Send” button was clicked. The user will get rather upset if you send their message at any other time or for any other reason. This is why sending a message should be an event handler. Event handlers let you handle specific ChatRoom({ roomId }) { const [message, setMessage] = useState(''); // ... function handleSendClick() { sendMessage(message); } // ... return ( <> <input value={message} onChange={e => setMessage(e.target.value)} /> <button onClick={handleSendClick}>Send</button> </> );} With an event handler, you can be sure that sendMessage(message) will only run if the user presses the button. Effects run whenever synchronization is needed Recall that you also need to keep the component connected to the chat room. Where does that code go? The reason to run this code is not some particular interaction. It doesn’t matter why or how the user navigated to the chat room screen. Now that they’re looking at it and could interact with it, the component needs to stay connected to the selected chat server. Even if the chat room component was the initial screen of your app, and the user has not performed any interactions at all, you would still need to connect. This is why it’s an ChatRoom({ roomId }) { // ... useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; }, [roomId]); // ...} With this code, you can be sure that there is always an active connection to the currently selected chat server, regardless of the specific interactions performed by the user. Whether the user has only opened your app, selected a different room, or navigated to another screen and back, your Effect ensures that the component will remain synchronized with the currently selected room, and will re-connect whenever it’s necessary. App.jschat.jsApp.jsReloadClearForkimport { useState, useEffect } from 'react'; import { createConnection, sendMessage } from './chat.js'; const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId }) { const [message, setMessage] = useState(''); useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); }, [roomId]); function handleSendClick() { sendMessage(message); } return ( <> <h1>Welcome to the {roomId} room!</h1> <input value={message} onChange={e => setMessage(e.target.value)} /> <button onClick={handleSendClick}>Send</button> </> ); } export default function App() { const [roomId, setRoomId] = useState('general'); const [show, setShow] = useState(false); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value=\"general\">general</option> <option value=\"travel\">travel</option> <option value=\"music\">music</option> </select> </label> <button onClick={() => setShow(!show)}> {show ? 'Close chat' : 'Open chat'} </button> {show && <hr />} {show && <ChatRoom roomId={roomId} />} </> ); } Show more Reactive values and reactive logic Intuitively, you could say that event handlers are always triggered “manually”, for example by clicking a button. Effects, on the other hand, are “automatic”: they run and re-run as often as it’s needed to stay synchronized. There is a more precise way to think about this. Props, state, and variables declared inside your component’s body are called reactive values. In this example, serverUrl is not a reactive value, but roomId and message are. They participate in the rendering data serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) { const [message, setMessage] = useState(''); // ...} Reactive values like these can change due to a re-render. For example, the user may edit the message or choose a different roomId in a dropdown. Event handlers and Effects respond to changes inside event handlers is not reactive. It will not run again unless the user performs the same interaction (e.g. a click) again. Event handlers can read reactive values without “reacting” to their changes. Logic inside Effects is reactive. If your Effect reads a reactive value, you have to specify it as a dependency. Then, if a re-render causes that value to change, React will re-run your Effect’s logic with the new value. Let’s revisit the previous example to illustrate this difference. Logic inside event handlers is not reactive Take a look at this line of code. Should this logic be reactive or not? // ... sendMessage(message); // ... From the user’s perspective, a change to the message does not mean that they want to send a message. It only means that the user is typing. In other words, the logic that sends a message should not be reactive. It should not run again only because the reactive value has changed. That’s why it belongs in the event handleSendClick() { sendMessage(message); } Event handlers aren’t reactive, so sendMessage(message) will only run when the user clicks the Send button. Logic inside Effects is reactive Now let’s return to these lines: // ... const connection = createConnection(serverUrl, roomId); connection.connect(); // ... From the user’s perspective, a change to the roomId does mean that they want to connect to a different room. In other words, the logic for connecting to the room should be reactive. You want these lines of code to “keep up” with the reactive value, and to run again if that value is different. That’s why it belongs in an (() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect() }; }, [roomId]); Effects are reactive, so createConnection(serverUrl, roomId) and connection.connect() will run for every distinct value of roomId. Your Effect keeps the chat connection synchronized to the currently selected room. Extracting non-reactive logic out of Effects Things get more tricky when you want to mix reactive logic with non-reactive logic. For example, imagine that you want to show a notification when the user connects to the chat. You read the current theme (dark or light) from the props so that you can show the notification in the correct ChatRoom({ roomId, theme }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.on('connected', () => { showNotification('Connected!', theme); }); connection.connect(); // ... However, theme is a reactive value (it can change as a result of re-rendering), and every reactive value read by an Effect must be declared as its dependency. Now you have to specify theme as a dependency of your ChatRoom({ roomId, theme }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.on('connected', () => { showNotification('Connected!', theme); }); connection.connect(); return () => { connection.disconnect() }; }, [roomId, theme]); // ✅ All dependencies declared // ... Play with this example and see if you can spot the problem with this user { useState, useEffect } from 'react'; import { createConnection, sendMessage } from './chat.js'; import { showNotification } from './notifications.js'; const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId, theme }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.on('connected', () => { showNotification('Connected!', theme); }); connection.connect(); return () => connection.disconnect(); }, [roomId, theme]); return <h1>Welcome to the {roomId} room!</h1> } export default function App() { const [roomId, setRoomId] = useState('general'); const [isDark, setIsDark] = useState(false); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value=\"general\">general</option> <option value=\"travel\">travel</option> <option value=\"music\">music</option> </select> </label> <label> <input type=\"checkbox\" checked={isDark} onChange={e => setIsDark(e.target.checked)} /> Use dark theme </label> <hr /> <ChatRoom roomId={roomId} theme={isDark ? 'dark' : 'light'} /> </> ); } Show more When the roomId changes, the chat re-connects as you would expect. But since theme is also a dependency, the chat also re-connects every time you switch between the dark and the light theme. That’s not great! In other words, you don’t want this line to be reactive, even though it is inside an Effect (which is reactive): // ... showNotification('Connected!', theme); // ... You need a way to separate this non-reactive logic from the reactive Effect around it. Declaring an Effect Event Use a special Hook called useEffectEvent to extract this non-reactive logic out of your { useEffect, useEffectEvent } from 'react';function ChatRoom({ roomId, theme }) { const onConnected = useEffectEvent(() => { showNotification('Connected!', theme); }); // ... Here, onConnected is called an Effect Event. It’s a part of your Effect logic, but it behaves a lot more like an event handler. The logic inside it is not reactive, and it always “sees” the latest values of your props and state. Now you can call the onConnected Effect Event from inside your ChatRoom({ roomId, theme }) { const onConnected = useEffectEvent(() => { showNotification('Connected!', theme); }); useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.on('connected', () => { onConnected(); }); connection.connect(); return () => connection.disconnect(); }, [roomId]); // ✅ All dependencies declared // ... This solves the problem. Note that you had to remove theme from the list of your Effect’s dependencies, because it’s no longer used in the Effect. You also don’t need to add onConnected to it, because Effect Events are not reactive and must be omitted from dependencies. Verify that the new behavior works as you would { useState, useEffect } from 'react'; import { useEffectEvent } from 'react'; import { createConnection, sendMessage } from './chat.js'; import { showNotification } from './notifications.js'; const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId, theme }) { const onConnected = useEffectEvent(() => { showNotification('Connected!', theme); }); useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.on('connected', () => { onConnected(); }); connection.connect(); return () => connection.disconnect(); }, [roomId]); return <h1>Welcome to the {roomId} room!</h1> } export default function App() { const [roomId, setRoomId] = useState('general'); const [isDark, setIsDark] = useState(false); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value=\"general\">general</option> <option value=\"travel\">travel</option> <option value=\"music\">music</option> </select> </label> <label> <input type=\"checkbox\" checked={isDark} onChange={e => setIsDark(e.target.checked)} /> Use dark theme </label> <hr /> <ChatRoom roomId={roomId} theme={isDark ? 'dark' : 'light'} /> </> ); } Show more You can think of Effect Events as being very similar to event handlers. The main difference is that event handlers run in response to user interactions, whereas Effect Events are triggered by you from Effects. Effect Events let you “break the chain” between the reactivity of Effects and code that should not be reactive. Reading latest props and state with Effect Events Effect Events let you fix many patterns where you might be tempted to suppress the dependency linter. For example, say you have an Effect to log the page Page() { useEffect(() => { logVisit(); }, []); // ...} Later, you add multiple routes to your site. Now your Page component receives a url prop with the current path. You want to pass the url as a part of your logVisit call, but the dependency linter Page({ url }) { useEffect(() => { logVisit(url); }, []); // 🔴 React Hook useEffect has a missing dependency: 'url' // ...} Think about what you want the code to do. You want to log a separate visit for different URLs since each URL represents a different page. In other words, this logVisit call should be reactive with respect to the url. This is why, in this case, it makes sense to follow the dependency linter, and add url as a Page({ url }) { useEffect(() => { logVisit(url); }, [url]); // ✅ All dependencies declared // ...} Now let’s say you want to include the number of items in the shopping cart together with every page Page({ url }) { const { items } = useContext(ShoppingCartContext); const numberOfItems = items.length; useEffect(() => { logVisit(url, numberOfItems); }, [url]); // 🔴 React Hook useEffect has a missing dependency: 'numberOfItems' // ...} You used numberOfItems inside the Effect, so the linter asks you to add it as a dependency. However, you don’t want the logVisit call to be reactive with respect to numberOfItems. If the user puts something into the shopping cart, and the numberOfItems changes, this does not mean that the user visited the page again. In other words, visiting the page is, in some sense, an “event”. It happens at a precise moment in time. Split the code in two Page({ url }) { const { items } = useContext(ShoppingCartContext); const numberOfItems = items.length; const onVisit = useEffectEvent(visitedUrl => { logVisit(visitedUrl, numberOfItems); }); useEffect(() => { onVisit(url); }, [url]); // ✅ All dependencies declared // ...} Here, onVisit is an Effect Event. The code inside it isn’t reactive. This is why you can use numberOfItems (or any other reactive value!) without worrying that it will cause the surrounding code to re-execute on changes. On the other hand, the Effect itself remains reactive. Code inside the Effect uses the url prop, so the Effect will re-run after every re-render with a different url. This, in turn, will call the onVisit Effect Event. As a result, you will call logVisit for every change to the url, and always read the latest numberOfItems. However, if numberOfItems changes on its own, this will not cause any of the code to re-run. NoteYou might be wondering if you could call onVisit() with no arguments, and read the url inside onVisit = useEffectEvent(() => { logVisit(url, numberOfItems); }); useEffect(() => { onVisit(); }, [url]);This would work, but it’s better to pass this url to the Effect Event explicitly. By passing url as an argument to your Effect Event, you are saying that visiting a page with a different url constitutes a separate “event” from the user’s perspective. The visitedUrl is a part of the “event” that onVisit = useEffectEvent(visitedUrl => { logVisit(visitedUrl, numberOfItems); }); useEffect(() => { onVisit(url); }, [url]);Since your Effect Event explicitly “asks” for the visitedUrl, now you can’t accidentally remove url from the Effect’s dependencies. If you remove the url dependency (causing distinct page visits to be counted as one), the linter will warn you about it. You want onVisit to be reactive with regards to the url, so instead of reading the url inside (where it wouldn’t be reactive), you pass it from your Effect.This becomes especially important if there is some asynchronous logic inside the onVisit = useEffectEvent(visitedUrl => { logVisit(visitedUrl, numberOfItems); }); useEffect(() => { setTimeout(() => { onVisit(url); }, 5000); // Delay logging visits }, [url]);Here, url inside onVisit corresponds to the latest url (which could have already changed), but visitedUrl corresponds to the url that originally caused this Effect (and this onVisit call) to run. Deep DiveIs it okay to suppress the dependency linter instead? Show DetailsIn the existing codebases, you may sometimes see the lint rule suppressed like Page({ url }) { const { items } = useContext(ShoppingCartContext); const numberOfItems = items.length; useEffect(() => { logVisit(url, numberOfItems); // 🔴 Avoid suppressing the linter like this: // eslint-disable-next-line react-hooks/exhaustive-deps }, [url]); // ...}We recommend never suppressing the linter.The first downside of suppressing the rule is that React will no longer warn you when your Effect needs to “react” to a new reactive dependency you’ve introduced to your code. In the earlier example, you added url to the dependencies because React reminded you to do it. You will no longer get such reminders for any future edits to that Effect if you disable the linter. This leads to bugs.Here is an example of a confusing bug caused by suppressing the linter. In this example, the handleMove function is supposed to read the current canMove state variable value in order to decide whether the dot should follow the cursor. However, canMove is always true inside handleMove.Can you see why?App.jsApp.jsReloadClearForkimport { useState, useEffect } from 'react'; export default function App() { const [position, setPosition] = useState({ , }); const [canMove, setCanMove] = useState(true); function handleMove(e) { if (canMove) { setPosition({ , }); } } useEffect(() => { window.addEventListener('pointermove', handleMove); return () => window.removeEventListener('pointermove', handleMove); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ( <> <label> <input type=\"checkbox\" checked={canMove} onChange={e => setCanMove(e.target.checked)} /> The dot is allowed to move </label> <hr /> <div style={{ position: 'absolute', backgroundColor: 'pink', borderRadius: '50%', , transform: `translate(${position.x}px, ${position.y}px)`, pointerEvents: 'none', , , , , }} /> </> ); } Show moreThe problem with this code is in suppressing the dependency linter. If you remove the suppression, you’ll see that this Effect should depend on the handleMove function. This makes is declared inside the component body, which makes it a reactive value. Every reactive value must be specified as a dependency, or it can potentially get stale over time!The author of the original code has “lied” to React by saying that the Effect does not depend ([]) on any reactive values. This is why React did not re-synchronize the Effect after canMove has changed (and handleMove with it). Because React did not re-synchronize the Effect, the handleMove attached as a listener is the handleMove function created during the initial render. During the initial render, canMove was true, which is why handleMove from the initial render will forever see that value.If you never suppress the linter, you will never see problems with stale values.With useEffectEvent, there is no need to “lie” to the linter, and the code works as you would { useState, useEffect } from 'react'; import { useEffectEvent } from 'react'; export default function App() { const [position, setPosition] = useState({ , }); const [canMove, setCanMove] = useState(true); const onMove = useEffectEvent(e => { if (canMove) { setPosition({ , }); } }); useEffect(() => { window.addEventListener('pointermove', onMove); return () => window.removeEventListener('pointermove', onMove); }, []); return ( <> <label> <input type=\"checkbox\" checked={canMove} onChange={e => setCanMove(e.target.checked)} /> The dot is allowed to move </label> <hr /> <div style={{ position: 'absolute', backgroundColor: 'pink', borderRadius: '50%', , transform: `translate(${position.x}px, ${position.y}px)`, pointerEvents: 'none', , , , , }} /> </> ); } Show moreThis doesn’t mean that useEffectEvent is always the correct solution. You should only apply it to the lines of code that you don’t want to be reactive. In the above sandbox, you didn’t want the Effect’s code to be reactive with regards to canMove. That’s why it made sense to extract an Effect Event.Read Removing Effect Dependencies for other correct alternatives to suppressing the linter. Limitations of Effect Events Effect Events are very limited in how you can use call them from inside Effects. Never pass them to other components or Hooks. For example, don’t declare and pass an Effect Event like Timer() { const [count, setCount] = useState(0); const onTick = useEffectEvent(() => { setCount(count + 1); }); useTimer(onTick, 1000); // 🔴 Effect Events return <h1>{count}</h1>}function useTimer(callback, delay) { useEffect(() => { const id = setInterval(() => { callback(); }, delay); return () => { clearInterval(id); }; }, [delay, callback]); // Need to specify \"callback\" in dependencies} Instead, always declare Effect Events directly next to the Effects that use Timer() { const [count, setCount] = useState(0); useTimer(() => { setCount(count + 1); }, 1000); return <h1>{count}</h1>}function useTimer(callback, delay) { const onTick = useEffectEvent(() => { callback(); }); useEffect(() => { const id = setInterval(() => { onTick(); // ✅ called locally inside an Effect }, delay); return () => { clearInterval(id); }; }, [delay]); // No need to specify \"onTick\" (an Effect Event) as a dependency} Effect Events are non-reactive “pieces” of your Effect code. They should be next to the Effect using them. Recap Event handlers run in response to specific interactions. Effects run whenever synchronization is needed. Logic inside event handlers is not reactive. Logic inside Effects is reactive. You can move non-reactive logic from Effects into Effect Events. Only call Effect Events from inside Effects. Don’t pass Effect Events to other components or Hooks. Try out some challenges1. Fix a variable that doesn’t update 2. Fix a freezing counter 3. Fix a non-adjustable delay 4. Fix a delayed notification Challenge 1 of a variable that doesn’t update This Timer component keeps a count state variable which increases every second. The value by which it’s increasing is stored in the increment state variable. You can control the increment variable with the plus and minus buttons.However, no matter how many times you click the plus button, the counter is still incremented by one every second. What’s wrong with this code? Why is increment always equal to 1 inside the Effect’s code? Find the mistake and fix it.App.jsApp.jsReloadClearForkimport { useState, useEffect } from 'react'; export default function Timer() { const [count, setCount] = useState(0); const [increment, setIncrement] = useState(1); useEffect(() => { const id = setInterval(() => { setCount(c => c + increment); }, 1000); return () => { clearInterval(id); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ( <> <h1> Counter: {count} <button onClick={() => setCount(0)}>Reset</button> </h1> <hr /> <p> Every second, increment by: <button disabled={increment === 0} onClick={() => { setIncrement(i => i - 1); }}>–</button> <b>{increment}</b> <button onClick={() => { setIncrement(i => i + 1); }}>+</button> </p> </> ); } Show more Show hint Show solutionNext ChallengePreviousLifecycle of Reactive EffectsNextRemoving Effect DependenciesCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewChoosing between event handlers and Effects Event handlers run in response to specific interactions Effects run whenever synchronization is needed Reactive values and reactive logic Logic inside event handlers is not reactive Logic inside Effects is reactive Extracting non-reactive logic out of Effects Declaring an Effect Event Reading latest props and state with Effect Events Limitations of Effect Events RecapChallenges\n\nExample:\n```javascript\nfunction ChatRoom({ roomId }) {  const [message, setMessage] = useState('');  // ...  function handleSendClick() {    sendMessage(message);  }  // ...  return (    <>      <input value={message} onChange={e => setMessage(e.target.value)} />      <button onClick={handleSendClick}>Send</button>    </>  );}\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId }) {  // ...  useEffect(() => {    const connection = createConnection(serverUrl, roomId);    connection.connect();    return () => {      connection.disconnect();    };  }, [roomId]);  // ...}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { createConnection, sendMessage } from './chat.js';\n\nconst serverUrl = 'https://localhost:1234';\n\nfunction ChatRoom({ roomId }) {\n  const [message, setMessage] = useState('');\n\n  useEffect(() => {\n    const connection = createConnection(serverUrl, roomId);\n    connection.connect();\n    return () => connection.disconnect();\n  }, [roomId]);\n\n  function handleSendClick() {\n    sendMessage(message);\n  }\n\n  return (\n    <>\n      <h1>Welcome to the {roomId} room!</h1>\n      <input value={message} onChange={e => setMessage(e.target.value)} />\n      <button onClick={handleSendClick}>Send</button>\n    </>\n  );\n}\n\nexport default function App() {\n  const [roomId, setRoomId] = useState('general');\n  const [show, setShow] = useState(false);\n  return (\n    <>\n      <label>\n        Choose the chat room:{' '}\n        <select\n          value={roomId}\n          onChange={e => setRoomId(e.target.value)}\n        >\n          <option value=\"general\">general</option>\n          <option value=\"travel\">travel</option>\n          <option value=\"music\">music</option>\n        </select>\n      </label>\n      <button onClick={() => setShow(!show)}>\n        {show ? 'Close chat' : 'Open chat'}\n      </button>\n      {show && <hr />}\n      {show && <ChatRoom roomId={roomId} />}\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nconst serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) {  const [message, setMessage] = useState('');  // ...}\n```\n\nExample:\n```javascript\n// ...    sendMessage(message);    // ...\n```\n\nExample:\n```javascript\nfunction handleSendClick() {    sendMessage(message);  }\n```\n\nExample:\n```javascript\n// ...    const connection = createConnection(serverUrl, roomId);    connection.connect();    // ...\n```\n\nExample:\n```javascript\nuseEffect(() => {    const connection = createConnection(serverUrl, roomId);    connection.connect();    return () => {      connection.disconnect()    };  }, [roomId]);\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId, theme }) {  useEffect(() => {    const connection = createConnection(serverUrl, roomId);    connection.on('connected', () => {      showNotification('Connected!', theme);    });    connection.connect();    // ...\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId, theme }) {  useEffect(() => {    const connection = createConnection(serverUrl, roomId);    connection.on('connected', () => {      showNotification('Connected!', theme);    });    connection.connect();    return () => {      connection.disconnect()    };  }, [roomId, theme]); // ✅ All dependencies declared  // ...\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { createConnection, sendMessage } from './chat.js';\nimport { showNotification } from './notifications.js';\n\nconst serverUrl = 'https://localhost:1234';\n\nfunction ChatRoom({ roomId, theme }) {\n  useEffect(() => {\n    const connection = createConnection(serverUrl, roomId);\n    connection.on('connected', () => {\n      showNotification('Connected!', theme);\n    });\n    connection.connect();\n    return () => connection.disconnect();\n  }, [roomId, theme]);\n\n  return <h1>Welcome to the {roomId} room!</h1>\n}\n\nexport default function App() {\n  const [roomId, setRoomId] = useState('general');\n  const [isDark, setIsDark] = useState(false);\n  return (\n    <>\n      <label>\n        Choose the chat room:{' '}\n        <select\n          value={roomId}\n          onChange={e => setRoomId(e.target.value)}\n        >\n          <option value=\"general\">general</option>\n          <option value=\"travel\">travel</option>\n          <option value=\"music\">music</option>\n        </select>\n      </label>\n      <label>\n        <input\n          type=\"checkbox\"\n          checked={isDark}\n          onChange={e => setIsDark(e.target.checked)}\n        />\n        Use dark theme\n      </label>\n      <hr />\n      <ChatRoom\n        roomId={roomId}\n        theme={isDark ? 'dark' : 'light'}\n      />\n    </>\n  );\n}\n```\n\nExample:\n```javascript\n// ...      showNotification('Connected!', theme);      // ...\n```\n\nExample:\n```javascript\nimport { useEffect, useEffectEvent } from 'react';function ChatRoom({ roomId, theme }) {  const onConnected = useEffectEvent(() => {    showNotification('Connected!', theme);  });  // ...\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId, theme }) {  const onConnected = useEffectEvent(() => {    showNotification('Connected!', theme);  });  useEffect(() => {    const connection = createConnection(serverUrl, roomId);    connection.on('connected', () => {      onConnected();    });    connection.connect();    return () => connection.disconnect();  }, [roomId]); // ✅ All dependencies declared  // ...\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { useEffectEvent } from 'react';\nimport { createConnection, sendMessage } from './chat.js';\nimport { showNotification } from './notifications.js';\n\nconst serverUrl = 'https://localhost:1234';\n\nfunction ChatRoom({ roomId, theme }) {\n  const onConnected = useEffectEvent(() => {\n    showNotification('Connected!', theme);\n  });\n\n  useEffect(() => {\n    const connection = createConnection(serverUrl, roomId);\n    connection.on('connected', () => {\n      onConnected();\n    });\n    connection.connect();\n    return () => connection.disconnect();\n  }, [roomId]);\n\n  return <h1>Welcome to the {roomId} room!</h1>\n}\n\nexport default function App() {\n  const [roomId, setRoomId] = useState('general');\n  const [isDark, setIsDark] = useState(false);\n  return (\n    <>\n      <label>\n        Choose the chat room:{' '}\n        <select\n          value={roomId}\n          onChange={e => setRoomId(e.target.value)}\n        >\n          <option value=\"general\">general</option>\n          <option value=\"travel\">travel</option>\n          <option value=\"music\">music</option>\n        </select>\n      </label>\n      <label>\n        <input\n          type=\"checkbox\"\n          checked={isDark}\n          onChange={e => setIsDark(e.target.checked)}\n        />\n        Use dark theme\n      </label>\n      <hr />\n      <ChatRoom\n        roomId={roomId}\n        theme={isDark ? 'dark' : 'light'}\n      />\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nfunction Page() {  useEffect(() => {    logVisit();  }, []);  // ...}\n```\n\nExample:\n```javascript\nfunction Page({ url }) {  useEffect(() => {    logVisit(url);  }, []); // 🔴 React Hook useEffect has a missing dependency: 'url'  // ...}\n```\n\nExample:\n```javascript\nfunction Page({ url }) {  useEffect(() => {    logVisit(url);  }, [url]); // ✅ All dependencies declared  // ...}\n```\n\nExample:\n```javascript\nfunction Page({ url }) {  const { items } = useContext(ShoppingCartContext);  const numberOfItems = items.length;  useEffect(() => {    logVisit(url, numberOfItems);  }, [url]); // 🔴 React Hook useEffect has a missing dependency: 'numberOfItems'  // ...}\n```\n\nExample:\n```javascript\nfunction Page({ url }) {  const { items } = useContext(ShoppingCartContext);  const numberOfItems = items.length;  const onVisit = useEffectEvent(visitedUrl => {    logVisit(visitedUrl, numberOfItems);  });  useEffect(() => {    onVisit(url);  }, [url]); // ✅ All dependencies declared  // ...}\n```\n\nExample:\n```javascript\nconst onVisit = useEffectEvent(() => {    logVisit(url, numberOfItems);  });  useEffect(() => {    onVisit();  }, [url]);\n```\n\nExample:\n```javascript\nconst onVisit = useEffectEvent(visitedUrl => {    logVisit(visitedUrl, numberOfItems);  });  useEffect(() => {    onVisit(url);  }, [url]);\n```\n\nExample:\n```javascript\nconst onVisit = useEffectEvent(visitedUrl => {    logVisit(visitedUrl, numberOfItems);  });  useEffect(() => {    setTimeout(() => {      onVisit(url);    }, 5000); // Delay logging visits  }, [url]);\n```\n\nExample:\n```javascript\nfunction Page({ url }) {  const { items } = useContext(ShoppingCartContext);  const numberOfItems = items.length;  useEffect(() => {    logVisit(url, numberOfItems);    // 🔴 Avoid suppressing the linter like this:    // eslint-disable-next-line react-hooks/exhaustive-deps  }, [url]);  // ...}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\n\nexport default function App() {\n  const [position, setPosition] = useState({ x: 0, y: 0 });\n  const [canMove, setCanMove] = useState(true);\n\n  function handleMove(e) {\n    if (canMove) {\n      setPosition({ x: e.clientX, y: e.clientY });\n    }\n  }\n\n  useEffect(() => {\n    window.addEventListener('pointermove', handleMove);\n    return () => window.removeEventListener('pointermove', handleMove);\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, []);\n\n  return (\n    <>\n      <label>\n        <input type=\"checkbox\"\n          checked={canMove}\n          onChange={e => setCanMove(e.target.checked)}\n        />\n        The dot is allowed to move\n      </label>\n      <hr />\n      <div style={{\n        position: 'absolute',\n        backgroundColor: 'pink',\n        borderRadius: '50%',\n        opacity: 0.6,\n        transform: `translate(${position.x}px, ${position.y}px)`,\n        pointerEvents: 'none',\n        left: -20,\n        top: -20,\n        width: 40,\n        height: 40,\n      }} />\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { useEffectEvent } from 'react';\n\nexport default function App() {\n  const [position, setPosition] = useState({ x: 0, y: 0 });\n  const [canMove, setCanMove] = useState(true);\n\n  const onMove = useEffectEvent(e => {\n    if (canMove) {\n      setPosition({ x: e.clientX, y: e.clientY });\n    }\n  });\n\n  useEffect(() => {\n    window.addEventListener('pointermove', onMove);\n    return () => window.removeEventListener('pointermove', onMove);\n  }, []);\n\n  return (\n    <>\n      <label>\n        <input type=\"checkbox\"\n          checked={canMove}\n          onChange={e => setCanMove(e.target.checked)}\n        />\n        The dot is allowed to move\n      </label>\n      <hr />\n      <div style={{\n        position: 'absolute',\n        backgroundColor: 'pink',\n        borderRadius: '50%',\n        opacity: 0.6,\n        transform: `translate(${position.x}px, ${position.y}px)`,\n        pointerEvents: 'none',\n        left: -20,\n        top: -20,\n        width: 40,\n        height: 40,\n      }} />\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nfunction Timer() {  const [count, setCount] = useState(0);  const onTick = useEffectEvent(() => {    setCount(count + 1);  });  useTimer(onTick, 1000); // 🔴 Avoid: Passing Effect Events  return <h1>{count}</h1>}function useTimer(callback, delay) {  useEffect(() => {    const id = setInterval(() => {      callback();    }, delay);    return () => {      clearInterval(id);    };  }, [delay, callback]); // Need to specify \"callback\" in dependencies}\n```\n\nExample:\n```javascript\nfunction Timer() {  const [count, setCount] = useState(0);  useTimer(() => {    setCount(count + 1);  }, 1000);  return <h1>{count}</h1>}function useTimer(callback, delay) {  const onTick = useEffectEvent(() => {    callback();  });  useEffect(() => {    const id = setInterval(() => {      onTick(); // ✅ Good: Only called locally inside an Effect    }, delay);    return () => {      clearInterval(id);    };  }, [delay]); // No need to specify \"onTick\" (an Effect Event) as a dependency}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\n\nexport default function Timer() {\n  const [count, setCount] = useState(0);\n  const [increment, setIncrement] = useState(1);\n\n  useEffect(() => {\n    const id = setInterval(() => {\n      setCount(c => c + increment);\n    }, 1000);\n    return () => {\n      clearInterval(id);\n    };\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, []);\n\n  return (\n    <>\n      <h1>\n        Counter: {count}\n        <button onClick={() => setCount(0)}>Reset</button>\n      </h1>\n      <hr />\n      <p>\n        Every second, increment by:\n        <button disabled={increment === 0} onClick={() => {\n          setIncrement(i => i - 1);\n        }}>–</button>\n        <b>{increment}</b>\n        <button onClick={() => {\n          setIncrement(i => i + 1);\n        }}>+</button>\n      </p>\n    </>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.906Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":29,"totalLines":422,"estimatedTokens":9703}}34{"id":"doc-removing_effect_dependencies_react-d20eff86","source":"documentation","title":"Removing Effect Dependencies – React","url":"https://react.dev/learn/removing-effect-dependencies","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactEscape HatchesCopy pageCopyRemoving Effect DependenciesWhen you write an Effect, the linter will verify that you’ve included every reactive value (like props and state) that the Effect reads in the list of your Effect’s dependencies. This ensures that your Effect remains synchronized with the latest props and state of your component. Unnecessary dependencies may cause your Effect to run too often, or even create an infinite loop. Follow this guide to review and remove unnecessary dependencies from your Effects. You will learn How to fix infinite Effect dependency loops What to do when you want to remove a dependency How to read a value from your Effect without “reacting” to it How and why to avoid object and function dependencies Why suppressing the dependency linter is dangerous, and what to do instead Dependencies should match the code When you write an Effect, you first specify how to start and stop whatever you want your Effect to be serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); // ...} Then, if you leave the Effect dependencies empty ([]), the linter will suggest the correct { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); }, []); // <-- Fix the mistake here! return <h1>Welcome to the {roomId} room!</h1>; } export default function App() { const [roomId, setRoomId] = useState('general'); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value=\"general\">general</option> <option value=\"travel\">travel</option> <option value=\"music\">music</option> </select> </label> <hr /> <ChatRoom roomId={roomId} /> </> ); } Show more Fill them in according to what the linter ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); }, [roomId]); // ✅ All dependencies declared // ...} Effects “react” to reactive values. Since roomId is a reactive value (it can change due to a re-render), the linter verifies that you’ve specified it as a dependency. If roomId receives a different value, React will re-synchronize your Effect. This ensures that the chat stays connected to the selected room and “reacts” to the { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); }, [roomId]); return <h1>Welcome to the {roomId} room!</h1>; } export default function App() { const [roomId, setRoomId] = useState('general'); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value=\"general\">general</option> <option value=\"travel\">travel</option> <option value=\"music\">music</option> </select> </label> <hr /> <ChatRoom roomId={roomId} /> </> ); } Show more To remove a dependency, prove that it’s not a dependency Notice that you can’t “choose” the dependencies of your Effect. Every reactive value used by your Effect’s code must be declared in your dependency list. The dependency list is determined by the surrounding serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) { // This is a reactive value useEffect(() => { const connection = createConnection(serverUrl, roomId); // This Effect reads that reactive value connection.connect(); return () => connection.disconnect(); }, [roomId]); // ✅ So you must specify that reactive value as a dependency of your Effect // ...} Reactive values include props and all variables and functions declared directly inside of your component. Since roomId is a reactive value, you can’t remove it from the dependency list. The linter wouldn’t allow serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); }, []); // 🔴 React Hook useEffect has a missing dependency: 'roomId' // ...} And the linter would be right! Since roomId may change over time, this would introduce a bug in your code. To remove a dependency, “prove” to the linter that it doesn’t need to be a dependency. For example, you can move roomId out of your component to prove that it’s not reactive and won’t change on serverUrl = 'https://localhost:1234';const roomId = 'music'; // Not a reactive value anymorefunction ChatRoom() { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); }, []); // ✅ All dependencies declared // ...} Now that roomId is not a reactive value (and can’t change on a re-render), it doesn’t need to be a { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; const serverUrl = 'https://localhost:1234'; const roomId = 'music'; export default function ChatRoom() { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); }, []); return <h1>Welcome to the {roomId} room!</h1>; } This is why you could now specify an empty ([]) dependency list. Your Effect really doesn’t depend on any reactive value anymore, so it really doesn’t need to re-run when any of the component’s props or state change. To change the dependencies, change the code You might have noticed a pattern in your , you change the code of your Effect or how your reactive values are declared. Then, you follow the linter and adjust the dependencies to match the code you have changed. If you’re not happy with the list of dependencies, you go back to the first step (and change the code again). The last part is important. If you want to change the dependencies, change the surrounding code first. You can think of the dependency list as a list of all the reactive values used by your Effect’s code. You don’t choose what to put on that list. The list describes your code. To change the dependency list, change the code. This might feel like solving an equation. You might start with a goal (for example, to remove a dependency), and you need to “find” the code matching that goal. Not everyone finds solving equations fun, and the same thing could be said about writing Effects! Luckily, there is a list of common recipes that you can try below. PitfallIf you have an existing codebase, you might have some Effects that suppress the linter like (() => { // ... // 🔴 Avoid suppressing the linter like this: // eslint-ignore-next-line react-hooks/exhaustive-deps}, []);When dependencies don’t match the code, there is a very high risk of introducing bugs. By suppressing the linter, you “lie” to React about the values your Effect depends on.Instead, use the techniques below. Deep DiveWhy is suppressing the dependency linter so dangerous? Show DetailsSuppressing the linter leads to very unintuitive bugs that are hard to find and fix. Here’s one { useState, useEffect } from 'react'; export default function Timer() { const [count, setCount] = useState(0); const [increment, setIncrement] = useState(1); function onTick() { setCount(count + increment); } useEffect(() => { const id = setInterval(onTick, 1000); return () => clearInterval(id); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ( <> <h1> Counter: {count} <button onClick={() => setCount(0)}>Reset</button> </h1> <hr /> <p> Every second, increment by: <button disabled={increment === 0} onClick={() => { setIncrement(i => i - 1); }}>–</button> <b>{increment}</b> <button onClick={() => { setIncrement(i => i + 1); }}>+</button> </p> </> ); } Show moreLet’s say that you wanted to run the Effect “only on mount”. You’ve read that empty ([]) dependencies do that, so you’ve decided to ignore the linter, and forcefully specified [] as the dependencies.This counter was supposed to increment every second by the amount configurable with the two buttons. However, since you “lied” to React that this Effect doesn’t depend on anything, React forever keeps using the onTick function from the initial render. During that render, count was 0 and increment was 1. This is why onTick from that render always calls setCount(0 + 1) every second, and you always see 1. Bugs like this are harder to fix when they’re spread across multiple components.There’s always a better solution than ignoring the linter! To fix this code, you need to add onTick to the dependency list. (To ensure the interval is only setup once, make onTick an Effect Event.)We recommend treating the dependency lint error as a compilation error. If you don’t suppress it, you will never see bugs like this. The rest of this page documents the alternatives for this and other cases. Removing unnecessary dependencies Every time you adjust the Effect’s dependencies to reflect the code, look at the dependency list. Does it make sense for the Effect to re-run when any of these dependencies change? Sometimes, the answer is “no”: You might want to re-execute different parts of your Effect under different conditions. You might want to only read the latest value of some dependency instead of “reacting” to its changes. A dependency may change too often unintentionally because it’s an object or a function. To find the right solution, you’ll need to answer a few questions about your Effect. Let’s walk through them. Should this code move to an event handler? The first thing you should think about is whether this code should be an Effect at all. Imagine a form. On submit, you set the submitted state variable to true. You need to send a POST request and show a notification. You’ve put this logic inside an Effect that “reacts” to submitted being Form() { const [submitted, setSubmitted] = useState(false); useEffect(() => { if (submitted) { // 🔴 logic inside an Effect post('/api/register'); showNotification('Successfully registered!'); } }, [submitted]); function handleSubmit() { setSubmitted(true); } // ...} Later, you want to style the notification message according to the current theme, so you read the current theme. Since theme is declared in the component body, it is a reactive value, so you add it as a Form() { const [submitted, setSubmitted] = useState(false); const theme = useContext(ThemeContext); useEffect(() => { if (submitted) { // 🔴 logic inside an Effect post('/api/register'); showNotification('Successfully registered!', theme); } }, [submitted, theme]); // ✅ All dependencies declared function handleSubmit() { setSubmitted(true); } // ...} By doing this, you’ve introduced a bug. Imagine you submit the form first and then switch between Dark and Light themes. The theme will change, the Effect will re-run, and so it will display the same notification again! The problem here is that this shouldn’t be an Effect in the first place. You want to send this POST request and show the notification in response to submitting the form, which is a particular interaction. To run some code in response to particular interaction, put that logic directly into the corresponding event Form() { const theme = useContext(ThemeContext); function handleSubmit() { // ✅ logic is called from event handlers post('/api/register'); showNotification('Successfully registered!', theme); } // ...} Now that the code is in an event handler, it’s not reactive—so it will only run when the user submits the form. Read more about choosing between event handlers and Effects and how to delete unnecessary Effects. Is your Effect doing several unrelated things? The next question you should ask yourself is whether your Effect is doing several unrelated things. Imagine you’re creating a shipping form where the user needs to choose their city and area. You fetch the list of cities from the server according to the selected country to show them in a ShippingForm({ country }) { const [cities, setCities] = useState(null); const [city, setCity] = useState(null); useEffect(() => { let ignore = false; fetch(`/api/cities?country=${country}`) ); return () => { ignore = true; }; }, [country]); // ✅ All dependencies declared // ... This is a good example of fetching data in an Effect. You are synchronizing the cities state with the network according to the country prop. You can’t do this in an event handler because you need to fetch as soon as ShippingForm is displayed and whenever the country changes (no matter which interaction causes it). Now let’s say you’re adding a second select box for city areas, which should fetch the areas for the currently selected city. You might start by adding a second fetch call for the list of areas inside the same ShippingForm({ country }) { const [cities, setCities] = useState(null); const [city, setCity] = useState(null); const [areas, setAreas] = useState(null); useEffect(() => { let ignore = false; fetch(`/api/cities?country=${country}`) ); // 🔴 single Effect synchronizes two independent processes if (city) { fetch(`/api/areas?city=${city}`) ); } return () => { ignore = true; }; }, [country, city]); // ✅ All dependencies declared // ... However, since the Effect now uses the city state variable, you’ve had to add city to the list of dependencies. That, in turn, introduced a the user selects a different city, the Effect will re-run and call fetchCities(country). As a result, you will be unnecessarily refetching the list of cities many times. The problem with this code is that you’re synchronizing two different unrelated want to synchronize the cities state to the network based on the country prop. You want to synchronize the areas state to the network based on the city state. Split the logic into two Effects, each of which reacts to the prop that it needs to synchronize ShippingForm({ country }) { const [cities, setCities] = useState(null); useEffect(() => { let ignore = false; fetch(`/api/cities?country=${country}`) ); return () => { ignore = true; }; }, [country]); // ✅ All dependencies declared const [city, setCity] = useState(null); const [areas, setAreas] = useState(null); useEffect(() => { if (city) { let ignore = false; fetch(`/api/areas?city=${city}`) ); return () => { ignore = true; }; } }, [city]); // ✅ All dependencies declared // ... Now the first Effect only re-runs if the country changes, while the second Effect re-runs when the city changes. You’ve separated them by different things are synchronized by two separate Effects. Two separate Effects have two separate dependency lists, so they won’t trigger each other unintentionally. The final code is longer than the original, but splitting these Effects is still correct. Each Effect should represent an independent synchronization process. In this example, deleting one Effect doesn’t break the other Effect’s logic. This means they synchronize different things, and it’s good to split them up. If you’re concerned about duplication, you can improve this code by extracting repetitive logic into a custom Hook. Are you reading some state to calculate the next state? This Effect updates the messages state variable with a newly created array every time a new message ChatRoom({ roomId }) { const [messages, setMessages] = useState([]); useEffect(() => { const connection = createConnection(); connection.connect(); connection.on('message', (receivedMessage) => { setMessages([...messages, receivedMessage]); }); // ... It uses the messages variable to create a new array starting with all the existing messages and adds the new message at the end. However, since messages is a reactive value read by an Effect, it must be a ChatRoom({ roomId }) { const [messages, setMessages] = useState([]); useEffect(() => { const connection = createConnection(); connection.connect(); connection.on('message', (receivedMessage) => { setMessages([...messages, receivedMessage]); }); return () => connection.disconnect(); }, [roomId, messages]); // ✅ All dependencies declared // ... And making messages a dependency introduces a problem. Every time you receive a message, setMessages() causes the component to re-render with a new messages array that includes the received message. However, since this Effect now depends on messages, this will also re-synchronize the Effect. So every new message will make the chat re-connect. The user would not like that! To fix the issue, don’t read messages inside the Effect. Instead, pass an updater function to ChatRoom({ roomId }) { const [messages, setMessages] = useState([]); useEffect(() => { const connection = createConnection(); connection.connect(); connection.on('message', (receivedMessage) => { setMessages(msgs => [...msgs, receivedMessage]); }); return () => connection.disconnect(); }, [roomId]); // ✅ All dependencies declared // ... Notice how your Effect does not read the messages variable at all now. You only need to pass an updater function like msgs => [...msgs, receivedMessage]. React puts your updater function in a queue and will provide the msgs argument to it during the next render. This is why the Effect itself doesn’t need to depend on messages anymore. As a result of this fix, receiving a chat message will no longer make the chat re-connect. Do you want to read a value without “reacting” to its changes? Suppose that you want to play a sound when the user receives a new message unless isMuted is ChatRoom({ roomId }) { const [messages, setMessages] = useState([]); const [isMuted, setIsMuted] = useState(false); useEffect(() => { const connection = createConnection(); connection.connect(); connection.on('message', (receivedMessage) => { setMessages(msgs => [...msgs, receivedMessage]); if (!isMuted) { playSound(); } }); // ... Since your Effect now uses isMuted in its code, you have to add it to the ChatRoom({ roomId }) { const [messages, setMessages] = useState([]); const [isMuted, setIsMuted] = useState(false); useEffect(() => { const connection = createConnection(); connection.connect(); connection.on('message', (receivedMessage) => { setMessages(msgs => [...msgs, receivedMessage]); if (!isMuted) { playSound(); } }); return () => connection.disconnect(); }, [roomId, isMuted]); // ✅ All dependencies declared // ... The problem is that every time isMuted changes (for example, when the user presses the “Muted” toggle), the Effect will re-synchronize, and reconnect to the chat. This is not the desired user experience! (In this example, even disabling the linter would not work—if you do that, isMuted would get “stuck” with its old value.) To solve this problem, you need to extract the logic that shouldn’t be reactive out of the Effect. You don’t want this Effect to “react” to the changes in isMuted. Move this non-reactive piece of logic into an Effect { useState, useEffect, useEffectEvent } from 'react';function ChatRoom({ roomId }) { const [messages, setMessages] = useState([]); const [isMuted, setIsMuted] = useState(false); const onMessage = useEffectEvent(receivedMessage => { setMessages(msgs => [...msgs, receivedMessage]); if (!isMuted) { playSound(); } }); useEffect(() => { const connection = createConnection(); connection.connect(); connection.on('message', (receivedMessage) => { onMessage(receivedMessage); }); return () => connection.disconnect(); }, [roomId]); // ✅ All dependencies declared // ... Effect Events let you split an Effect into reactive parts (which should “react” to reactive values like roomId and their changes) and non-reactive parts (which only read their latest values, like onMessage reads isMuted). Now that you read isMuted inside an Effect Event, it doesn’t need to be a dependency of your Effect. As a result, the chat won’t re-connect when you toggle the “Muted” setting on and off, solving the original issue! Wrapping an event handler from the props You might run into a similar problem when your component receives an event handler as a ChatRoom({ roomId, onReceiveMessage }) { const [messages, setMessages] = useState([]); useEffect(() => { const connection = createConnection(); connection.connect(); connection.on('message', (receivedMessage) => { onReceiveMessage(receivedMessage); }); return () => connection.disconnect(); }, [roomId, onReceiveMessage]); // ✅ All dependencies declared // ... Suppose that the parent component passes a different onReceiveMessage function on every render: <ChatRoom roomId={roomId} onReceiveMessage={receivedMessage => { // ... }}/> Since onReceiveMessage is a dependency, it would cause the Effect to re-synchronize after every parent re-render. This would make it re-connect to the chat. To solve this, wrap the call in an Effect ChatRoom({ roomId, onReceiveMessage }) { const [messages, setMessages] = useState([]); const onMessage = useEffectEvent(receivedMessage => { onReceiveMessage(receivedMessage); }); useEffect(() => { const connection = createConnection(); connection.connect(); connection.on('message', (receivedMessage) => { onMessage(receivedMessage); }); return () => connection.disconnect(); }, [roomId]); // ✅ All dependencies declared // ... Effect Events aren’t reactive, so you don’t need to specify them as dependencies. As a result, the chat will no longer re-connect even if the parent component passes a function that’s different on every re-render. Separating reactive and non-reactive code In this example, you want to log a visit every time roomId changes. You want to include the current notificationCount with every log, but you don’t want a change to notificationCount to trigger a log event. The solution is again to split out the non-reactive code into an Effect Chat({ roomId, notificationCount }) { const onVisit = useEffectEvent(visitedRoomId => { logVisit(visitedRoomId, notificationCount); }); useEffect(() => { onVisit(roomId); }, [roomId]); // ✅ All dependencies declared // ...} You want your logic to be reactive with regards to roomId, so you read roomId inside of your Effect. However, you don’t want a change to notificationCount to log an extra visit, so you read notificationCount inside of the Effect Event. Learn more about reading the latest props and state from Effects using Effect Events. Does some reactive value change unintentionally? Sometimes, you do want your Effect to “react” to a certain value, but that value changes more often than you’d like—and might not reflect any actual change from the user’s perspective. For example, let’s say that you create an options object in the body of your component, and then read that object from inside of your ChatRoom({ roomId }) { // ... const options = { , }; useEffect(() => { const connection = createConnection(options); connection.connect(); // ... This object is declared in the component body, so it’s a reactive value. When you read a reactive value like this inside an Effect, you declare it as a dependency. This ensures your Effect “reacts” to its changes: // ... useEffect(() => { const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [options]); // ✅ All dependencies declared // ... It is important to declare it as a dependency! This ensures, for example, that if the roomId changes, your Effect will re-connect to the chat with the new options. However, there is also a problem with the code above. To see it, try typing into the input in the sandbox below, and watch what happens in the { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId }) { const [message, setMessage] = useState(''); // Temporarily disable the linter to demonstrate the problem // eslint-disable-next-line react-hooks/exhaustive-deps const options = { , }; useEffect(() => { const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [options]); return ( <> <h1>Welcome to the {roomId} room!</h1> <input value={message} onChange={e => setMessage(e.target.value)} /> </> ); } export default function App() { const [roomId, setRoomId] = useState('general'); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value=\"general\">general</option> <option value=\"travel\">travel</option> <option value=\"music\">music</option> </select> </label> <hr /> <ChatRoom roomId={roomId} /> </> ); } Show more In the sandbox above, the input only updates the message state variable. From the user’s perspective, this should not affect the chat connection. However, every time you update the message, your component re-renders. When your component re-renders, the code inside of it runs again from scratch. A new options object is created from scratch on every re-render of the ChatRoom component. React sees that the options object is a different object from the options object created during the last render. This is why it re-synchronizes your Effect (which depends on options), and the chat re-connects as you type. This problem only affects objects and functions. In JavaScript, each newly created object and function is considered distinct from all the others. It doesn’t matter that the contents inside of them may be the same! // During the first renderconst options1 = { serverUrl: 'https://localhost:1234', roomId: 'music' };// During the next renderconst options2 = { serverUrl: 'https://localhost:1234', roomId: 'music' };// These are two different objects!console.log(Object.is(options1, options2)); // false Object and function dependencies can make your Effect re-synchronize more often than you need. This is why, whenever possible, you should try to avoid objects and functions as your Effect’s dependencies. Instead, try moving them outside the component, inside the Effect, or extracting primitive values out of them. Move static objects and functions outside your component If the object does not depend on any props and state, you can move that object outside your options = { serverUrl: 'https://localhost:1234', roomId: 'music'};function ChatRoom() { const [message, setMessage] = useState(''); useEffect(() => { const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, []); // ✅ All dependencies declared // ... This way, you prove to the linter that it’s not reactive. It can’t change as a result of a re-render, so it doesn’t need to be a dependency. Now re-rendering ChatRoom won’t cause your Effect to re-synchronize. This works for functions createOptions() { return { serverUrl: 'https://localhost:1234', roomId: 'music' };}function ChatRoom() { const [message, setMessage] = useState(''); useEffect(() => { const options = createOptions(); const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, []); // ✅ All dependencies declared // ... Since createOptions is declared outside your component, it’s not a reactive value. This is why it doesn’t need to be specified in your Effect’s dependencies, and why it won’t ever cause your Effect to re-synchronize. Move dynamic objects and functions inside your Effect If your object depends on some reactive value that may change as a result of a re-render, like a roomId prop, you can’t pull it outside your component. You can, however, move its creation inside of your Effect’s serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) { const [message, setMessage] = useState(''); useEffect(() => { const options = { , }; const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [roomId]); // ✅ All dependencies declared // ... Now that options is declared inside of your Effect, it is no longer a dependency of your Effect. Instead, the only reactive value used by your Effect is roomId. Since roomId is not an object or function, you can be sure that it won’t be unintentionally different. In JavaScript, numbers and strings are compared by their content: // During the first renderconst roomId1 = 'music';// During the next renderconst roomId2 = 'music';// These two strings are the same!console.log(Object.is(roomId1, roomId2)); // true Thanks to this fix, the chat no longer re-connects if you edit the { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId }) { const [message, setMessage] = useState(''); useEffect(() => { const options = { , }; const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [roomId]); return ( <> <h1>Welcome to the {roomId} room!</h1> <input value={message} onChange={e => setMessage(e.target.value)} /> </> ); } export default function App() { const [roomId, setRoomId] = useState('general'); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value=\"general\">general</option> <option value=\"travel\">travel</option> <option value=\"music\">music</option> </select> </label> <hr /> <ChatRoom roomId={roomId} /> </> ); } Show more However, it does re-connect when you change the roomId dropdown, as you would expect. This works for functions, serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) { const [message, setMessage] = useState(''); useEffect(() => { function createOptions() { return { , }; } const options = createOptions(); const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [roomId]); // ✅ All dependencies declared // ... You can write your own functions to group pieces of logic inside your Effect. As long as you also declare them inside your Effect, they’re not reactive values, and so they don’t need to be dependencies of your Effect. Read primitive values from objects Sometimes, you may receive an object from ChatRoom({ options }) { const [message, setMessage] = useState(''); useEffect(() => { const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [options]); // ✅ All dependencies declared // ... The risk here is that the parent component will create the object during rendering: <ChatRoom roomId={roomId} options={{ , }}/> This would cause your Effect to re-connect every time the parent component re-renders. To fix this, read information from the object outside the Effect, and avoid having object and function ChatRoom({ options }) { const [message, setMessage] = useState(''); const { roomId, serverUrl } = options; useEffect(() => { const connection = createConnection({ , }); connection.connect(); return () => connection.disconnect(); }, [roomId, serverUrl]); // ✅ All dependencies declared // ... The logic gets a little repetitive (you read some values from an object outside an Effect, and then create an object with the same values inside the Effect). But it makes it very explicit what information your Effect actually depends on. If an object is re-created unintentionally by the parent component, the chat would not re-connect. However, if options.roomId or options.serverUrl really are different, the chat would re-connect. Calculate primitive values from functions The same approach can work for functions. For example, suppose the parent component passes a function: <ChatRoom roomId={roomId} getOptions={() => { return { , }; }}/> To avoid making it a dependency (and causing it to re-connect on re-renders), call it outside the Effect. This gives you the roomId and serverUrl values that aren’t objects, and that you can read from inside your ChatRoom({ getOptions }) { const [message, setMessage] = useState(''); const { roomId, serverUrl } = getOptions(); useEffect(() => { const connection = createConnection({ , }); connection.connect(); return () => connection.disconnect(); }, [roomId, serverUrl]); // ✅ All dependencies declared // ... This only works for pure functions because they are safe to call during rendering. If your function is an event handler, but you don’t want its changes to re-synchronize your Effect, wrap it into an Effect Event instead. Recap Dependencies should always match the code. When you’re not happy with your dependencies, what you need to edit is the code. Suppressing the linter leads to very confusing bugs, and you should always avoid it. To remove a dependency, you need to “prove” to the linter that it’s not necessary. If some code should run in response to a specific interaction, move that code to an event handler. If different parts of your Effect should re-run for different reasons, split it into several Effects. If you want to update some state based on the previous state, pass an updater function. If you want to read the latest value without “reacting” it, extract an Effect Event from your Effect. In JavaScript, objects and functions are considered different if they were created at different times. Try to avoid object and function dependencies. Move them outside the component or inside the Effect. Try out some challenges1. Fix a resetting interval 2. Fix a retriggering animation 3. Fix a reconnecting chat 4. Fix a reconnecting chat, again Challenge 1 of a resetting interval This Effect sets up an interval that ticks every second. You’ve noticed something strange seems like the interval gets destroyed and re-created every time it ticks. Fix the code so that the interval doesn’t get constantly re-created.App.jsApp.jsReloadClearForkimport { useState, useEffect } from 'react'; export default function Timer() { const [count, setCount] = useState(0); useEffect(() => { console.log('✅ Creating an interval'); const id = setInterval(() => { console.log('⏰ Interval tick'); setCount(count + 1); }, 1000); return () => { console.log('❌ Clearing an interval'); clearInterval(id); }; }, [count]); return <h1>Counter: {count}</h1> } Show more Show hint Show solutionNext ChallengePreviousSeparating Events from EffectsNextReusing Logic with Custom HooksCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewDependencies should match the code To remove a dependency, prove that it’s not a dependency To change the dependencies, change the code Removing unnecessary dependencies Should this code move to an event handler? Is your Effect doing several unrelated things? Are you reading some state to calculate the next state? Do you want to read a value without “reacting” to its changes? Does some reactive value change unintentionally? RecapChallenges\n\nExample:\n```javascript\nconst serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) {  useEffect(() => {    const connection = createConnection(serverUrl, roomId);    connection.connect();    return () => connection.disconnect();  \t// ...}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';\n\nconst serverUrl = 'https://localhost:1234';\n\nfunction ChatRoom({ roomId }) {\n  useEffect(() => {\n    const connection = createConnection(serverUrl, roomId);\n    connection.connect();\n    return () => connection.disconnect();\n  }, []); // <-- Fix the mistake here!\n  return <h1>Welcome to the {roomId} room!</h1>;\n}\n\nexport default function App() {\n  const [roomId, setRoomId] = useState('general');\n  return (\n    <>\n      <label>\n        Choose the chat room:{' '}\n        <select\n          value={roomId}\n          onChange={e => setRoomId(e.target.value)}\n        >\n          <option value=\"general\">general</option>\n          <option value=\"travel\">travel</option>\n          <option value=\"music\">music</option>\n        </select>\n      </label>\n      <hr />\n      <ChatRoom roomId={roomId} />\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId }) {  useEffect(() => {    const connection = createConnection(serverUrl, roomId);    connection.connect();    return () => connection.disconnect();  }, [roomId]); // ✅ All dependencies declared  // ...}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';\n\nconst serverUrl = 'https://localhost:1234';\n\nfunction ChatRoom({ roomId }) {\n  useEffect(() => {\n    const connection = createConnection(serverUrl, roomId);\n    connection.connect();\n    return () => connection.disconnect();\n  }, [roomId]);\n  return <h1>Welcome to the {roomId} room!</h1>;\n}\n\nexport default function App() {\n  const [roomId, setRoomId] = useState('general');\n  return (\n    <>\n      <label>\n        Choose the chat room:{' '}\n        <select\n          value={roomId}\n          onChange={e => setRoomId(e.target.value)}\n        >\n          <option value=\"general\">general</option>\n          <option value=\"travel\">travel</option>\n          <option value=\"music\">music</option>\n        </select>\n      </label>\n      <hr />\n      <ChatRoom roomId={roomId} />\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nconst serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) { // This is a reactive value  useEffect(() => {    const connection = createConnection(serverUrl, roomId); // This Effect reads that reactive value    connection.connect();    return () => connection.disconnect();  }, [roomId]); // ✅ So you must specify that reactive value as a dependency of your Effect  // ...}\n```\n\nExample:\n```javascript\nconst serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) {  useEffect(() => {    const connection = createConnection(serverUrl, roomId);    connection.connect();    return () => connection.disconnect();  }, []); // 🔴 React Hook useEffect has a missing dependency: 'roomId'  // ...}\n```\n\nExample:\n```javascript\nconst serverUrl = 'https://localhost:1234';const roomId = 'music'; // Not a reactive value anymorefunction ChatRoom() {  useEffect(() => {    const connection = createConnection(serverUrl, roomId);    connection.connect();    return () => connection.disconnect();  }, []); // ✅ All dependencies declared  // ...}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';\n\nconst serverUrl = 'https://localhost:1234';\nconst roomId = 'music';\n\nexport default function ChatRoom() {\n  useEffect(() => {\n    const connection = createConnection(serverUrl, roomId);\n    connection.connect();\n    return () => connection.disconnect();\n  }, []);\n  return <h1>Welcome to the {roomId} room!</h1>;\n}\n```\n\nExample:\n```javascript\nuseEffect(() => {  // ...  // 🔴 Avoid suppressing the linter like this:  // eslint-ignore-next-line react-hooks/exhaustive-deps}, []);\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\n\nexport default function Timer() {\n  const [count, setCount] = useState(0);\n  const [increment, setIncrement] = useState(1);\n\n  function onTick() {\n\tsetCount(count + increment);\n  }\n\n  useEffect(() => {\n    const id = setInterval(onTick, 1000);\n    return () => clearInterval(id);\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, []);\n\n  return (\n    <>\n      <h1>\n        Counter: {count}\n        <button onClick={() => setCount(0)}>Reset</button>\n      </h1>\n      <hr />\n      <p>\n        Every second, increment by:\n        <button disabled={increment === 0} onClick={() => {\n          setIncrement(i => i - 1);\n        }}>–</button>\n        <b>{increment}</b>\n        <button onClick={() => {\n          setIncrement(i => i + 1);\n        }}>+</button>\n      </p>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nfunction Form() {  const [submitted, setSubmitted] = useState(false);  useEffect(() => {    if (submitted) {      // 🔴 Avoid: Event-specific logic inside an Effect      post('/api/register');      showNotification('Successfully registered!');    }  }, [submitted]);  function handleSubmit() {    setSubmitted(true);  }  // ...}\n```\n\nExample:\n```javascript\nfunction Form() {  const [submitted, setSubmitted] = useState(false);  const theme = useContext(ThemeContext);  useEffect(() => {    if (submitted) {      // 🔴 Avoid: Event-specific logic inside an Effect      post('/api/register');      showNotification('Successfully registered!', theme);    }  }, [submitted, theme]); // ✅ All dependencies declared  function handleSubmit() {    setSubmitted(true);  }  // ...}\n```\n\nExample:\n```javascript\nfunction Form() {  const theme = useContext(ThemeContext);  function handleSubmit() {    // ✅ Good: Event-specific logic is called from event handlers    post('/api/register');    showNotification('Successfully registered!', theme);  }  // ...}\n```\n\nExample:\n```javascript\nfunction ShippingForm({ country }) {  const [cities, setCities] = useState(null);  const [city, setCity] = useState(null);  useEffect(() => {    let ignore = false;    fetch(`/api/cities?country=${country}`)      .then(response => response.json())      .then(json => {        if (!ignore) {          setCities(json);        }      });    return () => {      ignore = true;    };  }, [country]); // ✅ All dependencies declared  // ...\n```\n\nExample:\n```javascript\nfunction ShippingForm({ country }) {  const [cities, setCities] = useState(null);  const [city, setCity] = useState(null);  const [areas, setAreas] = useState(null);  useEffect(() => {    let ignore = false;    fetch(`/api/cities?country=${country}`)      .then(response => response.json())      .then(json => {        if (!ignore) {          setCities(json);        }      });    // 🔴 Avoid: A single Effect synchronizes two independent processes    if (city) {      fetch(`/api/areas?city=${city}`)        .then(response => response.json())        .then(json => {          if (!ignore) {            setAreas(json);          }        });    }    return () => {      ignore = true;    };  }, [country, city]); // ✅ All dependencies declared  // ...\n```\n\nExample:\n```javascript\nfunction ShippingForm({ country }) {  const [cities, setCities] = useState(null);  useEffect(() => {    let ignore = false;    fetch(`/api/cities?country=${country}`)      .then(response => response.json())      .then(json => {        if (!ignore) {          setCities(json);        }      });    return () => {      ignore = true;    };  }, [country]); // ✅ All dependencies declared  const [city, setCity] = useState(null);  const [areas, setAreas] = useState(null);  useEffect(() => {    if (city) {      let ignore = false;      fetch(`/api/areas?city=${city}`)        .then(response => response.json())        .then(json => {          if (!ignore) {            setAreas(json);          }        });      return () => {        ignore = true;      };    }  }, [city]); // ✅ All dependencies declared  // ...\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId }) {  const [messages, setMessages] = useState([]);  useEffect(() => {    const connection = createConnection();    connection.connect();    connection.on('message', (receivedMessage) => {      setMessages([...messages, receivedMessage]);    });    // ...\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId }) {  const [messages, setMessages] = useState([]);  useEffect(() => {    const connection = createConnection();    connection.connect();    connection.on('message', (receivedMessage) => {      setMessages([...messages, receivedMessage]);    });    return () => connection.disconnect();  }, [roomId, messages]); // ✅ All dependencies declared  // ...\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId }) {  const [messages, setMessages] = useState([]);  useEffect(() => {    const connection = createConnection();    connection.connect();    connection.on('message', (receivedMessage) => {      setMessages(msgs => [...msgs, receivedMessage]);    });    return () => connection.disconnect();  }, [roomId]); // ✅ All dependencies declared  // ...\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId }) {  const [messages, setMessages] = useState([]);  const [isMuted, setIsMuted] = useState(false);  useEffect(() => {    const connection = createConnection();    connection.connect();    connection.on('message', (receivedMessage) => {      setMessages(msgs => [...msgs, receivedMessage]);      if (!isMuted) {        playSound();      }    });    // ...\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId }) {  const [messages, setMessages] = useState([]);  const [isMuted, setIsMuted] = useState(false);  useEffect(() => {    const connection = createConnection();    connection.connect();    connection.on('message', (receivedMessage) => {      setMessages(msgs => [...msgs, receivedMessage]);      if (!isMuted) {        playSound();      }    });    return () => connection.disconnect();  }, [roomId, isMuted]); // ✅ All dependencies declared  // ...\n```\n\nExample:\n```javascript\nimport { useState, useEffect, useEffectEvent } from 'react';function ChatRoom({ roomId }) {  const [messages, setMessages] = useState([]);  const [isMuted, setIsMuted] = useState(false);  const onMessage = useEffectEvent(receivedMessage => {    setMessages(msgs => [...msgs, receivedMessage]);    if (!isMuted) {      playSound();    }  });  useEffect(() => {    const connection = createConnection();    connection.connect();    connection.on('message', (receivedMessage) => {      onMessage(receivedMessage);    });    return () => connection.disconnect();  }, [roomId]); // ✅ All dependencies declared  // ...\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId, onReceiveMessage }) {  const [messages, setMessages] = useState([]);  useEffect(() => {    const connection = createConnection();    connection.connect();    connection.on('message', (receivedMessage) => {      onReceiveMessage(receivedMessage);    });    return () => connection.disconnect();  }, [roomId, onReceiveMessage]); // ✅ All dependencies declared  // ...\n```\n\nExample:\n```javascript\n<ChatRoom  roomId={roomId}  onReceiveMessage={receivedMessage => {    // ...  }}/>\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId, onReceiveMessage }) {  const [messages, setMessages] = useState([]);  const onMessage = useEffectEvent(receivedMessage => {    onReceiveMessage(receivedMessage);  });  useEffect(() => {    const connection = createConnection();    connection.connect();    connection.on('message', (receivedMessage) => {      onMessage(receivedMessage);    });    return () => connection.disconnect();  }, [roomId]); // ✅ All dependencies declared  // ...\n```\n\nExample:\n```javascript\nfunction Chat({ roomId, notificationCount }) {  const onVisit = useEffectEvent(visitedRoomId => {    logVisit(visitedRoomId, notificationCount);  });  useEffect(() => {    onVisit(roomId);  }, [roomId]); // ✅ All dependencies declared  // ...}\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId }) {  // ...  const options = {    serverUrl: serverUrl,    roomId: roomId  };  useEffect(() => {    const connection = createConnection(options);    connection.connect();    // ...\n```\n\nExample:\n```javascript\n// ...  useEffect(() => {    const connection = createConnection(options);    connection.connect();    return () => connection.disconnect();  }, [options]); // ✅ All dependencies declared  // ...\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';\n\nconst serverUrl = 'https://localhost:1234';\n\nfunction ChatRoom({ roomId }) {\n  const [message, setMessage] = useState('');\n\n  // Temporarily disable the linter to demonstrate the problem\n  // eslint-disable-next-line react-hooks/exhaustive-deps\n  const options = {\n    serverUrl: serverUrl,\n    roomId: roomId\n  };\n\n  useEffect(() => {\n    const connection = createConnection(options);\n    connection.connect();\n    return () => connection.disconnect();\n  }, [options]);\n\n  return (\n    <>\n      <h1>Welcome to the {roomId} room!</h1>\n      <input value={message} onChange={e => setMessage(e.target.value)} />\n    </>\n  );\n}\n\nexport default function App() {\n  const [roomId, setRoomId] = useState('general');\n  return (\n    <>\n      <label>\n        Choose the chat room:{' '}\n        <select\n          value={roomId}\n          onChange={e => setRoomId(e.target.value)}\n        >\n          <option value=\"general\">general</option>\n          <option value=\"travel\">travel</option>\n          <option value=\"music\">music</option>\n        </select>\n      </label>\n      <hr />\n      <ChatRoom roomId={roomId} />\n    </>\n  );\n}\n```\n\nExample:\n```javascript\n// During the first renderconst options1 = { serverUrl: 'https://localhost:1234', roomId: 'music' };// During the next renderconst options2 = { serverUrl: 'https://localhost:1234', roomId: 'music' };// These are two different objects!console.log(Object.is(options1, options2)); // false\n```\n\nExample:\n```javascript\nconst options = {  serverUrl: 'https://localhost:1234',  roomId: 'music'};function ChatRoom() {  const [message, setMessage] = useState('');  useEffect(() => {    const connection = createConnection(options);    connection.connect();    return () => connection.disconnect();  }, []); // ✅ All dependencies declared  // ...\n```\n\nExample:\n```javascript\nfunction createOptions() {  return {    serverUrl: 'https://localhost:1234',    roomId: 'music'  };}function ChatRoom() {  const [message, setMessage] = useState('');  useEffect(() => {    const options = createOptions();    const connection = createConnection(options);    connection.connect();    return () => connection.disconnect();  }, []); // ✅ All dependencies declared  // ...\n```\n\nExample:\n```javascript\nconst serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) {  const [message, setMessage] = useState('');  useEffect(() => {    const options = {      serverUrl: serverUrl,      roomId: roomId    };    const connection = createConnection(options);    connection.connect();    return () => connection.disconnect();  }, [roomId]); // ✅ All dependencies declared  // ...\n```\n\nExample:\n```javascript\n// During the first renderconst roomId1 = 'music';// During the next renderconst roomId2 = 'music';// These two strings are the same!console.log(Object.is(roomId1, roomId2)); // true\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';\n\nconst serverUrl = 'https://localhost:1234';\n\nfunction ChatRoom({ roomId }) {\n  const [message, setMessage] = useState('');\n\n  useEffect(() => {\n    const options = {\n      serverUrl: serverUrl,\n      roomId: roomId\n    };\n    const connection = createConnection(options);\n    connection.connect();\n    return () => connection.disconnect();\n  }, [roomId]);\n\n  return (\n    <>\n      <h1>Welcome to the {roomId} room!</h1>\n      <input value={message} onChange={e => setMessage(e.target.value)} />\n    </>\n  );\n}\n\nexport default function App() {\n  const [roomId, setRoomId] = useState('general');\n  return (\n    <>\n      <label>\n        Choose the chat room:{' '}\n        <select\n          value={roomId}\n          onChange={e => setRoomId(e.target.value)}\n        >\n          <option value=\"general\">general</option>\n          <option value=\"travel\">travel</option>\n          <option value=\"music\">music</option>\n        </select>\n      </label>\n      <hr />\n      <ChatRoom roomId={roomId} />\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nconst serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) {  const [message, setMessage] = useState('');  useEffect(() => {    function createOptions() {      return {        serverUrl: serverUrl,        roomId: roomId      };    }    const options = createOptions();    const connection = createConnection(options);    connection.connect();    return () => connection.disconnect();  }, [roomId]); // ✅ All dependencies declared  // ...\n```\n\nExample:\n```javascript\nfunction ChatRoom({ options }) {  const [message, setMessage] = useState('');  useEffect(() => {    const connection = createConnection(options);    connection.connect();    return () => connection.disconnect();  }, [options]); // ✅ All dependencies declared  // ...\n```\n\nExample:\n```javascript\n<ChatRoom  roomId={roomId}  options={{    serverUrl: serverUrl,    roomId: roomId  }}/>\n```\n\nExample:\n```javascript\nfunction ChatRoom({ options }) {  const [message, setMessage] = useState('');  const { roomId, serverUrl } = options;  useEffect(() => {    const connection = createConnection({      roomId: roomId,      serverUrl: serverUrl    });    connection.connect();    return () => connection.disconnect();  }, [roomId, serverUrl]); // ✅ All dependencies declared  // ...\n```\n\nExample:\n```javascript\n<ChatRoom  roomId={roomId}  getOptions={() => {    return {      serverUrl: serverUrl,      roomId: roomId    };  }}/>\n```\n\nExample:\n```javascript\nfunction ChatRoom({ getOptions }) {  const [message, setMessage] = useState('');  const { roomId, serverUrl } = getOptions();  useEffect(() => {    const connection = createConnection({      roomId: roomId,      serverUrl: serverUrl    });    connection.connect();    return () => connection.disconnect();  }, [roomId, serverUrl]); // ✅ All dependencies declared  // ...\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\n\nexport default function Timer() {\n  const [count, setCount] = useState(0);\n\n  useEffect(() => {\n    console.log('✅ Creating an interval');\n    const id = setInterval(() => {\n      console.log('⏰ Interval tick');\n      setCount(count + 1);\n    }, 1000);\n    return () => {\n      console.log('❌ Clearing an interval');\n      clearInterval(id);\n    };\n  }, [count]);\n\n  return <h1>Counter: {count}</h1>\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.910Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":42,"totalLines":438,"estimatedTokens":13782}}35{"id":"doc-you_might_not_need_an_effect_react-8b892800","source":"documentation","title":"You Might Not Need an Effect – React","url":"https://react.dev/learn/you-might-not-need-an-effect","text":"Example:\n```javascript\nfunction Form() {  const [firstName, setFirstName] = useState('Taylor');  const [lastName, setLastName] = useState('Swift');  // 🔴 Avoid: redundant state and unnecessary Effect  const [fullName, setFullName] = useState('');  useEffect(() => {    setFullName(firstName + ' ' + lastName);  }, [firstName, lastName]);  // ...}\n```\n\nExample:\n```javascript\nfunction Form() {  const [firstName, setFirstName] = useState('Taylor');  const [lastName, setLastName] = useState('Swift');  // ✅ Good: calculated during rendering  const fullName = firstName + ' ' + lastName;  // ...}\n```\n\nExample:\n```javascript\nfunction TodoList({ todos, filter }) {  const [newTodo, setNewTodo] = useState('');  // 🔴 Avoid: redundant state and unnecessary Effect  const [visibleTodos, setVisibleTodos] = useState([]);  useEffect(() => {    setVisibleTodos(getFilteredTodos(todos, filter));  }, [todos, filter]);  // ...}\n```\n\nExample:\n```javascript\nfunction TodoList({ todos, filter }) {  const [newTodo, setNewTodo] = useState('');  // ✅ This is fine if getFilteredTodos() is not slow.  const visibleTodos = getFilteredTodos(todos, filter);  // ...}\n```\n\nExample:\n```javascript\nimport { useMemo, useState } from 'react';function TodoList({ todos, filter }) {  const [newTodo, setNewTodo] = useState('');  const visibleTodos = useMemo(() => {    // ✅ Does not re-run unless todos or filter change    return getFilteredTodos(todos, filter);  }, [todos, filter]);  // ...}\n```\n\nExample:\n```javascript\nimport { useMemo, useState } from 'react';function TodoList({ todos, filter }) {  const [newTodo, setNewTodo] = useState('');  // ✅ Does not re-run getFilteredTodos() unless todos or filter change  const visibleTodos = useMemo(() => getFilteredTodos(todos, filter), [todos, filter]);  // ...}\n```\n\nExample:\n```javascript\nconsole.time('filter array');const visibleTodos = getFilteredTodos(todos, filter);console.timeEnd('filter array');\n```\n\nExample:\n```javascript\nconsole.time('filter array');const visibleTodos = useMemo(() => {  return getFilteredTodos(todos, filter); // Skipped if todos and filter haven't changed}, [todos, filter]);console.timeEnd('filter array');\n```\n\nExample:\n```javascript\nexport default function ProfilePage({ userId }) {  const [comment, setComment] = useState('');  // 🔴 Avoid: Resetting state on prop change in an Effect  useEffect(() => {    setComment('');  }, [userId]);  // ...}\n```\n\nExample:\n```javascript\nexport default function ProfilePage({ userId }) {  return (    <Profile      userId={userId}      key={userId}    />  );}function Profile({ userId }) {  // ✅ This and any other state below will reset on key change automatically  const [comment, setComment] = useState('');  // ...}\n```\n\nExample:\n```javascript\nfunction List({ items }) {  const [isReverse, setIsReverse] = useState(false);  const [selection, setSelection] = useState(null);  // 🔴 Avoid: Adjusting state on prop change in an Effect  useEffect(() => {    setSelection(null);  }, [items]);  // ...}\n```\n\nExample:\n```javascript\nfunction List({ items }) {  const [isReverse, setIsReverse] = useState(false);  const [selection, setSelection] = useState(null);  // Better: Adjust the state while rendering  const [prevItems, setPrevItems] = useState(items);  if (items !== prevItems) {    setPrevItems(items);    setSelection(null);  }  // ...}\n```\n\nExample:\n```javascript\nfunction List({ items }) {  const [isReverse, setIsReverse] = useState(false);  const [selectedId, setSelectedId] = useState(null);  // ✅ Best: Calculate everything during rendering  const selection = items.find(item => item.id === selectedId) ?? null;  // ...}\n```\n\nExample:\n```javascript\nfunction ProductPage({ product, addToCart }) {  // 🔴 Avoid: Event-specific logic inside an Effect  useEffect(() => {    if (product.isInCart) {      showNotification(`Added ${product.name} to the shopping cart!`);    }  }, [product]);  function handleBuyClick() {    addToCart(product);  }  function handleCheckoutClick() {    addToCart(product);    navigateTo('/checkout');  }  // ...}\n```\n\nExample:\n```javascript\nfunction ProductPage({ product, addToCart }) {  // ✅ Good: Event-specific logic is called from event handlers  function buyProduct() {    addToCart(product);    showNotification(`Added ${product.name} to the shopping cart!`);  }  function handleBuyClick() {    buyProduct();  }  function handleCheckoutClick() {    buyProduct();    navigateTo('/checkout');  }  // ...}\n```\n\nExample:\n```javascript\nfunction Form() {  const [firstName, setFirstName] = useState('');  const [lastName, setLastName] = useState('');  // ✅ Good: This logic should run because the component was displayed  useEffect(() => {    post('/analytics/event', { eventName: 'visit_form' });  }, []);  // 🔴 Avoid: Event-specific logic inside an Effect  const [jsonToSubmit, setJsonToSubmit] = useState(null);  useEffect(() => {    if (jsonToSubmit !== null) {      post('/api/register', jsonToSubmit);    }  }, [jsonToSubmit]);  function handleSubmit(e) {    e.preventDefault();    setJsonToSubmit({ firstName, lastName });  }  // ...}\n```\n\nExample:\n```javascript\nfunction Form() {  const [firstName, setFirstName] = useState('');  const [lastName, setLastName] = useState('');  // ✅ Good: This logic runs because the component was displayed  useEffect(() => {    post('/analytics/event', { eventName: 'visit_form' });  }, []);  function handleSubmit(e) {    e.preventDefault();    // ✅ Good: Event-specific logic is in the event handler    post('/api/register', { firstName, lastName });  }  // ...}\n```\n\nExample:\n```javascript\nfunction Game() {  const [card, setCard] = useState(null);  const [goldCardCount, setGoldCardCount] = useState(0);  const [round, setRound] = useState(1);  const [isGameOver, setIsGameOver] = useState(false);  // 🔴 Avoid: Chains of Effects that adjust the state solely to trigger each other  useEffect(() => {    if (card !== null && card.gold) {      setGoldCardCount(c => c + 1);    }  }, [card]);  useEffect(() => {    if (goldCardCount > 3) {      setRound(r => r + 1)      setGoldCardCount(0);    }  }, [goldCardCount]);  useEffect(() => {    if (round > 5) {      setIsGameOver(true);    }  }, [round]);  useEffect(() => {    alert('Good game!');  }, [isGameOver]);  function handlePlaceCard(nextCard) {    if (isGameOver) {      throw Error('Game already ended.');    } else {      setCard(nextCard);    }  }  // ...\n```\n\nExample:\n```javascript\nfunction Game() {  const [card, setCard] = useState(null);  const [goldCardCount, setGoldCardCount] = useState(0);  const [round, setRound] = useState(1);  // ✅ Calculate what you can during rendering  const isGameOver = round > 5;  function handlePlaceCard(nextCard) {    if (isGameOver) {      throw Error('Game already ended.');    }    // ✅ Calculate all the next state in the event handler    setCard(nextCard);    if (nextCard.gold) {      if (goldCardCount < 3) {        setGoldCardCount(goldCardCount + 1);      } else {        setGoldCardCount(0);        setRound(round + 1);        if (round === 5) {          alert('Good game!');        }      }    }  }  // ...\n```\n\nExample:\n```javascript\nfunction App() {  // 🔴 Avoid: Effects with logic that should only ever run once  useEffect(() => {    loadDataFromLocalStorage();    checkAuthToken();  }, []);  // ...}\n```\n\nExample:\n```javascript\nlet didInit = false;function App() {  useEffect(() => {    if (!didInit) {      didInit = true;      // ✅ Only runs once per app load      loadDataFromLocalStorage();      checkAuthToken();    }  }, []);  // ...}\n```\n\nExample:\n```javascript\nif (typeof window !== 'undefined') { // Check if we're running in the browser.   // ✅ Only runs once per app load  checkAuthToken();  loadDataFromLocalStorage();}function App() {  // ...}\n```\n\nExample:\n```javascript\nfunction Toggle({ onChange }) {  const [isOn, setIsOn] = useState(false);  // 🔴 Avoid: The onChange handler runs too late  useEffect(() => {    onChange(isOn);  }, [isOn, onChange])  function handleClick() {    setIsOn(!isOn);  }  function handleDragEnd(e) {    if (isCloserToRightEdge(e)) {      setIsOn(true);    } else {      setIsOn(false);    }  }  // ...}\n```\n\nExample:\n```javascript\nfunction Toggle({ onChange }) {  const [isOn, setIsOn] = useState(false);  function updateToggle(nextIsOn) {    // ✅ Good: Perform all updates during the event that caused them    setIsOn(nextIsOn);    onChange(nextIsOn);  }  function handleClick() {    updateToggle(!isOn);  }  function handleDragEnd(e) {    if (isCloserToRightEdge(e)) {      updateToggle(true);    } else {      updateToggle(false);    }  }  // ...}\n```\n\nExample:\n```javascript\n// ✅ Also good: the component is fully controlled by its parentfunction Toggle({ isOn, onChange }) {  function handleClick() {    onChange(!isOn);  }  function handleDragEnd(e) {    if (isCloserToRightEdge(e)) {      onChange(true);    } else {      onChange(false);    }  }  // ...}\n```\n\nExample:\n```javascript\nfunction Parent() {  const [data, setData] = useState(null);  // ...  return <Child onFetched={setData} />;}function Child({ onFetched }) {  const data = useSomeAPI();  // 🔴 Avoid: Passing data to the parent in an Effect  useEffect(() => {    if (data) {      onFetched(data);    }  }, [onFetched, data]);  // ...}\n```\n\nExample:\n```javascript\nfunction Parent() {  const data = useSomeAPI();  // ...  // ✅ Good: Passing data down to the child  return <Child data={data} />;}function Child({ data }) {  // ...}\n```\n\nExample:\n```javascript\nfunction useOnlineStatus() {  // Not ideal: Manual store subscription in an Effect  const [isOnline, setIsOnline] = useState(true);  useEffect(() => {    function updateState() {      setIsOnline(navigator.onLine);    }    updateState();    window.addEventListener('online', updateState);    window.addEventListener('offline', updateState);    return () => {      window.removeEventListener('online', updateState);      window.removeEventListener('offline', updateState);    };  }, []);  return isOnline;}function ChatIndicator() {  const isOnline = useOnlineStatus();  // ...}\n```\n\nExample:\n```javascript\nfunction subscribe(callback) {  window.addEventListener('online', callback);  window.addEventListener('offline', callback);  return () => {    window.removeEventListener('online', callback);    window.removeEventListener('offline', callback);  };}function useOnlineStatus() {  // ✅ Good: Subscribing to an external store with a built-in Hook  return useSyncExternalStore(    subscribe, // React won't resubscribe for as long as you pass the same function    () => navigator.onLine, // How to get the value on the client    () => true // How to get the value on the server  );}function ChatIndicator() {  const isOnline = useOnlineStatus();  // ...}\n```\n\nExample:\n```javascript\nfunction SearchResults({ query }) {  const [results, setResults] = useState([]);  const [page, setPage] = useState(1);  useEffect(() => {    // 🔴 Avoid: Fetching without cleanup logic    fetchResults(query, page).then(json => {      setResults(json);    });  }, [query, page]);  function handleNextPageClick() {    setPage(page + 1);  }  // ...}\n```\n\nExample:\n```javascript\nfunction SearchResults({ query }) {  const [results, setResults] = useState([]);  const [page, setPage] = useState(1);  useEffect(() => {    let ignore = false;    fetchResults(query, page).then(json => {      if (!ignore) {        setResults(json);      }    });    return () => {      ignore = true;    };  }, [query, page]);  function handleNextPageClick() {    setPage(page + 1);  }  // ...}\n```\n\nExample:\n```javascript\nfunction SearchResults({ query }) {  const [page, setPage] = useState(1);  const params = new URLSearchParams({ query, page });  const results = useData(`/api/search?${params}`);  function handleNextPageClick() {    setPage(page + 1);  }  // ...}function useData(url) {  const [data, setData] = useState(null);  useEffect(() => {    let ignore = false;    fetch(url)      .then(response => response.json())      .then(json => {        if (!ignore) {          setData(json);        }      });    return () => {      ignore = true;    };  }, [url]);  return data;}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { initialTodos, createTodo } from './todos.js';\n\nexport default function TodoList() {\n  const [todos, setTodos] = useState(initialTodos);\n  const [showActive, setShowActive] = useState(false);\n  const [activeTodos, setActiveTodos] = useState([]);\n  const [visibleTodos, setVisibleTodos] = useState([]);\n  const [footer, setFooter] = useState(null);\n\n  useEffect(() => {\n    setActiveTodos(todos.filter(todo => !todo.completed));\n  }, [todos]);\n\n  useEffect(() => {\n    setVisibleTodos(showActive ? activeTodos : todos);\n  }, [showActive, todos, activeTodos]);\n\n  useEffect(() => {\n    setFooter(\n      <footer>\n        {activeTodos.length} todos left\n      </footer>\n    );\n  }, [activeTodos]);\n\n  return (\n    <>\n      <label>\n        <input\n          type=\"checkbox\"\n          checked={showActive}\n          onChange={e => setShowActive(e.target.checked)}\n        />\n        Show only active todos\n      </label>\n      <NewTodo onAdd={newTodo => setTodos([...todos, newTodo])} />\n      <ul>\n        {visibleTodos.map(todo => (\n          <li key={todo.id}>\n            {todo.completed ? <s>{todo.text}</s> : todo.text}\n          </li>\n        ))}\n      </ul>\n      {footer}\n    </>\n  );\n}\n\nfunction NewTodo({ onAdd }) {\n  const [text, setText] = useState('');\n\n  function handleAddClick() {\n    setText('');\n    onAdd(createTodo(text));\n  }\n\n  return (\n    <>\n      <input value={text} onChange={e => setText(e.target.value)} />\n      <button onClick={handleAddClick}>\n        Add\n      </button>\n    </>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.913Z","totalSectionsIncluded":0,"totalCodeBlocksIncluded":33,"totalLines":231,"estimatedTokens":3430}}36{"id":"doc-choosing_the_state_structure_react-75363447","source":"documentation","title":"Choosing the State Structure – React","url":"https://react.dev/learn/choosing-the-state-structure","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactManaging StateCopy pageCopyChoosing the State StructureStructuring state well can make a difference between a component that is pleasant to modify and debug, and one that is a constant source of bugs. Here are some tips you should consider when structuring state. You will learn When to use a single vs multiple state variables What to avoid when organizing state How to fix common issues with the state structure Principles for structuring state When you write a component that holds some state, you’ll have to make choices about how many state variables to use and what the shape of their data should be. While it’s possible to write correct programs even with a suboptimal state structure, there are a few principles that can guide you to make better related state. If you always update two or more state variables at the same time, consider merging them into a single state variable. Avoid contradictions in state. When the state is structured in a way that several pieces of state may contradict and “disagree” with each other, you leave room for mistakes. Try to avoid this. Avoid redundant state. If you can calculate some information from the component’s props or its existing state variables during rendering, you should not put that information into that component’s state. Avoid duplication in state. When the same data is duplicated between multiple state variables, or within nested objects, it is difficult to keep them in sync. Reduce duplication when you can. Avoid deeply nested state. Deeply hierarchical state is not very convenient to update. When possible, prefer to structure state in a flat way. The goal behind these principles is to make state easy to update without introducing mistakes. Removing redundant and duplicate data from state helps ensure that all its pieces stay in sync. This is similar to how a database engineer might want to “normalize” the database structure to reduce the chance of bugs. To paraphrase Albert Einstein, “Make your state as simple as it can be—but no simpler.” Now let’s see how these principles apply in action. Group related state You might sometimes be unsure between using a single or multiple state variables. Should you do this? const [x, setX] = useState(0);const [y, setY] = useState(0); Or this? const [position, setPosition] = useState({ , }); Technically, you can use either of these approaches. But if some two state variables always change together, it might be a good idea to unify them into a single state variable. Then you won’t forget to always keep them in sync, like in this example where moving the cursor updates both coordinates of the red { useState } from 'react'; export default function MovingDot() { const [position, setPosition] = useState({ , }); return ( <div onPointerMove={e => { setPosition({ , }); }} style={{ position: 'relative', width: '100vw', height: '100vh', }}> <div style={{ position: 'absolute', backgroundColor: 'red', borderRadius: '50%', transform: `translate(${position.x}px, ${position.y}px)`, , , , , }} /> </div> ) } Show more Another case where you’ll group data into an object or an array is when you don’t know how many pieces of state you’ll need. For example, it’s helpful when you have a form where the user can add custom fields. PitfallIf your state variable is an object, remember that you can’t update only one field in it without explicitly copying the other fields. For example, you can’t do setPosition({ }) in the above example because it would not have the y property at all! Instead, if you wanted to set x alone, you would either do setPosition({ ...position, }), or split them into two state variables and do setX(100). Avoid contradictions in state Here is a hotel feedback form with isSending and isSent state { useState } from 'react'; export default function FeedbackForm() { const [text, setText] = useState(''); const [isSending, setIsSending] = useState(false); const [isSent, setIsSent] = useState(false); async function handleSubmit(e) { e.preventDefault(); setIsSending(true); await sendMessage(text); setIsSending(false); setIsSent(true); } if (isSent) { return <h1>Thanks for feedback!</h1> } return ( <form onSubmit={handleSubmit}> <p>How was your stay at The Prancing Pony?</p> <textarea disabled={isSending} value={text} onChange={e => setText(e.target.value)} /> <br /> <button disabled={isSending} type=\"submit\" > Send </button> {isSending && <p>Sending...</p>} </form> ); } // Pretend to send a message. function sendMessage(text) { return new Promise(resolve => { setTimeout(resolve, 2000); }); } Show more While this code works, it leaves the door open for “impossible” states. For example, if you forget to call setIsSent and setIsSending together, you may end up in a situation where both isSending and isSent are true at the same time. The more complex your component is, the harder it is to understand what happened. Since isSending and isSent should never be true at the same time, it is better to replace them with one status state variable that may take one of three valid states: 'typing' (initial), 'sending', and 'sent': App.jsApp.jsReloadClearForkimport { useState } from 'react'; export default function FeedbackForm() { const [text, setText] = useState(''); const [status, setStatus] = useState('typing'); async function handleSubmit(e) { e.preventDefault(); setStatus('sending'); await sendMessage(text); setStatus('sent'); } const isSending = status === 'sending'; const isSent = status === 'sent'; if (isSent) { return <h1>Thanks for feedback!</h1> } return ( <form onSubmit={handleSubmit}> <p>How was your stay at The Prancing Pony?</p> <textarea disabled={isSending} value={text} onChange={e => setText(e.target.value)} /> <br /> <button disabled={isSending} type=\"submit\" > Send </button> {isSending && <p>Sending...</p>} </form> ); } // Pretend to send a message. function sendMessage(text) { return new Promise(resolve => { setTimeout(resolve, 2000); }); } Show more You can still declare some constants for isSending = status === 'sending';const isSent = status === 'sent'; But they’re not state variables, so you don’t need to worry about them getting out of sync with each other. Avoid redundant state If you can calculate some information from the component’s props or its existing state variables during rendering, you should not put that information into that component’s state. For example, take this form. It works, but can you find any redundant state in it? App.jsApp.jsReloadClearForkimport { useState } from 'react'; export default function Form() { const [firstName, setFirstName] = useState(''); const [lastName, setLastName] = useState(''); const [fullName, setFullName] = useState(''); function handleFirstNameChange(e) { setFirstName(e.target.value); setFullName(e.target.value + ' ' + lastName); } function handleLastNameChange(e) { setLastName(e.target.value); setFullName(firstName + ' ' + e.target.value); } return ( <> <h2>Let’s check you in</h2> <label> First name:{' '} <input value={firstName} onChange={handleFirstNameChange} /> </label> <label> Last name:{' '} <input value={lastName} onChange={handleLastNameChange} /> </label> <p> Your ticket will be issued to: <b>{fullName}</b> </p> </> ); } Show more This form has three state , lastName, and fullName. However, fullName is redundant. You can always calculate fullName from firstName and lastName during render, so remove it from state. This is how you can do { useState } from 'react'; export default function Form() { const [firstName, setFirstName] = useState(''); const [lastName, setLastName] = useState(''); const fullName = firstName + ' ' + lastName; function handleFirstNameChange(e) { setFirstName(e.target.value); } function handleLastNameChange(e) { setLastName(e.target.value); } return ( <> <h2>Let’s check you in</h2> <label> First name:{' '} <input value={firstName} onChange={handleFirstNameChange} /> </label> <label> Last name:{' '} <input value={lastName} onChange={handleLastNameChange} /> </label> <p> Your ticket will be issued to: <b>{fullName}</b> </p> </> ); } Show more Here, fullName is not a state variable. Instead, it’s calculated during fullName = firstName + ' ' + lastName; As a result, the change handlers don’t need to do anything special to update it. When you call setFirstName or setLastName, you trigger a re-render, and then the next fullName will be calculated from the fresh data. Deep DiveDon’t mirror props in state Show DetailsA common example of redundant state is code like Message({ messageColor }) { const [color, setColor] = useState(messageColor);Here, a color state variable is initialized to the messageColor prop. The problem is that if the parent component passes a different value of messageColor later (for example, 'red' instead of 'blue'), the color state variable would not be updated! The state is only initialized during the first render.This is why “mirroring” some prop in a state variable can lead to confusion. Instead, use the messageColor prop directly in your code. If you want to give it a shorter name, use a Message({ messageColor }) { const color = messageColor;This way it won’t get out of sync with the prop passed from the parent component.”Mirroring” props into state only makes sense when you want to ignore all updates for a specific prop. By convention, start the prop name with initial or default to clarify that its new values are Message({ initialColor }) { // The `color` state variable holds the *first* value of `initialColor`. // Further changes to the `initialColor` prop are ignored. const [color, setColor] = useState(initialColor); Avoid duplication in state This menu list component lets you choose a single travel snack out of { useState } from 'react'; const initialItems = [ { title: 'pretzels', }, { title: 'crispy seaweed', }, { title: 'granola bar', }, ]; export default function Menu() { const [items, setItems] = useState(initialItems); const [selectedItem, setSelectedItem] = useState( items[0] ); return ( <> <h2>What's your travel snack?</h2> <ul> {items.map(item => ( <li key={item.id}> {item.title} {' '} <button onClick={() => { setSelectedItem(item); }}>Choose</button> </li> ))} </ul> <p>You picked {selectedItem.title}.</p> </> ); } Show more Currently, it stores the selected item as an object in the selectedItem state variable. However, this is not contents of the selectedItem is the same object as one of the items inside the items list. This means that the information about the item itself is duplicated in two places. Why is this a problem? Let’s make each item { useState } from 'react'; const initialItems = [ { title: 'pretzels', }, { title: 'crispy seaweed', }, { title: 'granola bar', }, ]; export default function Menu() { const [items, setItems] = useState(initialItems); const [selectedItem, setSelectedItem] = useState( items[0] ); function handleItemChange(id, e) { setItems(items.map(item => { if (item.id === id) { return { ...item, , }; } else { return item; } })); } return ( <> <h2>What's your travel snack?</h2> <ul> {items.map((item, index) => ( <li key={item.id}> <input value={item.title} onChange={e => { handleItemChange(item.id, e) }} /> {' '} <button onClick={() => { setSelectedItem(item); }}>Choose</button> </li> ))} </ul> <p>You picked {selectedItem.title}.</p> </> ); } Show more Notice how if you first click “Choose” on an item and then edit it, the input updates but the label at the bottom does not reflect the edits. This is because you have duplicated state, and you forgot to update selectedItem. Although you could update selectedItem too, an easier fix is to remove duplication. In this example, instead of a selectedItem object (which creates a duplication with objects inside items), you hold the selectedId in state, and then get the selectedItem by searching the items array for an item with that { useState } from 'react'; const initialItems = [ { title: 'pretzels', }, { title: 'crispy seaweed', }, { title: 'granola bar', }, ]; export default function Menu() { const [items, setItems] = useState(initialItems); const [selectedId, setSelectedId] = useState(0); const selectedItem = items.find(item => item.id === selectedId ); function handleItemChange(id, e) { setItems(items.map(item => { if (item.id === id) { return { ...item, , }; } else { return item; } })); } return ( <> <h2>What's your travel snack?</h2> <ul> {items.map((item, index) => ( <li key={item.id}> <input value={item.title} onChange={e => { handleItemChange(item.id, e) }} /> {' '} <button onClick={() => { setSelectedId(item.id); }}>Choose</button> </li> ))} </ul> <p>You picked {selectedItem.title}.</p> </> ); } Show more The state used to be duplicated like = [{ , title: 'pretzels'}, ...] selectedItem = {id: 0, title: 'pretzels'} But after the change it’s like = [{ , title: 'pretzels'}, ...] selectedId = 0 The duplication is gone, and you only keep the essential state! Now if you edit the selected item, the message below will update immediately. This is because setItems triggers a re-render, and items.find(...) would find the item with the updated title. You didn’t need to hold the selected item in state, because only the selected ID is essential. The rest could be calculated during render. Avoid deeply nested state Imagine a travel plan consisting of planets, continents, and countries. You might be tempted to structure its state using nested objects and arrays, like in this const initialTravelPlan = { , title: '(Root)', childPlaces: [{ , title: 'Earth', childPlaces: [{ , title: 'Africa', childPlaces: [{ , title: 'Botswana', childPlaces: [] }, { , title: 'Egypt', childPlaces: [] }, { , title: 'Kenya', childPlaces: [] }, { , title: 'Madagascar', childPlaces: [] }, { , title: 'Morocco', childPlaces: [] }, { , title: 'Nigeria', childPlaces: [] }, { , title: 'South Africa', childPlaces: [] }] }, { , title: 'Americas', childPlaces: [{ , title: 'Argentina', childPlaces: [] }, { , title: 'Brazil', childPlaces: [] }, { , title: 'Barbados', childPlaces: [] }, { , title: 'Canada', childPlaces: [] }, { , title: 'Jamaica', childPlaces: [] }, { , title: 'Mexico', childPlaces: [] }, { , title: 'Trinidad and Tobago', childPlaces: [] }, { , title: 'Venezuela', childPlaces: [] }] }, { , title: 'Asia', childPlaces: [{ , title: 'China', childPlaces: [] }, { , title: 'India', childPlaces: [] }, { , title: 'Singapore', childPlaces: [] }, { , title: 'South Korea', childPlaces: [] }, { , title: 'Thailand', childPlaces: [] }, { , title: 'Vietnam', childPlaces: [] }] }, { , title: 'Europe', childPlaces: [{ , title: 'Croatia', childPlaces: [], }, { , title: 'France', childPlaces: [], }, { , title: 'Germany', childPlaces: [], }, { , title: 'Italy', childPlaces: [], }, { , title: 'Portugal', childPlaces: [], }, { , title: 'Spain', childPlaces: [], }, { , title: 'Turkey', childPlaces: [], }] }, { , title: 'Oceania', childPlaces: [{ , title: 'Australia', childPlaces: [], }, { , title: 'Bora Bora (French Polynesia)', childPlaces: [], }, { , title: 'Easter Island (Chile)', childPlaces: [], }, { , title: 'Fiji', childPlaces: [], }, { , title: 'Hawaii (the USA)', childPlaces: [], }, { , title: 'New Zealand', childPlaces: [], }, { , title: 'Vanuatu', childPlaces: [], }] }] }, { , title: 'Moon', childPlaces: [{ , title: 'Rheita', childPlaces: [] }, { , title: 'Piccolomini', childPlaces: [] }, { , title: 'Tycho', childPlaces: [] }] }, { , title: 'Mars', childPlaces: [{ , title: 'Corn Town', childPlaces: [] }, { , title: 'Green Hill', childPlaces: [] }] }] }; Show more Now let’s say you want to add a button to delete a place you’ve already visited. How would you go about it? Updating nested state involves making copies of objects all the way up from the part that changed. Deleting a deeply nested place would involve copying its entire parent place chain. Such code can be very verbose. If the state is too nested to update easily, consider making it “flat”. Here is one way you can restructure this data. Instead of a tree-like structure where each place has an array of its child places, you can have each place hold an array of its child place IDs. Then store a mapping from each place ID to the corresponding place. This data restructuring might remind you of seeing a database const initialTravelPlan = { 0: { , title: '(Root)', childIds: [1, 42, 46], }, 1: { , title: 'Earth', childIds: [2, 10, 19, 26, 34] }, 2: { , title: 'Africa', childIds: [3, 4, 5, 6 , 7, 8, 9] }, 3: { , title: 'Botswana', childIds: [] }, 4: { , title: 'Egypt', childIds: [] }, 5: { , title: 'Kenya', childIds: [] }, 6: { , title: 'Madagascar', childIds: [] }, 7: { , title: 'Morocco', childIds: [] }, 8: { , title: 'Nigeria', childIds: [] }, 9: { , title: 'South Africa', childIds: [] }, 10: { , title: 'Americas', childIds: [11, 12, 13, 14, 15, 16, 17, 18], }, 11: { , title: 'Argentina', childIds: [] }, 12: { , title: 'Brazil', childIds: [] }, 13: { , title: 'Barbados', childIds: [] }, 14: { , title: 'Canada', childIds: [] }, 15: { , title: 'Jamaica', childIds: [] }, 16: { , title: 'Mexico', childIds: [] }, 17: { , title: 'Trinidad and Tobago', childIds: [] }, 18: { , title: 'Venezuela', childIds: [] }, 19: { , title: 'Asia', childIds: [20, 21, 22, 23, 24, 25], }, 20: { , title: 'China', childIds: [] }, 21: { , title: 'India', childIds: [] }, 22: { , title: 'Singapore', childIds: [] }, 23: { , title: 'South Korea', childIds: [] }, 24: { , title: 'Thailand', childIds: [] }, 25: { , title: 'Vietnam', childIds: [] }, 26: { , title: 'Europe', childIds: [27, 28, 29, 30, 31, 32, 33], }, 27: { , title: 'Croatia', childIds: [] }, 28: { , title: 'France', childIds: [] }, 29: { , title: 'Germany', childIds: [] }, 30: { , title: 'Italy', childIds: [] }, 31: { , title: 'Portugal', childIds: [] }, 32: { , title: 'Spain', childIds: [] }, 33: { , title: 'Turkey', childIds: [] }, 34: { , title: 'Oceania', childIds: [35, 36, 37, 38, 39, 40, 41], }, 35: { , title: 'Australia', childIds: [] }, 36: { , title: 'Bora Bora (French Polynesia)', childIds: [] }, 37: { , title: 'Easter Island (Chile)', childIds: [] }, 38: { , title: 'Fiji', childIds: [] }, 39: { , title: 'Hawaii (the USA)', childIds: [] }, 40: { , title: 'New Zealand', childIds: [] }, 41: { , title: 'Vanuatu', childIds: [] }, 42: { , title: 'Moon', childIds: [43, 44, 45] }, 43: { , title: 'Rheita', childIds: [] }, 44: { , title: 'Piccolomini', childIds: [] }, 45: { , title: 'Tycho', childIds: [] }, 46: { , title: 'Mars', childIds: [47, 48] }, 47: { , title: 'Corn Town', childIds: [] }, 48: { , title: 'Green Hill', childIds: [] } }; Show more Now that the state is “flat” (also known as “normalized”), updating nested items becomes easier. In order to remove a place now, you only need to update two levels of updated version of its parent place should exclude the removed ID from its childIds array. The updated version of the root “table” object should include the updated version of the parent place. Here is an example of how you could go about { useState } from 'react'; import { initialTravelPlan } from './places.js'; export default function TravelPlan() { const [plan, setPlan] = useState(initialTravelPlan); function handleComplete(parentId, childId) { const parent = plan[parentId]; // Create a new version of the parent place // that doesn't include this child ID. const nextParent = { ...parent, ); } const root = plan[0]; const planetIds = root.childIds; return ( <> <h2>Places to visit</h2> <ol> {planetIds.map(id => ( <PlaceTree key={id} id={id} parentId={0} placesById={plan} onComplete={handleComplete} /> ))} </ol> </> ); } function PlaceTree({ id, parentId, placesById, onComplete }) { const place = placesById[id]; const childIds = place.childIds; return ( <li> {place.title} <button onClick={() => { onComplete(parentId, id); }}> Complete </button> {childIds.length > 0 && <ol> {childIds.map(childId => ( <PlaceTree key={childId} id={childId} parentId={id} placesById={placesById} onComplete={onComplete} /> ))} </ol> } </li> ); } Show more You can nest state as much as you like, but making it “flat” can solve numerous problems. It makes state easier to update, and it helps ensure you don’t have duplication in different parts of a nested object. Deep DiveImproving memory usage Show DetailsIdeally, you would also remove the deleted items (and their children!) from the “table” object to improve memory usage. This version does that. It also uses Immer to make the update logic more concise.package.jsonApp.jsplaces.jspackage.jsonReloadClearFork{ \"dependencies\": { \"immer\": \"1.7.3\", \"react\": \"latest\", \"react-dom\": \"latest\", \"react-scripts\": \"latest\", \"use-immer\": \"0.5.1\" }, \"scripts\": { \"start\": \"react-scripts start\", \"build\": \"react-scripts build\", \"test\": \"react-scripts test --env=jsdom\", \"eject\": \"react-scripts eject\" }, \"devDependencies\": {} } Sometimes, you can also reduce state nesting by moving some of the nested state into the child components. This works well for ephemeral UI state that doesn’t need to be stored, like whether an item is hovered. Recap If two state variables always update together, consider merging them into one. Choose your state variables carefully to avoid creating “impossible” states. Structure your state in a way that reduces the chances that you’ll make a mistake updating it. Avoid redundant and duplicate state so that you don’t need to keep it in sync. Don’t put props into state unless you specifically want to prevent updates. For UI patterns like selection, keep ID or index in state instead of the object itself. If updating deeply nested state is complicated, try flattening it. Try out some challenges1. Fix a component that’s not updating 2. Fix a broken packing list 3. Fix the disappearing selection 4. Implement multiple selection Challenge 1 of a component that’s not updating This Clock component receives two and time. When you select a different color in the select box, the Clock component receives a different color prop from its parent component. However, for some reason, the displayed color doesn’t update. Why? Fix the problem.Clock.jsClock.jsReloadClearForkimport { useState } from 'react'; export default function Clock(props) { const [color, setColor] = useState(props.color); return ( <h1 style={{ }}> {props.time} </h1> ); } Show solutionNext ChallengePreviousReacting to Input with StateNextSharing State Between ComponentsCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewPrinciples for structuring state Group related state Avoid contradictions in state Avoid redundant state Avoid duplication in state Avoid deeply nested state RecapChallenges\n\nExample:\n```javascript\nconst [x, setX] = useState(0);const [y, setY] = useState(0);\n```\n\nExample:\n```javascript\nconst [position, setPosition] = useState({ x: 0, y: 0 });\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function MovingDot() {\n  const [position, setPosition] = useState({\n    x: 0,\n    y: 0\n  });\n  return (\n    <div\n      onPointerMove={e => {\n        setPosition({\n          x: e.clientX,\n          y: e.clientY\n        });\n      }}\n      style={{\n        position: 'relative',\n        width: '100vw',\n        height: '100vh',\n      }}>\n      <div style={{\n        position: 'absolute',\n        backgroundColor: 'red',\n        borderRadius: '50%',\n        transform: `translate(${position.x}px, ${position.y}px)`,\n        left: -10,\n        top: -10,\n        width: 20,\n        height: 20,\n      }} />\n    </div>\n  )\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function FeedbackForm() {\n  const [text, setText] = useState('');\n  const [isSending, setIsSending] = useState(false);\n  const [isSent, setIsSent] = useState(false);\n\n  async function handleSubmit(e) {\n    e.preventDefault();\n    setIsSending(true);\n    await sendMessage(text);\n    setIsSending(false);\n    setIsSent(true);\n  }\n\n  if (isSent) {\n    return <h1>Thanks for feedback!</h1>\n  }\n\n  return (\n    <form onSubmit={handleSubmit}>\n      <p>How was your stay at The Prancing Pony?</p>\n      <textarea\n        disabled={isSending}\n        value={text}\n        onChange={e => setText(e.target.value)}\n      />\n      <br />\n      <button\n        disabled={isSending}\n        type=\"submit\"\n      >\n        Send\n      </button>\n      {isSending && <p>Sending...</p>}\n    </form>\n  );\n}\n\n// Pretend to send a message.\nfunction sendMessage(text) {\n  return new Promise(resolve => {\n    setTimeout(resolve, 2000);\n  });\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function FeedbackForm() {\n  const [text, setText] = useState('');\n  const [status, setStatus] = useState('typing');\n\n  async function handleSubmit(e) {\n    e.preventDefault();\n    setStatus('sending');\n    await sendMessage(text);\n    setStatus('sent');\n  }\n\n  const isSending = status === 'sending';\n  const isSent = status === 'sent';\n\n  if (isSent) {\n    return <h1>Thanks for feedback!</h1>\n  }\n\n  return (\n    <form onSubmit={handleSubmit}>\n      <p>How was your stay at The Prancing Pony?</p>\n      <textarea\n        disabled={isSending}\n        value={text}\n        onChange={e => setText(e.target.value)}\n      />\n      <br />\n      <button\n        disabled={isSending}\n        type=\"submit\"\n      >\n        Send\n      </button>\n      {isSending && <p>Sending...</p>}\n    </form>\n  );\n}\n\n// Pretend to send a message.\nfunction sendMessage(text) {\n  return new Promise(resolve => {\n    setTimeout(resolve, 2000);\n  });\n}\n```\n\nExample:\n```javascript\nconst isSending = status === 'sending';const isSent = status === 'sent';\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Form() {\n  const [firstName, setFirstName] = useState('');\n  const [lastName, setLastName] = useState('');\n  const [fullName, setFullName] = useState('');\n\n  function handleFirstNameChange(e) {\n    setFirstName(e.target.value);\n    setFullName(e.target.value + ' ' + lastName);\n  }\n\n  function handleLastNameChange(e) {\n    setLastName(e.target.value);\n    setFullName(firstName + ' ' + e.target.value);\n  }\n\n  return (\n    <>\n      <h2>Let’s check you in</h2>\n      <label>\n        First name:{' '}\n        <input\n          value={firstName}\n          onChange={handleFirstNameChange}\n        />\n      </label>\n      <label>\n        Last name:{' '}\n        <input\n          value={lastName}\n          onChange={handleLastNameChange}\n        />\n      </label>\n      <p>\n        Your ticket will be issued to: <b>{fullName}</b>\n      </p>\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Form() {\n  const [firstName, setFirstName] = useState('');\n  const [lastName, setLastName] = useState('');\n\n  const fullName = firstName + ' ' + lastName;\n\n  function handleFirstNameChange(e) {\n    setFirstName(e.target.value);\n  }\n\n  function handleLastNameChange(e) {\n    setLastName(e.target.value);\n  }\n\n  return (\n    <>\n      <h2>Let’s check you in</h2>\n      <label>\n        First name:{' '}\n        <input\n          value={firstName}\n          onChange={handleFirstNameChange}\n        />\n      </label>\n      <label>\n        Last name:{' '}\n        <input\n          value={lastName}\n          onChange={handleLastNameChange}\n        />\n      </label>\n      <p>\n        Your ticket will be issued to: <b>{fullName}</b>\n      </p>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nconst fullName = firstName + ' ' + lastName;\n```\n\nExample:\n```javascript\nfunction Message({ messageColor }) {  const [color, setColor] = useState(messageColor);\n```\n\nExample:\n```javascript\nfunction Message({ messageColor }) {  const color = messageColor;\n```\n\nExample:\n```javascript\nfunction Message({ initialColor }) {  // The `color` state variable holds the *first* value of `initialColor`.  // Further changes to the `initialColor` prop are ignored.  const [color, setColor] = useState(initialColor);\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nconst initialItems = [\n  { title: 'pretzels', id: 0 },\n  { title: 'crispy seaweed', id: 1 },\n  { title: 'granola bar', id: 2 },\n];\n\nexport default function Menu() {\n  const [items, setItems] = useState(initialItems);\n  const [selectedItem, setSelectedItem] = useState(\n    items[0]\n  );\n\n  return (\n    <>\n      <h2>What's your travel snack?</h2>\n      <ul>\n        {items.map(item => (\n          <li key={item.id}>\n            {item.title}\n            {' '}\n            <button onClick={() => {\n              setSelectedItem(item);\n            }}>Choose</button>\n          </li>\n        ))}\n      </ul>\n      <p>You picked {selectedItem.title}.</p>\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nconst initialItems = [\n  { title: 'pretzels', id: 0 },\n  { title: 'crispy seaweed', id: 1 },\n  { title: 'granola bar', id: 2 },\n];\n\nexport default function Menu() {\n  const [items, setItems] = useState(initialItems);\n  const [selectedItem, setSelectedItem] = useState(\n    items[0]\n  );\n\n  function handleItemChange(id, e) {\n    setItems(items.map(item => {\n      if (item.id === id) {\n        return {\n          ...item,\n          title: e.target.value,\n        };\n      } else {\n        return item;\n      }\n    }));\n  }\n\n  return (\n    <>\n      <h2>What's your travel snack?</h2>\n      <ul>\n        {items.map((item, index) => (\n          <li key={item.id}>\n            <input\n              value={item.title}\n              onChange={e => {\n                handleItemChange(item.id, e)\n              }}\n            />\n            {' '}\n            <button onClick={() => {\n              setSelectedItem(item);\n            }}>Choose</button>\n          </li>\n        ))}\n      </ul>\n      <p>You picked {selectedItem.title}.</p>\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nconst initialItems = [\n  { title: 'pretzels', id: 0 },\n  { title: 'crispy seaweed', id: 1 },\n  { title: 'granola bar', id: 2 },\n];\n\nexport default function Menu() {\n  const [items, setItems] = useState(initialItems);\n  const [selectedId, setSelectedId] = useState(0);\n\n  const selectedItem = items.find(item =>\n    item.id === selectedId\n  );\n\n  function handleItemChange(id, e) {\n    setItems(items.map(item => {\n      if (item.id === id) {\n        return {\n          ...item,\n          title: e.target.value,\n        };\n      } else {\n        return item;\n      }\n    }));\n  }\n\n  return (\n    <>\n      <h2>What's your travel snack?</h2>\n      <ul>\n        {items.map((item, index) => (\n          <li key={item.id}>\n            <input\n              value={item.title}\n              onChange={e => {\n                handleItemChange(item.id, e)\n              }}\n            />\n            {' '}\n            <button onClick={() => {\n              setSelectedId(item.id);\n            }}>Choose</button>\n          </li>\n        ))}\n      </ul>\n      <p>You picked {selectedItem.title}.</p>\n    </>\n  );\n}\n```\n\nExample:\n```text\nexport const initialTravelPlan = {\n  id: 0,\n  title: '(Root)',\n  childPlaces: [{\n    id: 1,\n    title: 'Earth',\n    childPlaces: [{\n      id: 2,\n      title: 'Africa',\n      childPlaces: [{\n        id: 3,\n        title: 'Botswana',\n        childPlaces: []\n      }, {\n        id: 4,\n        title: 'Egypt',\n        childPlaces: []\n      }, {\n        id: 5,\n        title: 'Kenya',\n        childPlaces: []\n      }, {\n        id: 6,\n        title: 'Madagascar',\n        childPlaces: []\n      }, {\n        id: 7,\n        title: 'Morocco',\n        childPlaces: []\n      }, {\n        id: 8,\n        title: 'Nigeria',\n        childPlaces: []\n      }, {\n        id: 9,\n        title: 'South Africa',\n        childPlaces: []\n      }]\n    }, {\n      id: 10,\n      title: 'Americas',\n      childPlaces: [{\n        id: 11,\n        title: 'Argentina',\n        childPlaces: []\n      }, {\n        id: 12,\n        title: 'Brazil',\n        childPlaces: []\n      }, {\n        id: 13,\n        title: 'Barbados',\n        childPlaces: []\n      }, {\n        id: 14,\n        title: 'Canada',\n        childPlaces: []\n      }, {\n        id: 15,\n        title: 'Jamaica',\n        childPlaces: []\n      }, {\n        id: 16,\n        title: 'Mexico',\n        childPlaces: []\n      }, {\n        id: 17,\n        title: 'Trinidad and Tobago',\n        childPlaces: []\n      }, {\n        id: 18,\n        title: 'Venezuela',\n        childPlaces: []\n      }]\n    }, {\n      id: 19,\n      title: 'Asia',\n      childPlaces: [{\n        id: 20,\n        title: 'China',\n        childPlaces: []\n      }, {\n        id: 21,\n        title: 'India',\n        childPlaces: []\n      }, {\n        id: 22,\n        title: 'Singapore',\n        childPlaces: []\n      }, {\n        id: 23,\n        title: 'South Korea',\n        childPlaces: []\n      }, {\n        id: 24,\n        title: 'Thailand',\n        childPlaces: []\n      }, {\n        id: 25,\n        title: 'Vietnam',\n        childPlaces: []\n      }]\n    }, {\n      id: 26,\n      title: 'Europe',\n      childPlaces: [{\n        id: 27,\n        title: 'Croatia',\n        childPlaces: [],\n      }, {\n        id: 28,\n        title: 'France',\n        childPlaces: [],\n      }, {\n        id: 29,\n        title: 'Germany',\n        childPlaces: [],\n      }, {\n        id: 30,\n        title: 'Italy',\n        childPlaces: [],\n      }, {\n        id: 31,\n        title: 'Portugal',\n        childPlaces: [],\n      }, {\n        id: 32,\n        title: 'Spain',\n        childPlaces: [],\n      }, {\n        id: 33,\n        title: 'Turkey',\n        childPlaces: [],\n      }]\n    }, {\n      id: 34,\n      title: 'Oceania',\n      childPlaces: [{\n        id: 35,\n        title: 'Australia',\n        childPlaces: [],\n      }, {\n        id: 36,\n        title: 'Bora Bora (French Polynesia)',\n        childPlaces: [],\n      }, {\n        id: 37,\n        title: 'Easter Island (Chile)',\n        childPlaces: [],\n      }, {\n        id: 38,\n        title: 'Fiji',\n        childPlaces: [],\n      }, {\n        id: 39,\n        title: 'Hawaii (the USA)',\n        childPlaces: [],\n      }, {\n        id: 40,\n        title: 'New Zealand',\n        childPlaces: [],\n      }, {\n        id: 41,\n        title: 'Vanuatu',\n        childPlaces: [],\n      }]\n    }]\n  }, {\n    id: 42,\n    title: 'Moon',\n    childPlaces: [{\n      id: 43,\n      title: 'Rheita',\n      childPlaces: []\n    }, {\n      id: 44,\n      title: 'Piccolomini',\n      childPlaces: []\n    }, {\n      id: 45,\n      title: 'Tycho',\n      childPlaces: []\n    }]\n  }, {\n    id: 46,\n    title: 'Mars',\n    childPlaces: [{\n      id: 47,\n      title: 'Corn Town',\n      childPlaces: []\n    }, {\n      id: 48,\n      title: 'Green Hill',\n      childPlaces: []\n    }]\n  }]\n};\n```\n\nExample:\n```text\nexport const initialTravelPlan = {\n  0: {\n    id: 0,\n    title: '(Root)',\n    childIds: [1, 42, 46],\n  },\n  1: {\n    id: 1,\n    title: 'Earth',\n    childIds: [2, 10, 19, 26, 34]\n  },\n  2: {\n    id: 2,\n    title: 'Africa',\n    childIds: [3, 4, 5, 6 , 7, 8, 9]\n  },\n  3: {\n    id: 3,\n    title: 'Botswana',\n    childIds: []\n  },\n  4: {\n    id: 4,\n    title: 'Egypt',\n    childIds: []\n  },\n  5: {\n    id: 5,\n    title: 'Kenya',\n    childIds: []\n  },\n  6: {\n    id: 6,\n    title: 'Madagascar',\n    childIds: []\n  },\n  7: {\n    id: 7,\n    title: 'Morocco',\n    childIds: []\n  },\n  8: {\n    id: 8,\n    title: 'Nigeria',\n    childIds: []\n  },\n  9: {\n    id: 9,\n    title: 'South Africa',\n    childIds: []\n  },\n  10: {\n    id: 10,\n    title: 'Americas',\n    childIds: [11, 12, 13, 14, 15, 16, 17, 18],\n  },\n  11: {\n    id: 11,\n    title: 'Argentina',\n    childIds: []\n  },\n  12: {\n    id: 12,\n    title: 'Brazil',\n    childIds: []\n  },\n  13: {\n    id: 13,\n    title: 'Barbados',\n    childIds: []\n  },\n  14: {\n    id: 14,\n    title: 'Canada',\n    childIds: []\n  },\n  15: {\n    id: 15,\n    title: 'Jamaica',\n    childIds: []\n  },\n  16: {\n    id: 16,\n    title: 'Mexico',\n    childIds: []\n  },\n  17: {\n    id: 17,\n    title: 'Trinidad and Tobago',\n    childIds: []\n  },\n  18: {\n    id: 18,\n    title: 'Venezuela',\n    childIds: []\n  },\n  19: {\n    id: 19,\n    title: 'Asia',\n    childIds: [20, 21, 22, 23, 24, 25],\n  },\n  20: {\n    id: 20,\n    title: 'China',\n    childIds: []\n  },\n  21: {\n    id: 21,\n    title: 'India',\n    childIds: []\n  },\n  22: {\n    id: 22,\n    title: 'Singapore',\n    childIds: []\n  },\n  23: {\n    id: 23,\n    title: 'South Korea',\n    childIds: []\n  },\n  24: {\n    id: 24,\n    title: 'Thailand',\n    childIds: []\n  },\n  25: {\n    id: 25,\n    title: 'Vietnam',\n    childIds: []\n  },\n  26: {\n    id: 26,\n    title: 'Europe',\n    childIds: [27, 28, 29, 30, 31, 32, 33],\n  },\n  27: {\n    id: 27,\n    title: 'Croatia',\n    childIds: []\n  },\n  28: {\n    id: 28,\n    title: 'France',\n    childIds: []\n  },\n  29: {\n    id: 29,\n    title: 'Germany',\n    childIds: []\n  },\n  30: {\n    id: 30,\n    title: 'Italy',\n    childIds: []\n  },\n  31: {\n    id: 31,\n    title: 'Portugal',\n    childIds: []\n  },\n  32: {\n    id: 32,\n    title: 'Spain',\n    childIds: []\n  },\n  33: {\n    id: 33,\n    title: 'Turkey',\n    childIds: []\n  },\n  34: {\n    id: 34,\n    title: 'Oceania',\n    childIds: [35, 36, 37, 38, 39, 40, 41],\n  },\n  35: {\n    id: 35,\n    title: 'Australia',\n    childIds: []\n  },\n  36: {\n    id: 36,\n    title: 'Bora Bora (French Polynesia)',\n    childIds: []\n  },\n  37: {\n    id: 37,\n    title: 'Easter Island (Chile)',\n    childIds: []\n  },\n  38: {\n    id: 38,\n    title: 'Fiji',\n    childIds: []\n  },\n  39: {\n    id: 40,\n    title: 'Hawaii (the USA)',\n    childIds: []\n  },\n  40: {\n    id: 40,\n    title: 'New Zealand',\n    childIds: []\n  },\n  41: {\n    id: 41,\n    title: 'Vanuatu',\n    childIds: []\n  },\n  42: {\n    id: 42,\n    title: 'Moon',\n    childIds: [43, 44, 45]\n  },\n  43: {\n    id: 43,\n    title: 'Rheita',\n    childIds: []\n  },\n  44: {\n    id: 44,\n    title: 'Piccolomini',\n    childIds: []\n  },\n  45: {\n    id: 45,\n    title: 'Tycho',\n    childIds: []\n  },\n  46: {\n    id: 46,\n    title: 'Mars',\n    childIds: [47, 48]\n  },\n  47: {\n    id: 47,\n    title: 'Corn Town',\n    childIds: []\n  },\n  48: {\n    id: 48,\n    title: 'Green Hill',\n    childIds: []\n  }\n};\n```\n\nExample:\n```text\nimport { useState } from 'react';\nimport { initialTravelPlan } from './places.js';\n\nexport default function TravelPlan() {\n  const [plan, setPlan] = useState(initialTravelPlan);\n\n  function handleComplete(parentId, childId) {\n    const parent = plan[parentId];\n    // Create a new version of the parent place\n    // that doesn't include this child ID.\n    const nextParent = {\n      ...parent,\n      childIds: parent.childIds\n        .filter(id => id !== childId)\n    };\n    // Update the root state object...\n    setPlan({\n      ...plan,\n      // ...so that it has the updated parent.\n      [parentId]: nextParent\n    });\n  }\n\n  const root = plan[0];\n  const planetIds = root.childIds;\n  return (\n    <>\n      <h2>Places to visit</h2>\n      <ol>\n        {planetIds.map(id => (\n          <PlaceTree\n            key={id}\n            id={id}\n            parentId={0}\n            placesById={plan}\n            onComplete={handleComplete}\n          />\n        ))}\n      </ol>\n    </>\n  );\n}\n\nfunction PlaceTree({ id, parentId, placesById, onComplete }) {\n  const place = placesById[id];\n  const childIds = place.childIds;\n  return (\n    <li>\n      {place.title}\n      <button onClick={() => {\n        onComplete(parentId, id);\n      }}>\n        Complete\n      </button>\n      {childIds.length > 0 &&\n        <ol>\n          {childIds.map(childId => (\n            <PlaceTree\n              key={childId}\n              id={childId}\n              parentId={id}\n              placesById={placesById}\n              onComplete={onComplete}\n            />\n          ))}\n        </ol>\n      }\n    </li>\n  );\n}\n```\n\nExample:\n```text\n{\n  \"dependencies\": {\n    \"immer\": \"1.7.3\",\n    \"react\": \"latest\",\n    \"react-dom\": \"latest\",\n    \"react-scripts\": \"latest\",\n    \"use-immer\": \"0.5.1\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"test\": \"react-scripts test --env=jsdom\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"devDependencies\": {}\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Clock(props) {\n  const [color, setColor] = useState(props.color);\n  return (\n    <h1 style={{ color: color }}>\n      {props.time}\n    </h1>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.917Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":20,"totalLines":967,"estimatedTokens":10417}}37{"id":"doc-reusing_logic_with_custom_hooks_react-843b8436","source":"documentation","title":"Reusing Logic with Custom Hooks – React","url":"https://react.dev/learn/reusing-logic-with-custom-hooks","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactEscape HatchesCopy pageCopyReusing Logic with Custom HooksReact comes with several built-in Hooks like useState, useContext, and useEffect. Sometimes, you’ll wish that there was a Hook for some more specific example, to fetch data, to keep track of whether the user is online, or to connect to a chat room. You might not find these Hooks in React, but you can create your own Hooks for your application’s needs. You will learn What custom Hooks are, and how to write your own How to reuse logic between components How to name and structure your custom Hooks When and why to extract custom Hooks Custom logic between components Imagine you’re developing an app that heavily relies on the network (as most apps do). You want to warn the user if their network connection has accidentally gone off while they were using your app. How would you go about it? It seems like you’ll need two things in your piece of state that tracks whether the network is online. An Effect that subscribes to the global online and offline events, and updates that state. This will keep your component synchronized with the network status. You might start with something like { useState, useEffect } from 'react'; export default function StatusBar() { const [isOnline, setIsOnline] = useState(true); useEffect(() => { function handleOnline() { setIsOnline(true); } function handleOffline() { setIsOnline(false); } window.addEventListener('online', handleOnline); window.addEventListener('offline', handleOffline); return () => { window.removeEventListener('online', handleOnline); window.removeEventListener('offline', handleOffline); }; }, []); return <h1>{isOnline ? '✅ Online' : '❌ Disconnected'}</h1>; } Show more Try turning your network on and off, and notice how this StatusBar updates in response to your actions. Now imagine you also want to use the same logic in a different component. You want to implement a Save button that will become disabled and show “Reconnecting…” instead of “Save” while the network is off. To start, you can copy and paste the isOnline state and the Effect into { useState, useEffect } from 'react'; export default function SaveButton() { const [isOnline, setIsOnline] = useState(true); useEffect(() => { function handleOnline() { setIsOnline(true); } function handleOffline() { setIsOnline(false); } window.addEventListener('online', handleOnline); window.addEventListener('offline', handleOffline); return () => { window.removeEventListener('online', handleOnline); window.removeEventListener('offline', handleOffline); }; }, []); function handleSaveClick() { console.log('✅ Progress saved'); } return ( <button disabled={!isOnline} onClick={handleSaveClick}> {isOnline ? 'Save progress' : 'Reconnecting...'} </button> ); } Show more Verify that, if you turn off the network, the button will change its appearance. These two components work fine, but the duplication in logic between them is unfortunate. It seems like even though they have different visual appearance, you want to reuse the logic between them. Extracting your own custom Hook from a component Imagine for a moment that, similar to useState and useEffect, there was a built-in useOnlineStatus Hook. Then both of these components could be simplified and you could remove the duplication between StatusBar() { const isOnline = useOnlineStatus(); return <h1>{isOnline ? '✅ Online' : '❌ Disconnected'}</h1>;}function SaveButton() { const isOnline = useOnlineStatus(); function handleSaveClick() { console.log('✅ Progress saved'); } return ( <button disabled={!isOnline} onClick={handleSaveClick}> {isOnline ? 'Save progress' : 'Reconnecting...'} </button> );} Although there is no such built-in Hook, you can write it yourself. Declare a function called useOnlineStatus and move all the duplicated code into it from the components you wrote useOnlineStatus() { const [isOnline, setIsOnline] = useState(true); useEffect(() => { function handleOnline() { setIsOnline(true); } function handleOffline() { setIsOnline(false); } window.addEventListener('online', handleOnline); window.addEventListener('offline', handleOffline); return () => { window.removeEventListener('online', handleOnline); window.removeEventListener('offline', handleOffline); }; }, []); return isOnline;} At the end of the function, return isOnline. This lets your components read that { useOnlineStatus } from './useOnlineStatus.js'; function StatusBar() { const isOnline = useOnlineStatus(); return <h1>{isOnline ? '✅ Online' : '❌ Disconnected'}</h1>; } function SaveButton() { const isOnline = useOnlineStatus(); function handleSaveClick() { console.log('✅ Progress saved'); } return ( <button disabled={!isOnline} onClick={handleSaveClick}> {isOnline ? 'Save progress' : 'Reconnecting...'} </button> ); } export default function App() { return ( <> <SaveButton /> <StatusBar /> </> ); } Show more Verify that switching the network on and off updates both components. Now your components don’t have as much repetitive logic. More importantly, the code inside them describes what they want to do (use the online status!) rather than how to do it (by subscribing to the browser events). When you extract logic into custom Hooks, you can hide the gnarly details of how you deal with some external system or a browser API. The code of your components expresses your intent, not the implementation. Hook names always start with use React applications are built from components. Components are built from Hooks, whether built-in or custom. You’ll likely often use custom Hooks created by others, but occasionally you might write one yourself! You must follow these naming component names must start with a capital letter, like StatusBar and SaveButton. React components also need to return something that React knows how to display, like a piece of JSX. Hook names must start with use followed by a capital letter, like useState (built-in) or useOnlineStatus (custom, like earlier on the page). Hooks may return arbitrary values. This convention guarantees that you can always look at a component and know where its state, Effects, and other React features might “hide”. For example, if you see a getColor() function call inside your component, you can be sure that it can’t possibly contain React state inside because its name doesn’t start with use. However, a function call like useOnlineStatus() will most likely contain calls to other Hooks inside! NoteIf your linter is configured for React, it will enforce this naming convention. Scroll up to the sandbox above and rename useOnlineStatus to getOnlineStatus. Notice that the linter won’t allow you to call useState or useEffect inside of it anymore. Only Hooks and components can call other Hooks! Deep DiveShould all functions called during rendering start with the use prefix? Show DetailsNo. Functions that don’t call Hooks don’t need to be Hooks.If your function doesn’t call any Hooks, avoid the use prefix. Instead, write it as a regular function without the use prefix. For example, useSorted below doesn’t call Hooks, so call it getSorted instead:// 🔴 Hook that doesn't use Hooksfunction useSorted(items) { return items.slice().sort();}// ✅ regular function that doesn't use Hooksfunction getSorted(items) { return items.slice().sort();}This ensures that your code can call this regular function anywhere, including List({ items, shouldSort }) { let displayedItems = items; if (shouldSort) { // ✅ It's ok to call getSorted() conditionally because it's not a Hook displayedItems = getSorted(items); } // ...}You should give use prefix to a function (and thus make it a Hook) if it uses at least one Hook inside of it:// ✅ Hook that uses other Hooksfunction useAuth() { return useContext(Auth);}Technically, this isn’t enforced by React. In principle, you could make a Hook that doesn’t call other Hooks. This is often confusing and limiting so it’s best to avoid that pattern. However, there may be rare cases where it is helpful. For example, maybe your function doesn’t use any Hooks right now, but you plan to add some Hook calls to it in the future. Then it makes sense to name it with the use prefix:// ✅ Hook that will likely use some other Hooks laterfunction useAuth() { // with this line when authentication is implemented: // return useContext(Auth); return TEST_USER;}Then components won’t be able to call it conditionally. This will become important when you actually add Hook calls inside. If you don’t plan to use Hooks inside it (now or later), don’t make it a Hook. Custom Hooks let you share stateful logic, not state itself In the earlier example, when you turned the network on and off, both components updated together. However, it’s wrong to think that a single isOnline state variable is shared between them. Look at this StatusBar() { const isOnline = useOnlineStatus(); // ...}function SaveButton() { const isOnline = useOnlineStatus(); // ...} It works the same way as before you extracted the StatusBar() { const [isOnline, setIsOnline] = useState(true); useEffect(() => { // ... }, []); // ...}function SaveButton() { const [isOnline, setIsOnline] = useState(true); useEffect(() => { // ... }, []); // ...} These are two completely independent state variables and Effects! They happened to have the same value at the same time because you synchronized them with the same external value (whether the network is on). To better illustrate this, we’ll need a different example. Consider this Form { useState } from 'react'; export default function Form() { const [firstName, setFirstName] = useState('Mary'); const [lastName, setLastName] = useState('Poppins'); function handleFirstNameChange(e) { setFirstName(e.target.value); } function handleLastNameChange(e) { setLastName(e.target.value); } return ( <> <label> First name: <input value={firstName} onChange={handleFirstNameChange} /> </label> <label> Last name: <input value={lastName} onChange={handleLastNameChange} /> </label> <p><b>Good morning, {firstName} {lastName}.</b></p> </> ); } Show more There’s some repetitive logic for each form ’s a piece of state (firstName and lastName). There’s a change handler (handleFirstNameChange and handleLastNameChange). There’s a piece of JSX that specifies the value and onChange attributes for that input. You can extract the repetitive logic into this useFormInput custom { useState } from 'react'; export function useFormInput(initialValue) { const [value, setValue] = useState(initialValue); function handleChange(e) { setValue(e.target.value); } const inputProps = { , }; return inputProps; } Show more Notice that it only declares one state variable called value. However, the Form component calls useFormInput two Form() { const firstNameProps = useFormInput('Mary'); const lastNameProps = useFormInput('Poppins'); // ... This is why it works like declaring two separate state variables! Custom Hooks let you share stateful logic but not state itself. Each call to a Hook is completely independent from every other call to the same Hook. This is why the two sandboxes above are completely equivalent. If you’d like, scroll back up and compare them. The behavior before and after extracting a custom Hook is identical. When you need to share the state itself between multiple components, lift it up and pass it down instead. Passing reactive values between Hooks The code inside your custom Hooks will re-run during every re-render of your component. This is why, like components, custom Hooks need to be pure. Think of custom Hooks’ code as part of your component’s body! Because custom Hooks re-render together with your component, they always receive the latest props and state. To see what this means, consider this chat room example. Change the server URL or the chat { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; import { showNotification } from './notifications.js'; export default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useEffect(() => { const options = { , }; const connection = createConnection(options); connection.on('message', (msg) => { showNotification('New message: ' + msg); }); connection.connect(); return () => connection.disconnect(); }, [roomId, serverUrl]); return ( <> <label> Server URL: <input value={serverUrl} onChange={e => setServerUrl(e.target.value)} /> </label> <h1>Welcome to the {roomId} room!</h1> </> ); } Show more When you change serverUrl or roomId, the Effect “reacts” to your changes and re-synchronizes. You can tell by the console messages that the chat re-connects every time that you change your Effect’s dependencies. Now move the Effect’s code into a custom function useChatRoom({ serverUrl, roomId }) { useEffect(() => { const options = { , }; const connection = createConnection(options); connection.connect(); connection.on('message', (msg) => { showNotification('New message: ' + msg); }); return () => connection.disconnect(); }, [roomId, serverUrl]);} This lets your ChatRoom component call your custom Hook without worrying about how it works default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useChatRoom({ , }); return ( <> <label> Server URL: <input value={serverUrl} onChange={e => setServerUrl(e.target.value)} /> </label> <h1>Welcome to the {roomId} room!</h1> </> );} This looks much simpler! (But it does the same thing.) Notice that the logic still responds to prop and state changes. Try editing the server URL or the selected { useState } from 'react'; import { useChatRoom } from './useChatRoom.js'; export default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useChatRoom({ , }); return ( <> <label> Server URL: <input value={serverUrl} onChange={e => setServerUrl(e.target.value)} /> </label> <h1>Welcome to the {roomId} room!</h1> </> ); } Show more Notice how you’re taking the return value of one default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useChatRoom({ , }); // ... and passing it as an input to another default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useChatRoom({ , }); // ... Every time your ChatRoom component re-renders, it passes the latest roomId and serverUrl to your Hook. This is why your Effect re-connects to the chat whenever their values are different after a re-render. (If you ever worked with audio or video processing software, chaining Hooks like this might remind you of chaining visual or audio effects. It’s as if the output of useState “feeds into” the input of the useChatRoom.) Passing event handlers to custom Hooks As you start using useChatRoom in more components, you might want to let components customize its behavior. For example, currently, the logic for what to do when a message arrives is hardcoded inside the function useChatRoom({ serverUrl, roomId }) { useEffect(() => { const options = { , }; const connection = createConnection(options); connection.connect(); connection.on('message', (msg) => { showNotification('New message: ' + msg); }); return () => connection.disconnect(); }, [roomId, serverUrl]);} Let’s say you want to move this logic back to your default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useChatRoom({ , , onReceiveMessage(msg) { showNotification('New message: ' + msg); } }); // ... To make this work, change your custom Hook to take onReceiveMessage as one of its named function useChatRoom({ serverUrl, roomId, onReceiveMessage }) { useEffect(() => { const options = { , }; const connection = createConnection(options); connection.connect(); connection.on('message', (msg) => { onReceiveMessage(msg); }); return () => connection.disconnect(); }, [roomId, serverUrl, onReceiveMessage]); // ✅ All dependencies declared} This will work, but there’s one more improvement you can do when your custom Hook accepts event handlers. Adding a dependency on onReceiveMessage is not ideal because it will cause the chat to re-connect every time the component re-renders. Wrap this event handler into an Effect Event to remove it from the { useEffect, useEffectEvent } from 'react';// ...export function useChatRoom({ serverUrl, roomId, onReceiveMessage }) { const onMessage = useEffectEvent(onReceiveMessage); useEffect(() => { const options = { , }; const connection = createConnection(options); connection.connect(); connection.on('message', (msg) => { onMessage(msg); }); return () => connection.disconnect(); }, [roomId, serverUrl]); // ✅ All dependencies declared} Now the chat won’t re-connect every time that the ChatRoom component re-renders. Here is a fully working demo of passing an event handler to a custom Hook that you can play { useState } from 'react'; import { useChatRoom } from './useChatRoom.js'; import { showNotification } from './notifications.js'; export default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useChatRoom({ , , onReceiveMessage(msg) { showNotification('New message: ' + msg); } }); return ( <> <label> Server URL: <input value={serverUrl} onChange={e => setServerUrl(e.target.value)} /> </label> <h1>Welcome to the {roomId} room!</h1> </> ); } Show more Notice how you no longer need to know how useChatRoom works in order to use it. You could add it to any other component, pass any other options, and it would work the same way. That’s the power of custom Hooks. When to use custom Hooks You don’t need to extract a custom Hook for every little duplicated bit of code. Some duplication is fine. For example, extracting a useFormInput Hook to wrap a single useState call like earlier is probably unnecessary. However, whenever you write an Effect, consider whether it would be clearer to also wrap it in a custom Hook. You shouldn’t need Effects very often, so if you’re writing one, it means that you need to “step outside React” to synchronize with some external system or to do something that React doesn’t have a built-in API for. Wrapping it into a custom Hook lets you precisely communicate your intent and how the data flows through it. For example, consider a ShippingForm component that displays two shows the list of cities, and another shows the list of areas in the selected city. You might start with some code that looks like ShippingForm({ country }) { const [cities, setCities] = useState(null); // This Effect fetches cities for a country useEffect(() => { let ignore = false; fetch(`/api/cities?country=${country}`) ); return () => { ignore = true; }; }, [country]); const [city, setCity] = useState(null); const [areas, setAreas] = useState(null); // This Effect fetches areas for the selected city useEffect(() => { if (city) { let ignore = false; fetch(`/api/areas?city=${city}`) ); return () => { ignore = true; }; } }, [city]); // ... Although this code is quite repetitive, it’s correct to keep these Effects separate from each other. They synchronize two different things, so you shouldn’t merge them into one Effect. Instead, you can simplify the ShippingForm component above by extracting the common logic between them into your own useData useData(url) { const [data, setData] = useState(null); useEffect(() => { if (url) { let ignore = false; fetch(url) ); return () => { ignore = true; }; } }, [url]); return data;} Now you can replace both Effects in the ShippingForm components with calls to ShippingForm({ country }) { const cities = useData(`/api/cities?country=${country}`); const [city, setCity] = useState(null); const areas = useData(city ? `/api/areas?city=${city}` : null); // ... Extracting a custom Hook makes the data flow explicit. You feed the url in and you get the data out. By “hiding” your Effect inside useData, you also prevent someone working on the ShippingForm component from adding unnecessary dependencies to it. With time, most of your app’s Effects will be in custom Hooks. Deep DiveKeep your custom Hooks focused on concrete high-level use cases Show DetailsStart by choosing your custom Hook’s name. If you struggle to pick a clear name, it might mean that your Effect is too coupled to the rest of your component’s logic, and is not yet ready to be extracted.Ideally, your custom Hook’s name should be clear enough that even a person who doesn’t write code often could have a good guess about what your custom Hook does, what it takes, and what it returns: ✅ useData(url) ✅ useImpressionLog(eventName, extraData) ✅ useChatRoom(options) When you synchronize with an external system, your custom Hook name may be more technical and use jargon specific to that system. It’s good as long as it would be clear to a person familiar with that system: ✅ useMediaQuery(query) ✅ useSocket(url) ✅ useIntersectionObserver(ref, options) Keep custom Hooks focused on concrete high-level use cases. Avoid creating and using custom “lifecycle” Hooks that act as alternatives and convenience wrappers for the useEffect API itself: 🔴 useMount(fn) 🔴 useEffectOnce(fn) 🔴 useUpdateEffect(fn) For example, this useMount Hook tries to ensure some code only runs “on mount”:function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // 🔴 custom \"lifecycle\" Hooks useMount(() => { const connection = createConnection({ roomId, serverUrl }); connection.connect(); post('/analytics/event', { eventName: 'visit_chat' }); }); // ...}// 🔴 custom \"lifecycle\" Hooksfunction useMount(fn) { useEffect(() => { fn(); }, []); // 🔴 React Hook useEffect has a missing dependency: 'fn'}Custom “lifecycle” Hooks like useMount don’t fit well into the React paradigm. For example, this code example has a mistake (it doesn’t “react” to roomId or serverUrl changes), but the linter won’t warn you about it because the linter only checks direct useEffect calls. It won’t know about your Hook.If you’re writing an Effect, start by using the React API ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // ✅ raw Effects separated by purpose useEffect(() => { const connection = createConnection({ serverUrl, roomId }); connection.connect(); return () => connection.disconnect(); }, [serverUrl, roomId]); useEffect(() => { post('/analytics/event', { eventName: 'visit_chat', roomId }); }, [roomId]); // ...}Then, you can (but don’t have to) extract custom Hooks for different high-level use ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // ✅ Hooks named after their purpose useChatRoom({ serverUrl, roomId }); useImpressionLog('visit_chat', { roomId }); // ...}A good custom Hook makes the calling code more declarative by constraining what it does. For example, useChatRoom(options) can only connect to the chat room, while useImpressionLog(eventName, extraData) can only send an impression log to the analytics. If your custom Hook API doesn’t constrain the use cases and is very abstract, in the long run it’s likely to introduce more problems than it solves. Custom Hooks help you migrate to better patterns Effects are an “escape hatch”: you use them when you need to “step outside React” and when there is no better built-in solution for your use case. With time, the React team’s goal is to reduce the number of the Effects in your app to the minimum by providing more specific solutions to more specific problems. Wrapping your Effects in custom Hooks makes it easier to upgrade your code when these solutions become available. Let’s return to this { useState, useEffect } from 'react'; export function useOnlineStatus() { const [isOnline, setIsOnline] = useState(true); useEffect(() => { function handleOnline() { setIsOnline(true); } function handleOffline() { setIsOnline(false); } window.addEventListener('online', handleOnline); window.addEventListener('offline', handleOffline); return () => { window.removeEventListener('online', handleOnline); window.removeEventListener('offline', handleOffline); }; }, []); return isOnline; } Show more In the above example, useOnlineStatus is implemented with a pair of useState and useEffect. However, this isn’t the best possible solution. There is a number of edge cases it doesn’t consider. For example, it assumes that when the component mounts, isOnline is already true, but this may be wrong if the network already went offline. You can use the browser navigator.onLine API to check for that, but using it directly would not work on the server for generating the initial HTML. In short, this code could be improved. React includes a dedicated API called useSyncExternalStore which takes care of all of these problems for you. Here is your useOnlineStatus Hook, rewritten to take advantage of this new { useSyncExternalStore } from 'react'; function subscribe(callback) { window.addEventListener('online', callback); window.addEventListener('offline', callback); return () => { window.removeEventListener('online', callback); window.removeEventListener('offline', callback); }; } export function useOnlineStatus() { return useSyncExternalStore( subscribe, () => navigator.onLine, // How to get the value on the client () => true // How to get the value on the server ); } Show more Notice how you didn’t need to change any of the components to make this StatusBar() { const isOnline = useOnlineStatus(); // ...}function SaveButton() { const isOnline = useOnlineStatus(); // ...} This is another reason for why wrapping Effects in custom Hooks is often make the data flow to and from your Effects very explicit. You let your components focus on the intent rather than on the exact implementation of your Effects. When React adds new features, you can remove those Effects without changing any of your components. Similar to a design system, you might find it helpful to start extracting common idioms from your app’s components into custom Hooks. This will keep your components’ code focused on the intent, and let you avoid writing raw Effects very often. Many excellent custom Hooks are maintained by the React community. Deep DiveWill React provide any built-in solution for data fetching? Show DetailsToday, with the use API, data can be read in render by passing a Promise to { use, Suspense } from \"react\";function Message({ messagePromise }) { const messageContent = use(messagePromise); return <p>Here is the message: {messageContent}</p>;}export function MessageContainer({ messagePromise }) { return ( <Suspense fallback={<p>⌛Downloading message...</p>}> <Message messagePromise={messagePromise} /> </Suspense> );}We’re still working out the details, but we expect that in the future, you’ll write data fetching like { use } from 'react';function ShippingForm({ country }) { const cities = use(fetch(`/api/cities?country=${country}`)); const [city, setCity] = useState(null); const areas = city ? use(fetch(`/api/areas?city=${city}`)) : null; // ...If you use custom Hooks like useData above in your app, it will require fewer changes to migrate to the eventually recommended approach than if you write raw Effects in every component manually. However, the old approach will still work fine, so if you feel happy writing raw Effects, you can continue to do that. There is more than one way to do it Let’s say you want to implement a fade-in animation from scratch using the browser requestAnimationFrame API. You might start with an Effect that sets up an animation loop. During each frame of the animation, you could change the opacity of the DOM node you hold in a ref until it reaches 1. Your code might start like { useState, useEffect, useRef } from 'react'; function Welcome() { const ref = useRef(null); useEffect(() => { const duration = 1000; const node = ref.current; let startTime = performance.now(); let frameId = null; function onFrame(now) { const timePassed = now - startTime; const progress = Math.min(timePassed / duration, 1); onProgress(progress); if (progress < 1) { // We still have more frames to paint frameId = requestAnimationFrame(onFrame); } } function onProgress(progress) { node.style.opacity = progress; } function start() { onProgress(0); startTime = performance.now(); frameId = requestAnimationFrame(onFrame); } function stop() { cancelAnimationFrame(frameId); startTime = null; frameId = null; } start(); return () => stop(); }, []); return ( <h1 className=\"welcome\" ref={ref}> Welcome </h1> ); } export default function App() { const [show, setShow] = useState(false); return ( <> <button onClick={() => setShow(!show)}> {show ? 'Remove' : 'Show'} </button> <hr /> {show && <Welcome />} </> ); } Show more To make the component more readable, you might extract the logic into a useFadeIn custom { useState, useEffect, useRef } from 'react'; import { useFadeIn } from './useFadeIn.js'; function Welcome() { const ref = useRef(null); useFadeIn(ref, 1000); return ( <h1 className=\"welcome\" ref={ref}> Welcome </h1> ); } export default function App() { const [show, setShow] = useState(false); return ( <> <button onClick={() => setShow(!show)}> {show ? 'Remove' : 'Show'} </button> <hr /> {show && <Welcome />} </> ); } Show more You could keep the useFadeIn code as is, but you could also refactor it more. For example, you could extract the logic for setting up the animation loop out of useFadeIn into a custom useAnimationLoop { useState, useEffect } from 'react'; import { useEffectEvent } from 'react'; export function useFadeIn(ref, duration) { const [isRunning, setIsRunning] = useState(true); useAnimationLoop(isRunning, (timePassed) => { const progress = Math.min(timePassed / duration, 1); ref.current.style.opacity = progress; if (progress === 1) { setIsRunning(false); } }); } function useAnimationLoop(isRunning, drawFrame) { const onFrame = useEffectEvent(drawFrame); useEffect(() => { if (!isRunning) { return; } const startTime = performance.now(); let frameId = null; function tick(now) { const timePassed = now - startTime; onFrame(timePassed); frameId = requestAnimationFrame(tick); } tick(); return () => cancelAnimationFrame(frameId); }, [isRunning]); } Show more However, you didn’t have to do that. As with regular functions, ultimately you decide where to draw the boundaries between different parts of your code. You could also take a very different approach. Instead of keeping the logic in the Effect, you could move most of the imperative logic inside a JavaScript { useState, useEffect } from 'react'; import { FadeInAnimation } from './animation.js'; export function useFadeIn(ref, duration) { useEffect(() => { const animation = new FadeInAnimation(ref.current); animation.start(duration); return () => { animation.stop(); }; }, [ref, duration]); } Effects let you connect React to external systems. The more coordination between Effects is needed (for example, to chain multiple animations), the more it makes sense to extract that logic out of Effects and Hooks completely like in the sandbox above. Then, the code you extracted becomes the “external system”. This lets your Effects stay simple because they only need to send messages to the system you’ve moved outside React. The examples above assume that the fade-in logic needs to be written in JavaScript. However, this particular fade-in animation is both simpler and much more efficient to implement with a plain CSS { (circle, rgba(63,94,251,1) 0%, rgba(252,70,107,1) 100%); 1000ms; } Sometimes, you don’t even need a Hook! Recap Custom Hooks let you share logic between components. Custom Hooks must be named starting with use followed by a capital letter. Custom Hooks only share stateful logic, not state itself. You can pass reactive values from one Hook to another, and they stay up-to-date. All Hooks re-run every time your component re-renders. The code of your custom Hooks should be pure, like your component’s code. Wrap event handlers received by custom Hooks into Effect Events. Don’t create custom Hooks like useMount. Keep their purpose specific. It’s up to you how and where to choose the boundaries of your code. Try out some challenges1. Extract a useCounter Hook 2. Make the counter delay configurable 3. Extract useInterval out of useCounter 4. Fix a resetting interval 5. Implement a staggering movement Challenge 1 of a useCounter Hook This component uses a state variable and an Effect to display a number that increments every second. Extract this logic into a custom Hook called useCounter. Your goal is to make the Counter component implementation look exactly like default function Counter() { const count = useCounter(); return <h1>Seconds passed: {count}</h1>;}You’ll need to write your custom Hook in useCounter.js and import it into the App.js file.App.jsuseCounter.jsApp.jsReloadClearForkimport { useState, useEffect } from 'react'; export default function Counter() { const [count, setCount] = useState(0); useEffect(() => { const id = setInterval(() => { setCount(c => c + 1); }, 1000); return () => clearInterval(id); }, []); return <h1>Seconds passed: {count}</h1>; } Show solutionNext ChallengePreviousRemoving Effect DependenciesCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewCustom logic between components Extracting your own custom Hook from a component Hook names always start with use Custom Hooks let you share stateful logic, not state itself Passing reactive values between Hooks Passing event handlers to custom Hooks When to use custom Hooks Custom Hooks help you migrate to better patterns There is more than one way to do it RecapChallenges\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\n\nexport default function StatusBar() {\n  const [isOnline, setIsOnline] = useState(true);\n  useEffect(() => {\n    function handleOnline() {\n      setIsOnline(true);\n    }\n    function handleOffline() {\n      setIsOnline(false);\n    }\n    window.addEventListener('online', handleOnline);\n    window.addEventListener('offline', handleOffline);\n    return () => {\n      window.removeEventListener('online', handleOnline);\n      window.removeEventListener('offline', handleOffline);\n    };\n  }, []);\n\n  return <h1>{isOnline ? '✅ Online' : '❌ Disconnected'}</h1>;\n}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\n\nexport default function SaveButton() {\n  const [isOnline, setIsOnline] = useState(true);\n  useEffect(() => {\n    function handleOnline() {\n      setIsOnline(true);\n    }\n    function handleOffline() {\n      setIsOnline(false);\n    }\n    window.addEventListener('online', handleOnline);\n    window.addEventListener('offline', handleOffline);\n    return () => {\n      window.removeEventListener('online', handleOnline);\n      window.removeEventListener('offline', handleOffline);\n    };\n  }, []);\n\n  function handleSaveClick() {\n    console.log('✅ Progress saved');\n  }\n\n  return (\n    <button disabled={!isOnline} onClick={handleSaveClick}>\n      {isOnline ? 'Save progress' : 'Reconnecting...'}\n    </button>\n  );\n}\n```\n\nExample:\n```javascript\nfunction StatusBar() {  const isOnline = useOnlineStatus();  return <h1>{isOnline ? '✅ Online' : '❌ Disconnected'}</h1>;}function SaveButton() {  const isOnline = useOnlineStatus();  function handleSaveClick() {    console.log('✅ Progress saved');  }  return (    <button disabled={!isOnline} onClick={handleSaveClick}>      {isOnline ? 'Save progress' : 'Reconnecting...'}    </button>  );}\n```\n\nExample:\n```javascript\nfunction useOnlineStatus() {  const [isOnline, setIsOnline] = useState(true);  useEffect(() => {    function handleOnline() {      setIsOnline(true);    }    function handleOffline() {      setIsOnline(false);    }    window.addEventListener('online', handleOnline);    window.addEventListener('offline', handleOffline);    return () => {      window.removeEventListener('online', handleOnline);      window.removeEventListener('offline', handleOffline);    };  }, []);  return isOnline;}\n```\n\nExample:\n```text\nimport { useOnlineStatus } from './useOnlineStatus.js';\n\nfunction StatusBar() {\n  const isOnline = useOnlineStatus();\n  return <h1>{isOnline ? '✅ Online' : '❌ Disconnected'}</h1>;\n}\n\nfunction SaveButton() {\n  const isOnline = useOnlineStatus();\n\n  function handleSaveClick() {\n    console.log('✅ Progress saved');\n  }\n\n  return (\n    <button disabled={!isOnline} onClick={handleSaveClick}>\n      {isOnline ? 'Save progress' : 'Reconnecting...'}\n    </button>\n  );\n}\n\nexport default function App() {\n  return (\n    <>\n      <SaveButton />\n      <StatusBar />\n    </>\n  );\n}\n```\n\nExample:\n```javascript\n// 🔴 Avoid: A Hook that doesn't use Hooksfunction useSorted(items) {  return items.slice().sort();}// ✅ Good: A regular function that doesn't use Hooksfunction getSorted(items) {  return items.slice().sort();}\n```\n\nExample:\n```javascript\nfunction List({ items, shouldSort }) {  let displayedItems = items;  if (shouldSort) {    // ✅ It's ok to call getSorted() conditionally because it's not a Hook    displayedItems = getSorted(items);  }  // ...}\n```\n\nExample:\n```javascript\n// ✅ Good: A Hook that uses other Hooksfunction useAuth() {  return useContext(Auth);}\n```\n\nExample:\n```javascript\n// ✅ Good: A Hook that will likely use some other Hooks laterfunction useAuth() {  // TODO: Replace with this line when authentication is implemented:  // return useContext(Auth);  return TEST_USER;}\n```\n\nExample:\n```javascript\nfunction StatusBar() {  const isOnline = useOnlineStatus();  // ...}function SaveButton() {  const isOnline = useOnlineStatus();  // ...}\n```\n\nExample:\n```javascript\nfunction StatusBar() {  const [isOnline, setIsOnline] = useState(true);  useEffect(() => {    // ...  }, []);  // ...}function SaveButton() {  const [isOnline, setIsOnline] = useState(true);  useEffect(() => {    // ...  }, []);  // ...}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Form() {\n  const [firstName, setFirstName] = useState('Mary');\n  const [lastName, setLastName] = useState('Poppins');\n\n  function handleFirstNameChange(e) {\n    setFirstName(e.target.value);\n  }\n\n  function handleLastNameChange(e) {\n    setLastName(e.target.value);\n  }\n\n  return (\n    <>\n      <label>\n        First name:\n        <input value={firstName} onChange={handleFirstNameChange} />\n      </label>\n      <label>\n        Last name:\n        <input value={lastName} onChange={handleLastNameChange} />\n      </label>\n      <p><b>Good morning, {firstName} {lastName}.</b></p>\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport function useFormInput(initialValue) {\n  const [value, setValue] = useState(initialValue);\n\n  function handleChange(e) {\n    setValue(e.target.value);\n  }\n\n  const inputProps = {\n    value: value,\n    onChange: handleChange\n  };\n\n  return inputProps;\n}\n```\n\nExample:\n```javascript\nfunction Form() {  const firstNameProps = useFormInput('Mary');  const lastNameProps = useFormInput('Poppins');  // ...\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';\nimport { showNotification } from './notifications.js';\n\nexport default function ChatRoom({ roomId }) {\n  const [serverUrl, setServerUrl] = useState('https://localhost:1234');\n\n  useEffect(() => {\n    const options = {\n      serverUrl: serverUrl,\n      roomId: roomId\n    };\n    const connection = createConnection(options);\n    connection.on('message', (msg) => {\n      showNotification('New message: ' + msg);\n    });\n    connection.connect();\n    return () => connection.disconnect();\n  }, [roomId, serverUrl]);\n\n  return (\n    <>\n      <label>\n        Server URL:\n        <input value={serverUrl} onChange={e => setServerUrl(e.target.value)} />\n      </label>\n      <h1>Welcome to the {roomId} room!</h1>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nexport function useChatRoom({ serverUrl, roomId }) {  useEffect(() => {    const options = {      serverUrl: serverUrl,      roomId: roomId    };    const connection = createConnection(options);    connection.connect();    connection.on('message', (msg) => {      showNotification('New message: ' + msg);    });    return () => connection.disconnect();  }, [roomId, serverUrl]);}\n```\n\nExample:\n```javascript\nexport default function ChatRoom({ roomId }) {  const [serverUrl, setServerUrl] = useState('https://localhost:1234');  useChatRoom({    roomId: roomId,    serverUrl: serverUrl  });  return (    <>      <label>        Server URL:        <input value={serverUrl} onChange={e => setServerUrl(e.target.value)} />      </label>      <h1>Welcome to the {roomId} room!</h1>    </>  );}\n```\n\nExample:\n```text\nimport { useState } from 'react';\nimport { useChatRoom } from './useChatRoom.js';\n\nexport default function ChatRoom({ roomId }) {\n  const [serverUrl, setServerUrl] = useState('https://localhost:1234');\n\n  useChatRoom({\n    roomId: roomId,\n    serverUrl: serverUrl\n  });\n\n  return (\n    <>\n      <label>\n        Server URL:\n        <input value={serverUrl} onChange={e => setServerUrl(e.target.value)} />\n      </label>\n      <h1>Welcome to the {roomId} room!</h1>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nexport default function ChatRoom({ roomId }) {  const [serverUrl, setServerUrl] = useState('https://localhost:1234');  useChatRoom({    roomId: roomId,    serverUrl: serverUrl  });  // ...\n```\n\nExample:\n```javascript\nexport default function ChatRoom({ roomId }) {  const [serverUrl, setServerUrl] = useState('https://localhost:1234');  useChatRoom({    roomId: roomId,    serverUrl: serverUrl,    onReceiveMessage(msg) {      showNotification('New message: ' + msg);    }  });  // ...\n```\n\nExample:\n```javascript\nexport function useChatRoom({ serverUrl, roomId, onReceiveMessage }) {  useEffect(() => {    const options = {      serverUrl: serverUrl,      roomId: roomId    };    const connection = createConnection(options);    connection.connect();    connection.on('message', (msg) => {      onReceiveMessage(msg);    });    return () => connection.disconnect();  }, [roomId, serverUrl, onReceiveMessage]); // ✅ All dependencies declared}\n```\n\nExample:\n```javascript\nimport { useEffect, useEffectEvent } from 'react';// ...export function useChatRoom({ serverUrl, roomId, onReceiveMessage }) {  const onMessage = useEffectEvent(onReceiveMessage);  useEffect(() => {    const options = {      serverUrl: serverUrl,      roomId: roomId    };    const connection = createConnection(options);    connection.connect();    connection.on('message', (msg) => {      onMessage(msg);    });    return () => connection.disconnect();  }, [roomId, serverUrl]); // ✅ All dependencies declared}\n```\n\nExample:\n```text\nimport { useState } from 'react';\nimport { useChatRoom } from './useChatRoom.js';\nimport { showNotification } from './notifications.js';\n\nexport default function ChatRoom({ roomId }) {\n  const [serverUrl, setServerUrl] = useState('https://localhost:1234');\n\n  useChatRoom({\n    roomId: roomId,\n    serverUrl: serverUrl,\n    onReceiveMessage(msg) {\n      showNotification('New message: ' + msg);\n    }\n  });\n\n  return (\n    <>\n      <label>\n        Server URL:\n        <input value={serverUrl} onChange={e => setServerUrl(e.target.value)} />\n      </label>\n      <h1>Welcome to the {roomId} room!</h1>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nfunction ShippingForm({ country }) {  const [cities, setCities] = useState(null);  // This Effect fetches cities for a country  useEffect(() => {    let ignore = false;    fetch(`/api/cities?country=${country}`)      .then(response => response.json())      .then(json => {        if (!ignore) {          setCities(json);        }      });    return () => {      ignore = true;    };  }, [country]);  const [city, setCity] = useState(null);  const [areas, setAreas] = useState(null);  // This Effect fetches areas for the selected city  useEffect(() => {    if (city) {      let ignore = false;      fetch(`/api/areas?city=${city}`)        .then(response => response.json())        .then(json => {          if (!ignore) {            setAreas(json);          }        });      return () => {        ignore = true;      };    }  }, [city]);  // ...\n```\n\nExample:\n```javascript\nfunction useData(url) {  const [data, setData] = useState(null);  useEffect(() => {    if (url) {      let ignore = false;      fetch(url)        .then(response => response.json())        .then(json => {          if (!ignore) {            setData(json);          }        });      return () => {        ignore = true;      };    }  }, [url]);  return data;}\n```\n\nExample:\n```javascript\nfunction ShippingForm({ country }) {  const cities = useData(`/api/cities?country=${country}`);  const [city, setCity] = useState(null);  const areas = useData(city ? `/api/areas?city=${city}` : null);  // ...\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId }) {  const [serverUrl, setServerUrl] = useState('https://localhost:1234');  // 🔴 Avoid: using custom \"lifecycle\" Hooks  useMount(() => {    const connection = createConnection({ roomId, serverUrl });    connection.connect();    post('/analytics/event', { eventName: 'visit_chat' });  });  // ...}// 🔴 Avoid: creating custom \"lifecycle\" Hooksfunction useMount(fn) {  useEffect(() => {    fn();  }, []); // 🔴 React Hook useEffect has a missing dependency: 'fn'}\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId }) {  const [serverUrl, setServerUrl] = useState('https://localhost:1234');  // ✅ Good: two raw Effects separated by purpose  useEffect(() => {    const connection = createConnection({ serverUrl, roomId });    connection.connect();    return () => connection.disconnect();  }, [serverUrl, roomId]);  useEffect(() => {    post('/analytics/event', { eventName: 'visit_chat', roomId });  }, [roomId]);  // ...}\n```\n\nExample:\n```javascript\nfunction ChatRoom({ roomId }) {  const [serverUrl, setServerUrl] = useState('https://localhost:1234');  // ✅ Great: custom Hooks named after their purpose  useChatRoom({ serverUrl, roomId });  useImpressionLog('visit_chat', { roomId });  // ...}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\n\nexport function useOnlineStatus() {\n  const [isOnline, setIsOnline] = useState(true);\n  useEffect(() => {\n    function handleOnline() {\n      setIsOnline(true);\n    }\n    function handleOffline() {\n      setIsOnline(false);\n    }\n    window.addEventListener('online', handleOnline);\n    window.addEventListener('offline', handleOffline);\n    return () => {\n      window.removeEventListener('online', handleOnline);\n      window.removeEventListener('offline', handleOffline);\n    };\n  }, []);\n  return isOnline;\n}\n```\n\nExample:\n```text\nimport { useSyncExternalStore } from 'react';\n\nfunction subscribe(callback) {\n  window.addEventListener('online', callback);\n  window.addEventListener('offline', callback);\n  return () => {\n    window.removeEventListener('online', callback);\n    window.removeEventListener('offline', callback);\n  };\n}\n\nexport function useOnlineStatus() {\n  return useSyncExternalStore(\n    subscribe,\n    () => navigator.onLine, // How to get the value on the client\n    () => true // How to get the value on the server\n  );\n}\n```\n\nExample:\n```javascript\nimport { use, Suspense } from \"react\";function Message({ messagePromise }) {  const messageContent = use(messagePromise);  return <p>Here is the message: {messageContent}</p>;}export function MessageContainer({ messagePromise }) {  return (    <Suspense fallback={<p>⌛Downloading message...</p>}>      <Message messagePromise={messagePromise} />    </Suspense>  );}\n```\n\nExample:\n```javascript\nimport { use } from 'react';function ShippingForm({ country }) {  const cities = use(fetch(`/api/cities?country=${country}`));  const [city, setCity] = useState(null);  const areas = city ? use(fetch(`/api/areas?city=${city}`)) : null;  // ...\n```\n\nExample:\n```text\nimport { useState, useEffect, useRef } from 'react';\n\nfunction Welcome() {\n  const ref = useRef(null);\n\n  useEffect(() => {\n    const duration = 1000;\n    const node = ref.current;\n\n    let startTime = performance.now();\n    let frameId = null;\n\n    function onFrame(now) {\n      const timePassed = now - startTime;\n      const progress = Math.min(timePassed / duration, 1);\n      onProgress(progress);\n      if (progress < 1) {\n        // We still have more frames to paint\n        frameId = requestAnimationFrame(onFrame);\n      }\n    }\n\n    function onProgress(progress) {\n      node.style.opacity = progress;\n    }\n\n    function start() {\n      onProgress(0);\n      startTime = performance.now();\n      frameId = requestAnimationFrame(onFrame);\n    }\n\n    function stop() {\n      cancelAnimationFrame(frameId);\n      startTime = null;\n      frameId = null;\n    }\n\n    start();\n    return () => stop();\n  }, []);\n\n  return (\n    <h1 className=\"welcome\" ref={ref}>\n      Welcome\n    </h1>\n  );\n}\n\nexport default function App() {\n  const [show, setShow] = useState(false);\n  return (\n    <>\n      <button onClick={() => setShow(!show)}>\n        {show ? 'Remove' : 'Show'}\n      </button>\n      <hr />\n      {show && <Welcome />}\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState, useEffect, useRef } from 'react';\nimport { useFadeIn } from './useFadeIn.js';\n\nfunction Welcome() {\n  const ref = useRef(null);\n\n  useFadeIn(ref, 1000);\n\n  return (\n    <h1 className=\"welcome\" ref={ref}>\n      Welcome\n    </h1>\n  );\n}\n\nexport default function App() {\n  const [show, setShow] = useState(false);\n  return (\n    <>\n      <button onClick={() => setShow(!show)}>\n        {show ? 'Remove' : 'Show'}\n      </button>\n      <hr />\n      {show && <Welcome />}\n    </>\n  );\n}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { useEffectEvent } from 'react';\n\nexport function useFadeIn(ref, duration) {\n  const [isRunning, setIsRunning] = useState(true);\n\n  useAnimationLoop(isRunning, (timePassed) => {\n    const progress = Math.min(timePassed / duration, 1);\n    ref.current.style.opacity = progress;\n    if (progress === 1) {\n      setIsRunning(false);\n    }\n  });\n}\n\nfunction useAnimationLoop(isRunning, drawFrame) {\n  const onFrame = useEffectEvent(drawFrame);\n\n  useEffect(() => {\n    if (!isRunning) {\n      return;\n    }\n\n    const startTime = performance.now();\n    let frameId = null;\n\n    function tick(now) {\n      const timePassed = now - startTime;\n      onFrame(timePassed);\n      frameId = requestAnimationFrame(tick);\n    }\n\n    tick();\n    return () => cancelAnimationFrame(frameId);\n  }, [isRunning]);\n}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\nimport { FadeInAnimation } from './animation.js';\n\nexport function useFadeIn(ref, duration) {\n  useEffect(() => {\n    const animation = new FadeInAnimation(ref.current);\n    animation.start(duration);\n    return () => {\n      animation.stop();\n    };\n  }, [ref, duration]);\n}\n```\n\nExample:\n```text\n.welcome {\n  color: white;\n  padding: 50px;\n  text-align: center;\n  font-size: 50px;\n  background-image: radial-gradient(circle, rgba(63,94,251,1) 0%, rgba(252,70,107,1) 100%);\n\n  animation: fadeIn 1000ms;\n}\n\n@keyframes fadeIn {\n  0% { opacity: 0; }\n  100% { opacity: 1; }\n}\n```\n\nExample:\n```javascript\nexport default function Counter() {  const count = useCounter();  return <h1>Seconds passed: {count}</h1>;}\n```\n\nExample:\n```text\nimport { useState, useEffect } from 'react';\n\nexport default function Counter() {\n  const [count, setCount] = useState(0);\n  useEffect(() => {\n    const id = setInterval(() => {\n      setCount(c => c + 1);\n    }, 1000);\n    return () => clearInterval(id);\n  }, []);\n  return <h1>Seconds passed: {count}</h1>;\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.922Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":40,"totalLines":586,"estimatedTokens":13254}}38{"id":"doc-incremental_adoption_react-339ec64f","source":"documentation","title":"Incremental Adoption – React","url":"https://react.dev/learn/react-compiler/incremental-adoption","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactReact CompilerCopy pageCopyIncremental AdoptionReact Compiler can be adopted incrementally, allowing you to try it on specific parts of your codebase first. This guide shows you how to gradually roll out the compiler in existing projects. You will learn Why incremental adoption is recommended Using Babel overrides for directory-based adoption Using the “use memo” directive for opt-in compilation Using the “use no memo” directive to exclude components Runtime feature flags with gating Monitoring your adoption progress Why Incremental Adoption? React Compiler is designed to optimize your entire codebase automatically, but you don’t have to adopt it all at once. Incremental adoption gives you control over the rollout process, letting you test the compiler on small parts of your app before expanding to the rest. Starting small helps you build confidence in the compiler’s optimizations. You can verify that your app behaves correctly with compiled code, measure performance improvements, and identify any edge cases specific to your codebase. This approach is especially valuable for production applications where stability is critical. Incremental adoption also makes it easier to address any Rules of React violations the compiler might find. Instead of fixing violations across your entire codebase at once, you can tackle them systematically as you expand compiler coverage. This keeps the migration manageable and reduces the risk of introducing bugs. By controlling which parts of your code get compiled, you can also run A/B tests to measure the real-world impact of the compiler’s optimizations. This data helps you make informed decisions about full adoption and demonstrates the value to your team. Approaches to Incremental Adoption There are three main approaches to adopt React Compiler overrides - Apply the compiler to specific directories Opt-in with “use memo” - Only compile components that explicitly opt in Runtime gating - Control compilation with feature flags All approaches allow you to test the compiler on specific parts of your application before full rollout. Directory-Based Adoption with Babel Overrides Babel’s overrides option lets you apply different plugins to different parts of your codebase. This is ideal for gradually adopting React Compiler directory by directory. Basic Configuration Start by applying the compiler to a specific directory: // babel.config.jsmodule.exports = { plugins: [ // Global plugins that apply to all files ], overrides: [ { test: './src/modern/**/*.{js,jsx,ts,tsx}', plugins: [ 'babel-plugin-react-compiler' ] } ]}; Expanding Coverage As you gain confidence, add more directories: // babel.config.jsmodule.exports = { plugins: [ // Global plugins ], overrides: [ { test: ['./src/modern/**/*.{js,jsx,ts,tsx}', './src/features/**/*.{js,jsx,ts,tsx}'], plugins: [ 'babel-plugin-react-compiler' ] }, { test: './src/legacy/**/*.{js,jsx,ts,tsx}', plugins: [ // Different plugins for legacy code ] } ]}; With Compiler Options You can also configure compiler options per override: // babel.config.jsmodule.exports = { plugins: [], overrides: [ { test: './src/experimental/**/*.{js,jsx,ts,tsx}', plugins: [ ['babel-plugin-react-compiler', { // options ... }] ] }, { test: './src/production/**/*.{js,jsx,ts,tsx}', plugins: [ ['babel-plugin-react-compiler', { // options ... }] ] } ]}; Opt-in Mode with “use memo” For maximum control, you can use compilationMode: 'annotation' to only compile components and hooks that explicitly opt in with the \"use memo\" directive. NoteThis approach gives you fine-grained control over individual components and hooks. It’s useful when you want to test the compiler on specific components without affecting entire directories. Annotation Mode Configuration // babel.config.jsmodule.exports = { plugins: [ ['babel-plugin-react-compiler', { compilationMode: 'annotation', }], ],}; Using the Directive Add \"use memo\" at the beginning of functions you want to TodoList({ todos }) { \"use memo\"; // Opt this component into compilation const sortedTodos = todos.slice().sort(); return ( <ul> {sortedTodos.map(todo => ( <TodoItem key={todo.id} todo={todo} /> ))} </ul> );}function useSortedData(data) { \"use memo\"; // Opt this hook into compilation return data.slice().sort();} With compilationMode: 'annotation', you \"use memo\" to every component you want optimized Add \"use memo\" to every custom hook Remember to add it to new components This gives you precise control over which components are compiled while you evaluate the compiler’s impact. Runtime Feature Flags with Gating The gating option enables you to control compilation at runtime using feature flags. This is useful for running A/B tests or gradually rolling out the compiler based on user segments. How Gating Works The compiler wraps optimized code in a runtime check. If the gate returns true, the optimized version runs. Otherwise, the original code runs. Gating Configuration // babel.config.jsmodule.exports = { plugins: [ ['babel-plugin-react-compiler', { gating: { source: 'ReactCompilerFeatureFlags', importSpecifierName: 'isCompilerEnabled', }, }], ],}; Implementing the Feature Flag Create a module that exports your gating function: // ReactCompilerFeatureFlags.jsexport function isCompilerEnabled() { // Use your feature flag system return getFeatureFlag('react-compiler-enabled');} Troubleshooting Adoption If you encounter issues during \"use no memo\" to temporarily exclude problematic components Check the debugging guide for common issues Fix Rules of React violations identified by the ESLint plugin Consider using compilationMode: 'annotation' for more gradual adoption Next Steps Read the configuration guide for more options Learn about debugging techniques Check the API reference for all compiler options PreviousInstallationNextDebugging and TroubleshootingCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewWhy Incremental Adoption? Approaches to Incremental Adoption Directory-Based Adoption with Babel Overrides Basic Configuration Expanding Coverage With Compiler Options Opt-in Mode with “use memo” Annotation Mode Configuration Using the Directive Runtime Feature Flags with Gating How Gating Works Gating Configuration Implementing the Feature Flag Troubleshooting Adoption Next Steps\n\nExample:\n```javascript\n// babel.config.jsmodule.exports = {  plugins: [    // Global plugins that apply to all files  ],  overrides: [    {      test: './src/modern/**/*.{js,jsx,ts,tsx}',      plugins: [        'babel-plugin-react-compiler'      ]    }  ]};\n```\n\nExample:\n```javascript\n// babel.config.jsmodule.exports = {  plugins: [    // Global plugins  ],  overrides: [    {      test: ['./src/modern/**/*.{js,jsx,ts,tsx}', './src/features/**/*.{js,jsx,ts,tsx}'],      plugins: [        'babel-plugin-react-compiler'      ]    },    {      test: './src/legacy/**/*.{js,jsx,ts,tsx}',      plugins: [        // Different plugins for legacy code      ]    }  ]};\n```\n\nExample:\n```javascript\n// babel.config.jsmodule.exports = {  plugins: [],  overrides: [    {      test: './src/experimental/**/*.{js,jsx,ts,tsx}',      plugins: [        ['babel-plugin-react-compiler', {          // options ...        }]      ]    },    {      test: './src/production/**/*.{js,jsx,ts,tsx}',      plugins: [        ['babel-plugin-react-compiler', {          // options ...        }]      ]    }  ]};\n```\n\nExample:\n```javascript\n// babel.config.jsmodule.exports = {  plugins: [    ['babel-plugin-react-compiler', {      compilationMode: 'annotation',    }],  ],};\n```\n\nExample:\n```javascript\nfunction TodoList({ todos }) {  \"use memo\"; // Opt this component into compilation  const sortedTodos = todos.slice().sort();  return (    <ul>      {sortedTodos.map(todo => (        <TodoItem key={todo.id} todo={todo} />      ))}    </ul>  );}function useSortedData(data) {  \"use memo\"; // Opt this hook into compilation  return data.slice().sort();}\n```\n\nExample:\n```javascript\n// babel.config.jsmodule.exports = {  plugins: [    ['babel-plugin-react-compiler', {      gating: {        source: 'ReactCompilerFeatureFlags',        importSpecifierName: 'isCompilerEnabled',      },    }],  ],};\n```\n\nExample:\n```javascript\n// ReactCompilerFeatureFlags.jsexport function isCompilerEnabled() {  // Use your feature flag system  return getFeatureFlag('react-compiler-enabled');}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.924Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":7,"totalLines":38,"estimatedTokens":2476}}39{"id":"doc-installation_react-f88049ce","source":"documentation","title":"Installation – React","url":"https://react.dev/learn/react-compiler/installation","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactReact CompilerCopy pageCopyInstallationThis guide will help you install and configure React Compiler in your React application. You will learn How to install React Compiler Basic configuration for different build tools How to verify your setup is working Prerequisites React Compiler is designed to work best with React 19, but it also supports React 17 and 18. Learn more about React version compatibility. Installation Install React Compiler as a Copynpm install -D babel-plugin-react-compiler@latest Or with Copyyarn add -D babel-plugin-react-compiler@latest Or with Copypnpm install -D babel-plugin-react-compiler@latest Basic Setup React Compiler is designed to work by default without any configuration. However, if you need to configure it in special circumstances (for example, to target React versions below 19), refer to the compiler options reference. The setup process depends on your build tool. React Compiler includes a Babel plugin that integrates with your build pipeline. PitfallReact Compiler must run first in your Babel plugin pipeline. The compiler needs the original source information for proper analysis, so it must process your code before other transformations. Babel Create or update your babel.config.js: module.exports = { plugins: [ 'babel-plugin-react-compiler', // must run first! // ... other plugins ], // ... other config}; Vite If you use Vite with version 6.0.0 or later of @vitejs/plugin-react, you can use the Copynpm install -D @rolldown/plugin-babel // vite.config.jsimport { defineConfig } from 'vite';import react, { reactCompilerPreset } from '@vitejs/plugin-react';import babel from '@rolldown/plugin-babel';export default defineConfig({ plugins: [ react(), babel({ presets: [reactCompilerPreset()] }), ],}); NoteIn @vitejs/plugin-react@6.0.0, the inline Babel option was removed. If you’re using an older version, you can use:// vite.config.jsimport { defineConfig } from 'vite';import react from '@vitejs/plugin-react';export default defineConfig({ plugins: [ react({ babel: { plugins: ['babel-plugin-react-compiler'], }, }), ],}); Alternatively, you can use the Babel plugin directly with @rolldown/plugin-babel: // vite.config.jsimport { defineConfig } from 'vite';import react from '@vitejs/plugin-react';import babel from '@rolldown/plugin-babel';export default defineConfig({ plugins: [ react(), babel({ plugins: ['babel-plugin-react-compiler'], }), ],}); Next.js Please refer to the Next.js docs for more information. React Router Install vite-plugin-babel, and add the compiler’s Babel plugin to Copynpm install vite-plugin-babel // vite.config.jsimport { defineConfig } from \"vite\";import babel from \"vite-plugin-babel\";import { reactRouter } from \"@react-router/dev/vite\";const ReactCompilerConfig = { /* ... */ };export default defineConfig({ plugins: [ reactRouter(), babel({ filter: /\\.[jt]sx?$/, babelConfig: { presets: [\"@babel/preset-typescript\"], // if you use TypeScript plugins: [ [\"babel-plugin-react-compiler\", ReactCompilerConfig], ], }, }), ],}); Webpack A community webpack loader is now available here. Expo Please refer to Expo’s docs to enable and use the React Compiler in Expo apps. Metro (React Native) React Native uses Babel via Metro, so refer to the Usage with Babel section for installation instructions. Rspack Please refer to Rspack’s docs to enable and use the React Compiler in Rspack apps. Rsbuild Please refer to Rsbuild’s docs to enable and use the React Compiler in Rsbuild apps. ESLint Integration React Compiler includes an ESLint rule that helps identify code that can’t be optimized. When the ESLint rule reports an error, it means the compiler will skip optimizing that specific component or hook. This is compiler will continue optimizing other parts of your codebase. You don’t need to fix all violations immediately. Address them at your own pace to gradually increase the number of optimized components. Install the ESLint Copynpm install -D eslint-plugin-react-hooks@latest If you haven’t already configured eslint-plugin-react-hooks, follow the installation instructions in the readme. The compiler rules are available in the recommended-latest preset. The ESLint rule violations of the Rules of React Show which components can’t be optimized Provide helpful error messages for fixing issues Verify Your Setup After installation, verify that React Compiler is working correctly. Check React DevTools Components optimized by React Compiler will show a “Memo ✨” badge in React the React Developer Tools browser extension Open your app in development mode Open React DevTools Look for the ✨ emoji next to component names If the compiler is will show a “Memo ✨” badge in React DevTools Expensive calculations will be automatically memoized No manual useMemo is required Check Build Output You can also verify the compiler is running by checking your build output. The compiled code will include automatic memoization logic that the compiler adds automatically. import { c as _c } from \"react/compiler-runtime\";export default function MyApp() { const $ = _c(1); let t0; if ($[0] === Symbol.for(\"react.memo_cache_sentinel\")) { t0 = <div>Hello World</div>; $[0] = t0; } else { t0 = $[0]; } return t0;} Troubleshooting Opting out specific components If a component is causing issues after compilation, you can temporarily opt it out using the \"use no memo\" ProblematicComponent() { \"use no memo\"; // Component code here} This tells the compiler to skip optimization for this specific component. You should fix the underlying issue and remove the directive once resolved. For more troubleshooting help, see the debugging guide. Next Steps Now that you have React Compiler installed, learn more version compatibility for React 17 and 18 Configuration options to customize the compiler Incremental adoption strategies for existing codebases Debugging techniques for troubleshooting issues Compiling Libraries guide for compiling your React library PreviousIntroductionNextIncremental AdoptionCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewPrerequisites Installation Basic Setup Babel Vite Next.js React Router Webpack Expo Metro (React Native) Rspack Rsbuild ESLint Integration Verify Your Setup Check React DevTools Check Build Output Troubleshooting Opting out specific components Next Steps\n\nExample:\n```text\nnpm install -D babel-plugin-react-compiler@latest\n```\n\nExample:\n```text\nyarn add -D babel-plugin-react-compiler@latest\n```\n\nExample:\n```text\npnpm install -D babel-plugin-react-compiler@latest\n```\n\nExample:\n```javascript\nmodule.exports = {  plugins: [    'babel-plugin-react-compiler', // must run first!    // ... other plugins  ],  // ... other config};\n```\n\nExample:\n```text\nnpm install -D @rolldown/plugin-babel\n```\n\nExample:\n```javascript\n// vite.config.jsimport { defineConfig } from 'vite';import react, { reactCompilerPreset } from '@vitejs/plugin-react';import babel from '@rolldown/plugin-babel';export default defineConfig({  plugins: [    react(),    babel({      presets: [reactCompilerPreset()]    }),  ],});\n```\n\nExample:\n```javascript\n// vite.config.jsimport { defineConfig } from 'vite';import react from '@vitejs/plugin-react';export default defineConfig({  plugins: [    react({      babel: {        plugins: ['babel-plugin-react-compiler'],      },    }),  ],});\n```\n\nExample:\n```javascript\n// vite.config.jsimport { defineConfig } from 'vite';import react from '@vitejs/plugin-react';import babel from '@rolldown/plugin-babel';export default defineConfig({  plugins: [    react(),    babel({      plugins: ['babel-plugin-react-compiler'],    }),  ],});\n```\n\nExample:\n```text\nnpm install vite-plugin-babel\n```\n\nExample:\n```javascript\n// vite.config.jsimport { defineConfig } from \"vite\";import babel from \"vite-plugin-babel\";import { reactRouter } from \"@react-router/dev/vite\";const ReactCompilerConfig = { /* ... */ };export default defineConfig({  plugins: [    reactRouter(),    babel({      filter: /\\.[jt]sx?$/,      babelConfig: {        presets: [\"@babel/preset-typescript\"], // if you use TypeScript        plugins: [          [\"babel-plugin-react-compiler\", ReactCompilerConfig],        ],      },    }),  ],});\n```\n\nExample:\n```text\nnpm install -D eslint-plugin-react-hooks@latest\n```\n\nExample:\n```javascript\nimport { c as _c } from \"react/compiler-runtime\";export default function MyApp() {  const $ = _c(1);  let t0;  if ($[0] === Symbol.for(\"react.memo_cache_sentinel\")) {    t0 = <div>Hello World</div>;    $[0] = t0;  } else {    t0 = $[0];  }  return t0;}\n```\n\nExample:\n```javascript\nfunction ProblematicComponent() {  \"use no memo\";  // Component code here}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.925Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":13,"totalLines":68,"estimatedTokens":2545}}40{"id":"doc-quick_start_react-82349621","source":"documentation","title":"Quick Start – React","url":"https://react.dev/learn","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactCopy pageCopyQuick StartWelcome to the React documentation! This page will give you an introduction to 80% of the React concepts that you will use on a daily basis. You will learn How to create and nest components How to add markup and styles How to display data How to render conditions and lists How to respond to events and update the screen How to share data between components Creating and nesting components React apps are made out of components. A component is a piece of the UI (user interface) that has its own logic and appearance. A component can be as small as a button, or as large as an entire page. React components are JavaScript functions that return MyButton() { return ( <button>I'm a button</button> );} Now that you’ve declared MyButton, you can nest it into another default function MyApp() { return ( <div> <h1>Welcome to my app</h1> <MyButton /> </div> );} Notice that <MyButton /> starts with a capital letter. That’s how you know it’s a React component. React component names must always start with a capital letter, while HTML tags must be lowercase. Have a look at the MyButton() { return ( <button> I'm a button </button> ); } export default function MyApp() { return ( <div> <h1>Welcome to my app</h1> <MyButton /> </div> ); } Show more The export default keywords specify the main component in the file. If you’re not familiar with some piece of JavaScript syntax, MDN and javascript.info have great references. Writing markup with JSX The markup syntax you’ve seen above is called JSX. It is optional, but most React projects use JSX for its convenience. All of the tools we recommend for local development support JSX out of the box. JSX is stricter than HTML. You have to close tags like <br />. Your component also can’t return multiple JSX tags. You have to wrap them into a shared parent, like a <div>...</div> or an empty <>...</> AboutPage() { return ( <> <h1>About</h1> <p>Hello there.<br />How do you do?</p> </> );} If you have a lot of HTML to port to JSX, you can use an online converter. Adding styles In React, you specify a CSS class with className. It works the same way as the HTML class attribute: <img className=\"avatar\" /> Then you write the CSS rules for it in a separate CSS file: /* In your CSS */.avatar { %;} React does not prescribe how you add CSS files. In the simplest case, you’ll add a <link> tag to your HTML. If you use a build tool or a framework, consult its documentation to learn how to add a CSS file to your project. Displaying data JSX lets you put markup into JavaScript. Curly braces let you “escape back” into JavaScript so that you can embed some variable from your code and display it to the user. For example, this will display user.name: return ( <h1> {user.name} </h1>); You can also “escape into JavaScript” from JSX attributes, but you have to use curly braces instead of quotes. For example, className=\"avatar\" passes the \"avatar\" string as the CSS class, but src={user.imageUrl} reads the JavaScript user.imageUrl variable value, and then passes that value as the src ( <img className=\"avatar\" src={user.imageUrl} />); You can put more complex expressions inside the JSX curly braces too, for example, string user = { name: 'Hedy Lamarr', imageUrl: 'https://react.dev/images/docs/scientists/yXOvdOSs.jpg', , }; export default function Profile() { return ( <> <h1>{user.name}</h1> <img className=\"avatar\" src={user.imageUrl} alt={'Photo of ' + user.name} style={{ , }} /> </> ); } Show more In the above example, style={{}} is not a special syntax, but a regular {} object inside the style={ } JSX curly braces. You can use the style attribute when your styles depend on JavaScript variables. Conditional rendering In React, there is no special syntax for writing conditions. Instead, you’ll use the same techniques as you use when writing regular JavaScript code. For example, you can use an if statement to conditionally include content;if (isLoggedIn) { content = <AdminPanel />;} else { content = <LoginForm />;}return ( <div> {content} </div>); If you prefer more compact code, you can use the conditional ? operator. Unlike if, it works inside JSX: <div> {isLoggedIn ? ( <AdminPanel /> ) : ( <LoginForm /> )}</div> When you don’t need the else branch, you can also use a shorter logical && syntax: <div> {isLoggedIn && <AdminPanel />}</div> All of these approaches also work for conditionally specifying attributes. If you’re unfamiliar with some of this JavaScript syntax, you can start by always using if...else. Rendering lists You will rely on JavaScript features like for loop and the array map() function to render lists of components. For example, let’s say you have an array of products = [ { title: 'Cabbage', }, { title: 'Garlic', }, { title: 'Apple', },]; Inside your component, use the map() function to transform an array of products into an array of <li> listItems = products.map(product => <li key={product.id}> {product.title} </li>);return ( <ul>{listItems}</ul>); Notice how <li> has a key attribute. For each item in a list, you should pass a string or a number that uniquely identifies that item among its siblings. Usually, a key should be coming from your data, such as a database ID. React uses your keys to know what happened if you later insert, delete, or reorder the items. App.jsApp.jsReloadClearForkconst products = [ { title: 'Cabbage', , }, { title: 'Garlic', , }, { title: 'Apple', , }, ]; export default function ShoppingList() { const listItems = products.map(product => <li key={product.id} style={{ ? 'magenta' : 'darkgreen' }} > {product.title} </li> ); return ( <ul>{listItems}</ul> ); } Show more Responding to events You can respond to events by declaring event handler functions inside your MyButton() { function handleClick() { alert('You clicked me!'); } return ( <button onClick={handleClick}> Click me </button> );} Notice how onClick={handleClick} has no parentheses at the end! Do not call the event handler only need to pass it down. React will call your event handler when the user clicks the button. Updating the screen Often, you’ll want your component to “remember” some information and display it. For example, maybe you want to count the number of times a button is clicked. To do this, add state to your component. First, import useState from { useState } from 'react'; Now you can declare a state variable inside your MyButton() { const [count, setCount] = useState(0); // ... You’ll get two things from current state (count), and the function that lets you update it (setCount). You can give them any names, but the convention is to write [something, setSomething]. The first time the button is displayed, count will be 0 because you passed 0 to useState(). When you want to change state, call setCount() and pass the new value to it. Clicking this button will increment the MyButton() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <button onClick={handleClick}> Clicked {count} times </button> );} React will call your component function again. This time, count will be 1. Then it will be 2. And so on. If you render the same component multiple times, each will get its own state. Click each button { useState } from 'react'; export default function MyApp() { return ( <div> <h1>Counters that update separately</h1> <MyButton /> <MyButton /> </div> ); } function MyButton() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <button onClick={handleClick}> Clicked {count} times </button> ); } Show more Notice how each button “remembers” its own count state and doesn’t affect other buttons. Using Hooks Functions starting with use are called Hooks. useState is a built-in Hook provided by React. You can find other built-in Hooks in the API reference. You can also write your own Hooks by combining the existing ones. Hooks are more restrictive than other functions. You can only call Hooks at the top of your components (or other Hooks). If you want to use useState in a condition or a loop, extract a new component and put it there. Sharing data between components In the previous example, each MyButton had its own independent count, and when each button was clicked, only the count for the button clicked , each MyButton’s count state is 0The first MyButton updates its count to 1 However, often you’ll need components to share data and always update together. To make both MyButton components display the same count and update together, you need to move the state from the individual buttons “upwards” to the closest component containing all of them. In this example, it is , MyApp’s count state is 0 and is passed down to both childrenOn click, MyApp updates its count state to 1 and passes it down to both children Now when you click either button, the count in MyApp will change, which will change both of the counts in MyButton. Here’s how you can express this in code. First, move the state up from MyButton into default function MyApp() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <div> <h1>Counters that update separately</h1> <MyButton /> <MyButton /> </div> );}function MyButton() { // ... we're moving code from here ...} Then, pass the state down from MyApp to each MyButton, together with the shared click handler. You can pass information to MyButton using the JSX curly braces, just like you previously did with built-in tags like <img>: export default function MyApp() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <div> <h1>Counters that update together</h1> <MyButton count={count} onClick={handleClick} /> <MyButton count={count} onClick={handleClick} /> </div> );} The information you pass down like this is called props. Now the MyApp component contains the count state and the handleClick event handler, and passes both of them down as props to each of the buttons. Finally, change MyButton to read the props you have passed from its parent MyButton({ count, onClick }) { return ( <button onClick={onClick}> Clicked {count} times </button> );} When you click the button, the onClick handler fires. Each button’s onClick prop was set to the handleClick function inside MyApp, so the code inside of it runs. That code calls setCount(count + 1), incrementing the count state variable. The new count value is passed as a prop to each button, so they all show the new value. This is called “lifting state up”. By moving state up, you’ve shared it between components. App.jsApp.jsReloadClearForkimport { useState } from 'react'; export default function MyApp() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <div> <h1>Counters that update together</h1> <MyButton count={count} onClick={handleClick} /> <MyButton count={count} onClick={handleClick} /> </div> ); } function MyButton({ count, onClick }) { return ( <button onClick={onClick}> Clicked {count} times </button> ); } Show more Next Steps By now, you know the basics of how to write React code! Check out the Tutorial to put them into practice and build your first mini-app with React.NextTutorial: Tic-Tac-ToeCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewCreating and nesting components Writing markup with JSX Adding styles Displaying data Conditional rendering Rendering lists Responding to events Updating the screen Using Hooks Sharing data between components Next Steps\n\nExample:\n```javascript\nfunction MyButton() {  return (    <button>I'm a button</button>  );}\n```\n\nExample:\n```javascript\nexport default function MyApp() {  return (    <div>      <h1>Welcome to my app</h1>      <MyButton />    </div>  );}\n```\n\nExample:\n```text\nfunction MyButton() {\n  return (\n    <button>\n      I'm a button\n    </button>\n  );\n}\n\nexport default function MyApp() {\n  return (\n    <div>\n      <h1>Welcome to my app</h1>\n      <MyButton />\n    </div>\n  );\n}\n```\n\nExample:\n```javascript\nfunction AboutPage() {  return (    <>      <h1>About</h1>      <p>Hello there.<br />How do you do?</p>    </>  );}\n```\n\nExample:\n```javascript\n<img className=\"avatar\" />\n```\n\nExample:\n```javascript\n/* In your CSS */.avatar {  border-radius: 50%;}\n```\n\nExample:\n```javascript\nreturn (  <h1>    {user.name}  </h1>);\n```\n\nExample:\n```javascript\nreturn (  <img    className=\"avatar\"    src={user.imageUrl}  />);\n```\n\nExample:\n```text\nconst user = {\n  name: 'Hedy Lamarr',\n  imageUrl: 'https://react.dev/images/docs/scientists/yXOvdOSs.jpg',\n  imageSize: 90,\n};\n\nexport default function Profile() {\n  return (\n    <>\n      <h1>{user.name}</h1>\n      <img\n        className=\"avatar\"\n        src={user.imageUrl}\n        alt={'Photo of ' + user.name}\n        style={{\n          width: user.imageSize,\n          height: user.imageSize\n        }}\n      />\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nlet content;if (isLoggedIn) {  content = <AdminPanel />;} else {  content = <LoginForm />;}return (  <div>    {content}  </div>);\n```\n\nExample:\n```javascript\nconst products = [  { title: 'Cabbage', id: 1 },  { title: 'Garlic', id: 2 },  { title: 'Apple', id: 3 },];\n```\n\nExample:\n```javascript\nconst listItems = products.map(product =>  <li key={product.id}>    {product.title}  </li>);return (  <ul>{listItems}</ul>);\n```\n\nExample:\n```text\nconst products = [\n  { title: 'Cabbage', isFruit: false, id: 1 },\n  { title: 'Garlic', isFruit: false, id: 2 },\n  { title: 'Apple', isFruit: true, id: 3 },\n];\n\nexport default function ShoppingList() {\n  const listItems = products.map(product =>\n    <li\n      key={product.id}\n      style={{\n        color: product.isFruit ? 'magenta' : 'darkgreen'\n      }}\n    >\n      {product.title}\n    </li>\n  );\n\n  return (\n    <ul>{listItems}</ul>\n  );\n}\n```\n\nExample:\n```javascript\nfunction MyButton() {  function handleClick() {    alert('You clicked me!');  }  return (    <button onClick={handleClick}>      Click me    </button>  );}\n```\n\nExample:\n```javascript\nimport { useState } from 'react';\n```\n\nExample:\n```javascript\nfunction MyButton() {  const [count, setCount] = useState(0);  // ...\n```\n\nExample:\n```javascript\nfunction MyButton() {  const [count, setCount] = useState(0);  function handleClick() {    setCount(count + 1);  }  return (    <button onClick={handleClick}>      Clicked {count} times    </button>  );}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function MyApp() {\n  return (\n    <div>\n      <h1>Counters that update separately</h1>\n      <MyButton />\n      <MyButton />\n    </div>\n  );\n}\n\nfunction MyButton() {\n  const [count, setCount] = useState(0);\n\n  function handleClick() {\n    setCount(count + 1);\n  }\n\n  return (\n    <button onClick={handleClick}>\n      Clicked {count} times\n    </button>\n  );\n}\n```\n\nExample:\n```javascript\nexport default function MyApp() {  const [count, setCount] = useState(0);  function handleClick() {    setCount(count + 1);  }  return (    <div>      <h1>Counters that update separately</h1>      <MyButton />      <MyButton />    </div>  );}function MyButton() {  // ... we're moving code from here ...}\n```\n\nExample:\n```javascript\nexport default function MyApp() {  const [count, setCount] = useState(0);  function handleClick() {    setCount(count + 1);  }  return (    <div>      <h1>Counters that update together</h1>      <MyButton count={count} onClick={handleClick} />      <MyButton count={count} onClick={handleClick} />    </div>  );}\n```\n\nExample:\n```javascript\nfunction MyButton({ count, onClick }) {  return (    <button onClick={onClick}>      Clicked {count} times    </button>  );}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function MyApp() {\n  const [count, setCount] = useState(0);\n\n  function handleClick() {\n    setCount(count + 1);\n  }\n\n  return (\n    <div>\n      <h1>Counters that update together</h1>\n      <MyButton count={count} onClick={handleClick} />\n      <MyButton count={count} onClick={handleClick} />\n    </div>\n  );\n}\n\nfunction MyButton({ count, onClick }) {\n  return (\n    <button onClick={onClick}>\n      Clicked {count} times\n    </button>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.926Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":22,"totalLines":218,"estimatedTokens":4417}}41{"id":"doc-installation_react-a98e1a18","source":"documentation","title":"Installation – React","url":"https://react.dev/learn/installation","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactCopy pageCopyInstallationReact has been designed from the start for gradual adoption. You can use as little or as much React as you need. Whether you want to get a taste of React, add some interactivity to an HTML page, or start a complex React-powered app, this section will help you get started. Try React You don’t need to install anything to play with React. Try editing this sandbox! App.jsApp.jsReloadClearForkfunction Greeting({ name }) { return <h1>Hello, {name}</h1>; } export default function App() { return <Greeting name=\"world\" /> } You can edit it directly or open it in a new tab by pressing the “Fork” button in the upper right corner. Most pages in the React documentation contain sandboxes like this. Outside of the React documentation, there are many online sandboxes that support example, CodeSandbox, StackBlitz, or CodePen. To try React locally on your computer, download this HTML page. Open it in your editor and in your browser! Creating a React App If you want to start a new React app, you can create a React app using a recommended framework. Build a React App from Scratch If a framework is not a good fit for your project, you prefer to build your own framework, or you just want to learn the basics of a React app you can build a React app from scratch. Add React to an existing project If want to try using React in your existing app or a website, you can add React to an existing project. NoteShould I use Create React App? No. Create React App has been deprecated. For more information, see Sunsetting Create React App. Next steps Head to the Quick Start guide for a tour of the most important React concepts you will encounter every day.PreviousThinking in ReactNextCreating a React AppCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewTry React Creating a React App Build a React App from Scratch Add React to an existing project Next steps\n\nExample:\n```text\nfunction Greeting({ name }) {\n  return <h1>Hello, {name}</h1>;\n}\n\nexport default function App() {\n  return <Greeting name=\"world\" />\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.927Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":1,"totalLines":14,"estimatedTokens":902}}42{"id":"doc-creating_a_react_app_react-0312f613","source":"documentation","title":"Creating a React App – React","url":"https://react.dev/learn/creating-a-react-app","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactInstallationCopy pageCopyCreating a React AppIf you want to build a new app or website with React, we recommend starting with a framework. If your app has constraints not well-served by existing frameworks, you prefer to build your own framework, or you just want to learn the basics of a React app, you can build a React app from scratch. Full-stack frameworks These recommended frameworks support all the features you need to deploy and scale your app in production. They have integrated the latest React features and take advantage of React’s architecture. NoteFull-stack frameworks do not require a server. All the frameworks on this page support client-side rendering (CSR), single-page apps (SPA), and static-site generation (SSG). These apps can be deployed to a CDN or static hosting service without a server. Additionally, these frameworks allow you to add server-side rendering on a per-route basis, when it makes sense for your use case.This allows you to start with a client-only app, and if your needs change later, you can opt-in to using server features on individual routes without rewriting your app. See your framework’s documentation for configuring the rendering strategy. Next.js (App Router) Next.js’s App Router is a React framework that takes full advantage of React’s architecture to enable full-stack React apps. Terminal Copynpx create-next-app@latest Next.js is maintained by Vercel. You can deploy a Next.js app to any hosting provider that supports Node.js or Docker containers, or to your own server. Next.js also supports static export which doesn’t require a server. React Router (v7) React Router is the most popular routing library for React and can be paired with Vite to create a full-stack React framework. It emphasizes standard Web APIs and has several ready to deploy templates for various JavaScript runtimes and platforms. To create a new React Router framework project, Copynpx create-react-router@latest React Router is maintained by Shopify. Expo (for native apps) Expo is a React framework that lets you create universal Android, iOS, and web apps with truly native UIs. It provides an SDK for React Native that makes the native parts easier to use. To create a new Expo project, Copynpx create-expo-app@latest If you’re new to Expo, check out the Expo tutorial. Expo is maintained by Expo (the company). Building apps with Expo is free, and you can submit them to the Google and Apple app stores without restrictions. Expo additionally provides opt-in paid cloud services. Other frameworks There are other up-and-coming frameworks that are working towards our full stack React Start (Beta): TanStack Start is a full-stack React framework powered by TanStack Router. It provides a full-document SSR, streaming, server functions, bundling, and more using tools like Nitro and Vite. is a full stack React framework with lots of pre-installed packages and configuration that makes it easy to build full-stack web applications. Deep DiveWhich features make up the React team’s full-stack architecture vision? Show DetailsNext.js’s App Router bundler fully implements the official React Server Components specification. This lets you mix build-time, server-only, and interactive components in a single React tree.For example, you can write a server-only React component as an async function that reads from a database or from a file. Then you can pass data down from it to your interactive components:// This component runs *only* on the server (or during the build).async function Talks({ confId }) { // 1. You're on the server, so you can talk to your data layer. API endpoint not required. const talks = await db.Talks.findAll({ confId }); // 2. Add any amount of rendering logic. It won't make your JavaScript bundle larger. const videos = talks.map(talk => talk.video); // 3. Pass the data down to the components that will run in the browser. return <SearchableVideoList videos={videos} />;}Next.js’s App Router also integrates data fetching with Suspense. This lets you specify a loading state (like a skeleton placeholder) for different parts of your user interface directly in your React tree:<Suspense fallback={<TalksLoading />}> <Talks confId={conf.id} /></Suspense>Server Components and Suspense are React features rather than Next.js features. However, adopting them at the framework level requires buy-in and non-trivial implementation work. At the moment, the Next.js App Router is the most complete implementation. The React team is working with bundler developers to make these features easier to implement in the next generation of frameworks. Start From Scratch If your app has constraints not well-served by existing frameworks, you prefer to build your own framework, or you just want to learn the basics of a React app, there are other options available for starting a React project from scratch. Starting from scratch gives you more flexibility, but does require that you make choices on which tools to use for routing, data fetching, and other common usage patterns. It’s a lot like building your own framework, instead of using a framework that already exists. The frameworks we recommend have built-in solutions for these problems. If you want to build your own solutions, see our guide to build a React app from Scratch for instructions on how to set up a new React project starting with a build tool like Vite, Parcel, or RSbuild. If you’re a framework author interested in being included on this page, please let us know.PreviousInstallationNextBuild a React App from ScratchCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewFull-stack frameworks Next.js (App Router) React Router (v7) Expo (for native apps) Other frameworks Start From Scratch\n\nExample:\n```text\nnpx create-next-app@latest\n```\n\nExample:\n```text\nnpx create-react-router@latest\n```\n\nExample:\n```text\nnpx create-expo-app@latest\n```\n\nExample:\n```javascript\n// This component runs *only* on the server (or during the build).async function Talks({ confId }) {  // 1. You're on the server, so you can talk to your data layer. API endpoint not required.  const talks = await db.Talks.findAll({ confId });  // 2. Add any amount of rendering logic. It won't make your JavaScript bundle larger.  const videos = talks.map(talk => talk.video);  // 3. Pass the data down to the components that will run in the browser.  return <SearchableVideoList videos={videos} />;}\n```\n\nExample:\n```javascript\n<Suspense fallback={<TalksLoading />}>  <Talks confId={conf.id} /></Suspense>\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.928Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":5,"totalLines":28,"estimatedTokens":2020}}43{"id":"doc-editor_setup_react-78dc64f3","source":"documentation","title":"Editor Setup – React","url":"https://react.dev/learn/editor-setup","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactSetupCopy pageCopyEditor SetupA properly configured editor can make code clearer to read and faster to write. It can even help you catch bugs as you write them! If this is your first time setting up an editor or you’re looking to tune up your current editor, we have a few recommendations. You will learn What the most popular editors are How to format your code automatically Your editor VS Code is one of the most popular editors in use today. It has a large marketplace of extensions and integrates well with popular services like GitHub. Most of the features listed below can be added to VS Code as extensions as well, making it highly configurable! Other popular text editors used in the React community is an integrated development environment designed specifically for JavaScript. Sublime Text has support for JSX and TypeScript, syntax highlighting and autocomplete built in. Vim is a highly configurable text editor built to make creating and changing any kind of text very efficient. It is included as “vi” with most UNIX systems and with Apple OS X. Recommended text editor features Some editors come with these features built in, but others might require adding an extension. Check to see what support your editor of choice provides to be sure! Linting Code linters find problems in your code as you write, helping you fix them early. ESLint is a popular, open source linter for JavaScript. Install ESLint with the recommended configuration for React (be sure you have Node installed!) Integrate ESLint in VSCode with the official extension Make sure that you’ve enabled all the eslint-plugin-react-hooks rules for your project. They are essential and catch the most severe bugs early. The recommended eslint-config-react-app preset already includes them. Formatting The last thing you want to do when sharing your code with another contributor is get into a discussion about tabs vs spaces! Fortunately, Prettier will clean up your code by reformatting it to conform to preset, configurable rules. Run Prettier, and all your tabs will be converted to spaces—and your indentation, quotes, etc will also all be changed to conform to the configuration. In the ideal setup, Prettier will run when you save your file, quickly making these edits for you. You can install the Prettier extension in VSCode by following these VS Code Use Quick Open (press Ctrl/Cmd+P) Paste in ext install esbenp.prettier-vscode Press Enter Formatting on save Ideally, you should format your code on every save. VS Code has settings for this! In VS Code, press CTRL/CMD + SHIFT + P. Type “settings” Hit Enter In the search bar, type “format on save” Be sure the “format on save” option is ticked! If your ESLint preset has formatting rules, they may conflict with Prettier. We recommend disabling all formatting rules in your ESLint preset using eslint-config-prettier so that ESLint is only used for catching logical mistakes. If you want to enforce that files are formatted before a pull request is merged, use prettier --check for your continuous integration. PreviousSetupNextUsing TypeScriptCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewYour editor Recommended text editor features Linting Formatting\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.928Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":1193}}44{"id":"doc-debugging_and_troubleshooting_react-f18c2209","source":"documentation","title":"Debugging and Troubleshooting – React","url":"https://react.dev/learn/react-compiler/debugging","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactReact CompilerCopy pageCopyDebugging and TroubleshootingThis guide helps you identify and fix issues when using React Compiler. Learn how to debug compilation problems and resolve common issues. You will learn The difference between compiler errors and runtime issues Common patterns that break compilation Step-by-step debugging workflow Understanding Compiler Behavior React Compiler is designed to handle code that follows the Rules of React. When it encounters code that might break these rules, it safely skips optimization rather than risk changing your app’s behavior. Compiler Errors vs Runtime Issues Compiler errors occur at build time and prevent your code from compiling. These are rare because the compiler is designed to skip problematic code rather than fail. Runtime issues occur when compiled code behaves differently than expected. Most of the time, if you encounter an issue with React Compiler, it’s a runtime issue. This typically happens when your code violates the Rules of React in subtle ways that the compiler couldn’t detect, and the compiler mistakenly compiled a component it should have skipped. When debugging runtime issues, focus your efforts on finding Rules of React violations in the affected components that were not detected by the ESLint rule. The compiler relies on your code following these rules, and when they’re broken in ways it can’t detect, that’s when runtime problems occur. Common Breaking Patterns One of the main ways React Compiler can break your app is if your code was written to rely on memoization for correctness. This means your app depends on specific values being memoized to work properly. Since the compiler may memoize differently than your manual approach, this can lead to unexpected behavior like effects over-firing, infinite loops, or missing updates. Common scenarios where this that rely on referential equality - When effects depend on objects or arrays maintaining the same reference across renders Dependency arrays that need stable references - When unstable dependencies cause effects to fire too often or create infinite loops Conditional logic based on reference checks - When code uses referential equality checks for caching or optimization Debugging Workflow Follow these steps when you encounter Build Errors If you encounter a compiler error that unexpectedly breaks your build, this is likely a bug in the compiler. Report it to the react/react repository error message The code that caused the error Your React and compiler versions Runtime Issues For runtime behavior Temporarily Disable Compilation Use \"use no memo\" to isolate whether an issue is ProblematicComponent() { \"use no memo\"; // Skip compilation for this component // ... rest of component} If the issue disappears, it’s likely related to a Rules of React violation. You can also try removing manual memoization (useMemo, useCallback, memo) from the problematic component to verify that your app works correctly without any memoization. If the bug still occurs when all memoization is removed, you have a Rules of React violation that needs to be fixed. 2. Fix Issues Step by Step Identify the root cause (often memoization-for-correctness) Test after each fix Remove \"use no memo\" once fixed Verify the component shows the ✨ badge in React DevTools Reporting Compiler Bugs If you believe you’ve found a compiler it’s not a Rules of React violation - Check with ESLint Create a minimal reproduction - Isolate the issue in a small example Test without the compiler - Confirm the issue only occurs with compilation File an and compiler versions Minimal reproduction code Expected vs actual behavior Any error messages Next Steps Review the Rules of React to prevent issues Check the incremental adoption guide for gradual rollout strategies PreviousIncremental AdoptionCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewUnderstanding Compiler Behavior Compiler Errors vs Runtime Issues Common Breaking Patterns Debugging Workflow Compiler Build Errors Runtime Issues 1. Temporarily Disable Compilation 2. Fix Issues Step by Step Reporting Compiler Bugs Next Steps\n\nExample:\n```javascript\nfunction ProblematicComponent() {  \"use no memo\"; // Skip compilation for this component  // ... rest of component}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.929Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":1,"totalLines":8,"estimatedTokens":1457}}45{"id":"doc-add_react_to_an_existing_project_react-628c7f12","source":"documentation","title":"Add React to an Existing Project – React","url":"https://react.dev/learn/add-react-to-an-existing-project","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactInstallationCopy pageCopyAdd React to an Existing ProjectIf you want to add some interactivity to your existing project, you don’t have to rewrite it in React. Add React to your existing stack, and render interactive React components anywhere. NoteYou need to install Node.js for local development. Although you can try React online or with a simple HTML page, realistically most JavaScript tooling you’ll want to use for development requires Node.js. Using React for an entire subroute of your existing website Let’s say you have an existing web app at example.com built with another server technology (like Rails), and you want to implement all routes starting with example.com/some-app/ fully with React. Here’s how we recommend to set it the React part of your app using one of the React-based frameworks. Specify /some-app as the base path in your framework’s configuration (here’s , Gatsby). Configure your server or a proxy so that all requests under /some-app/ are handled by your React app. This ensures the React part of your app can benefit from the best practices baked into those frameworks. Many React-based frameworks are full-stack and let your React app take advantage of the server. However, you can use the same approach even if you can’t or don’t want to run JavaScript on the server. In that case, serve the HTML/CSS/JS export (next export output for Next.js, default for Gatsby) at /some-app/ instead. Using React for a part of your existing page Let’s say you have an existing page built with another technology (either a server one like Rails, or a client one like Backbone), and you want to render interactive React components somewhere on that page. That’s a common way to integrate React—in fact, it’s how most React usage looked at Meta for many years! You can do this in two up a JavaScript environment that lets you use the JSX syntax, split your code into modules with the import / export syntax, and use packages (for example, React) from the npm package registry. Render your React components where you want to see them on the page. The exact approach depends on your existing page setup, so let’s walk through some details. Step up a modular JavaScript environment A modular JavaScript environment lets you write your React components in individual files, as opposed to writing all of your code in a single file. It also lets you use all the wonderful packages published by other developers on the npm registry—including React itself! How you do this depends on your existing your app is already split into files that use import statements, try to use the setup you already have. Check whether writing <div /> in your JS code causes a syntax error. If it causes a syntax error, you might need to transform your JavaScript code with Babel, and enable the Babel React preset to use JSX. If your app doesn’t have an existing setup for compiling JavaScript modules, set it up with Vite. The Vite community maintains many integrations with backend frameworks, including Rails, Django, and Laravel. If your backend framework is not listed, follow this guide to manually integrate Vite builds with your backend. To check whether your setup works, run this command in your project Copynpm install react react-dom Then add these lines of code at the top of your main JavaScript file (it might be called index.js or main.js): index.jsindex.jsReloadClearForkimport { createRoot } from 'react-dom/client'; // Clear the existing HTML content document.body.innerHTML = '<div id=\"app\"></div>'; // Render your React component instead const root = createRoot(document.getElementById('app')); root.render(<h1>Hello, world</h1>); If the entire content of your page was replaced by a “Hello, world!”, everything worked! Keep reading. NoteIntegrating a modular JavaScript environment into an existing project for the first time can feel intimidating, but it’s worth it! If you get stuck, try our community resources or the Vite Chat. Step React components anywhere on the page In the previous step, you put this code at the top of your main { createRoot } from 'react-dom/client';// Clear the existing HTML contentdocument.body.innerHTML = '<div id=\"app\"></div>';// Render your React component insteadconst root = createRoot(document.getElementById('app'));root.render(<h1>Hello, world</h1>); Of course, you don’t actually want to clear the existing HTML content! Delete this code. Instead, you probably want to render your React components in specific places in your HTML. Open your HTML page (or the server templates that generate it) and add a unique id attribute to any tag, for example: <!-- ... somewhere in your html ... --><nav id=\"navigation\"></nav><!-- ... more html ... --> This lets you find that HTML element with document.getElementById and pass it to createRoot so that you can render your own React component { createRoot } from 'react-dom/client'; function NavigationBar() { // implement a navigation bar return <h1>Hello from React!</h1>; } const domNode = document.getElementById('navigation'); const root = createRoot(domNode); root.render(<NavigationBar />); Notice how the original HTML content from index.html is preserved, but your own NavigationBar React component now appears inside the <nav id=\"navigation\"> from your HTML. Read the createRoot usage documentation to learn more about rendering React components inside an existing HTML page. When you adopt React in an existing project, it’s common to start with small interactive components (like buttons), and then gradually keep “moving upwards” until eventually your entire page is built with React. If you ever reach that point, we recommend migrating to a React framework right after to get the most out of React. Using React Native in an existing native mobile app React Native can also be integrated into existing native apps incrementally. If you have an existing native app for Android (Java or Kotlin) or iOS (Objective-C or Swift), follow this guide to add a React Native screen to it.PreviousBuild a React App from ScratchNextSetupCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewUsing React for an entire subroute of your existing website Using React for a part of your existing page Step up a modular JavaScript environment Step React components anywhere on the page Using React Native in an existing native mobile app\n\nExample:\n```text\nnpm install react react-dom\n```\n\nExample:\n```text\nimport { createRoot } from 'react-dom/client';\n\n// Clear the existing HTML content\ndocument.body.innerHTML = '<div id=\"app\"></div>';\n\n// Render your React component instead\nconst root = createRoot(document.getElementById('app'));\nroot.render(<h1>Hello, world</h1>);\n```\n\nExample:\n```javascript\nimport { createRoot } from 'react-dom/client';// Clear the existing HTML contentdocument.body.innerHTML = '<div id=\"app\"></div>';// Render your React component insteadconst root = createRoot(document.getElementById('app'));root.render(<h1>Hello, world</h1>);\n```\n\nExample:\n```javascript\n<!-- ... somewhere in your html ... --><nav id=\"navigation\"></nav><!-- ... more html ... -->\n```\n\nExample:\n```text\nimport { createRoot } from 'react-dom/client';\n\nfunction NavigationBar() {\n  // TODO: Actually implement a navigation bar\n  return <h1>Hello from React!</h1>;\n}\n\nconst domNode = document.getElementById('navigation');\nconst root = createRoot(domNode);\nroot.render(<NavigationBar />);\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.930Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":5,"totalLines":44,"estimatedTokens":2238}}46{"id":"doc-understanding_your_ui_as_a_tree_react-3c301096","source":"documentation","title":"Understanding Your UI as a Tree – React","url":"https://react.dev/learn/understanding-your-ui-as-a-tree","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactDescribing the UICopy pageCopyUnderstanding Your UI as a TreeYour React app is taking shape with many components being nested within each other. How does React keep track of your app’s component structure?React, and many other UI libraries, model UI as a tree. Thinking of your app as a tree is useful for understanding the relationship between components. This understanding will help you debug future concepts like performance and state management. You will learn How React “sees” component structures What a render tree is and what it is useful for What a module dependency tree is and what it is useful for Your UI as a tree Trees are a relationship model between items. The UI is often represented using tree structures. For example, browsers use tree structures to model HTML (DOM) and CSS (CSSOM). Mobile platforms also use trees to represent their view hierarchy. React creates a UI tree from your components. In this example, the UI tree is then used to render to the DOM. Like browsers and mobile platforms, React also uses tree structures to manage and model the relationship between components in a React app. These trees are useful tools to understand how data flows through a React app and how to optimize rendering and app size. The Render Tree A major feature of components is the ability to compose components of other components. As we nest components, we have the concept of parent and child components, where each parent component may itself be a child of another component. When we render a React app, we can model this relationship in a tree, known as the render tree. Here is a React app that renders inspirational quotes. App.jsFancyText.jsInspirationGenerator.jsCopyright.jsquotes.jsApp.jsReloadClearForkimport FancyText from './FancyText'; import InspirationGenerator from './InspirationGenerator'; import Copyright from './Copyright'; export default function App() { return ( <> <FancyText title text=\"Get Inspired App\" /> <InspirationGenerator> <Copyright year={2004} /> </InspirationGenerator> </> ); } React creates a render tree, a UI tree, composed of the rendered components. From the example app, we can construct the above render tree. The tree is composed of nodes, each of which represents a component. App, FancyText, Copyright, to name a few, are all nodes in our tree. The root node in a React render tree is the root component of the app. In this case, the root component is App and it is the first component React renders. Each arrow in the tree points from a parent component to a child component. Deep DiveWhere are the HTML tags in the render tree? Show DetailsYou’ll notice in the above render tree, there is no mention of the HTML tags that each component renders. This is because the render tree is only composed of React components.React, as a UI framework, is platform agnostic. On react.dev, we showcase examples that render to the web, which uses HTML markup as its UI primitives. But a React app could just as likely render to a mobile or desktop platform, which may use different UI primitives like UIView or FrameworkElement.These platform UI primitives are not a part of React. React render trees can provide insight to our React app regardless of what platform your app renders to. A render tree represents a single render pass of a React application. With conditional rendering, a parent component may render different children depending on the data passed. We can update the app to conditionally render either an inspirational quote or color. App.jsFancyText.jsColor.jsInspirationGenerator.jsCopyright.jsinspirations.jsApp.jsReloadClearForkimport FancyText from './FancyText'; import InspirationGenerator from './InspirationGenerator'; import Copyright from './Copyright'; export default function App() { return ( <> <FancyText title text=\"Get Inspired App\" /> <InspirationGenerator> <Copyright year={2004} /> </InspirationGenerator> </> ); } With conditional rendering, across different renders, the render tree may render different components. In this example, depending on what inspiration.type is, we may render <FancyText> or <Color>. The render tree may be different for each render pass. Although render trees may differ across render passes, these trees are generally helpful for identifying what the top-level and leaf components are in a React app. Top-level components are the components nearest to the root component and affect the rendering performance of all the components beneath them and often contain the most complexity. Leaf components are near the bottom of the tree and have no child components and are often frequently re-rendered. Identifying these categories of components are useful for understanding data flow and performance of your app. The Module Dependency Tree Another relationship in a React app that can be modeled with a tree are an app’s module dependencies. As we break up our components and logic into separate files, we create JS modules where we may export components, functions, or constants. Each node in a module dependency tree is a module and each branch represents an import statement in that module. If we take the previous Inspirations app, we can build a module dependency tree, or dependency tree for short. The module dependency tree for the Inspirations app. The root node of the tree is the root module, also known as the entrypoint file. It often is the module that contains the root component. Comparing to the render tree of the same app, there are similar structures but some notable nodes that make-up the tree represent modules, not components. Non-component modules, like inspirations.js, are also represented in this tree. The render tree only encapsulates components. Copyright.js appears under App.js but in the render tree, Copyright, the component, appears as a child of InspirationGenerator. This is because InspirationGenerator accepts JSX as children props, so it renders Copyright as a child component but does not import the module. Dependency trees are useful to determine what modules are necessary to run your React app. When building a React app for production, there is typically a build step that will bundle all the necessary JavaScript to ship to the client. The tool responsible for this is called a bundler, and bundlers will use the dependency tree to determine what modules should be included. As your app grows, often the bundle size does too. Large bundle sizes are expensive for a client to download and run. Large bundle sizes can delay the time for your UI to get drawn. Getting a sense of your app’s dependency tree may help with debugging these issues. Recap Trees are a common way to represent the relationship between entities. They are often used to model UI. Render trees represent the nested relationship between React components across a single render. With conditional rendering, the render tree may change across different renders. With different prop values, components may render different children components. Render trees help identify what the top-level and leaf components are. Top-level components affect the rendering performance of all components beneath them and leaf components are often re-rendered frequently. Identifying them is useful for understanding and debugging rendering performance. Dependency trees represent the module dependencies in a React app. Dependency trees are used by build tools to bundle the necessary code to ship an app. Dependency trees are useful for debugging large bundle sizes that slow time to paint and expose opportunities for optimizing what code is bundled. PreviousKeeping Components PureNextAdding InteractivityCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewYour UI as a tree The Render Tree The Module Dependency Tree Recap\n\nExample:\n```text\nimport FancyText from './FancyText';\nimport InspirationGenerator from './InspirationGenerator';\nimport Copyright from './Copyright';\n\nexport default function App() {\n  return (\n    <>\n      <FancyText title text=\"Get Inspired App\" />\n      <InspirationGenerator>\n        <Copyright year={2004} />\n      </InspirationGenerator>\n    </>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.931Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":1,"totalLines":21,"estimatedTokens":2418}}47{"id":"doc-introduction_react-0cc5c69a","source":"documentation","title":"Introduction – React","url":"https://react.dev/learn/react-compiler/introduction","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactReact CompilerCopy pageCopyIntroductionReact Compiler is a new build-time tool that automatically optimizes your React app. It works with plain JavaScript, and understands the Rules of React, so you don’t need to rewrite any code to use it. You will learn What React Compiler does Getting started with the compiler Incremental adoption strategies Debugging and troubleshooting when things go wrong Using the compiler on your React library What does React Compiler do? React Compiler automatically optimizes your React application at build time. React is often fast enough without optimization, but sometimes you need to manually memoize components and values to keep your app responsive. This manual memoization is tedious, easy to get wrong, and adds extra code to maintain. React Compiler does this optimization automatically for you, freeing you from this mental burden so you can focus on building features. Before React Compiler Without the compiler, you need to manually memoize components and values to optimize { useMemo, useCallback, memo } from 'react';const ExpensiveComponent = memo(function ExpensiveComponent({ data, onClick }) { const processedData = useMemo(() => { return expensiveProcessing(data); }, [data]); const handleClick = useCallback((item) => { onClick(item.id); }, [onClick]); return ( <div> {processedData.map(item => ( <Item key={item.id} onClick={() => handleClick(item)} /> ))} </div> );}); NoteThis manual memoization has a subtle bug that breaks memoization:<Item key={item.id} onClick={() => handleClick(item)} />Even though handleClick is wrapped in useCallback, the arrow function () => handleClick(item) creates a new function every time the component renders. This means that Item will always receive a new onClick prop, breaking memoization.React Compiler is able to optimize this correctly with or without the arrow function, ensuring that Item only re-renders when props.onClick changes. After React Compiler With React Compiler, you write the same code without manual ExpensiveComponent({ data, onClick }) { const processedData = expensiveProcessing(data); const handleClick = (item) => { onClick(item.id); }; return ( <div> {processedData.map(item => ( <Item key={item.id} onClick={() => handleClick(item)} /> ))} </div> );} See this example in the React Compiler Playground React Compiler automatically applies the optimal memoization, ensuring your app only re-renders when necessary. Deep DiveWhat kind of memoization does React Compiler add? Show DetailsReact Compiler’s automatic memoization is primarily focused on improving update performance (re-rendering existing components), so it focuses on these two use cascading re-rendering of components Re-rendering <Parent /> causes many components in its component tree to re-render, even though only <Parent /> has changed Skipping expensive calculations from outside of React For example, calling expensivelyProcessAReallyLargeArrayOfObjects() inside of your component or hook that needs that data Optimizing Re-renders React lets you express your UI as a function of their current state (more props, state, and context). In its current implementation, when a component’s state changes, React will re-render that component and all of its children — unless you have applied some form of manual memoization with useMemo(), useCallback(), or React.memo(). For example, in the following example, <MessageButton> will re-render whenever <FriendList>’s state FriendList({ friends }) { const onlineCount = useFriendOnlineCount(); if (friends.length === 0) { return <NoFriends />; } return ( <div> <span>{onlineCount} online</span> {friends.map((friend) => ( <FriendListCard key={friend.id} friend={friend} /> ))} <MessageButton /> </div> );}See this example in the React Compiler PlaygroundReact Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as “fine-grained reactivity”. In the above example, React Compiler determines that the return value of <FriendListCard /> can be reused even as friends changes, and can avoid recreating this JSX and avoid re-rendering <MessageButton> as the count changes.Expensive calculations also get memoized React Compiler can also automatically memoize expensive calculations used during rendering:// **Not** memoized by React Compiler, since this is not a component or hookfunction expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ }// Memoized by React Compiler since this is a componentfunction TableContainer({ items }) { // This function call would be data = expensivelyProcessAReallyLargeArrayOfObjects(items); // ...}See this example in the React Compiler PlaygroundHowever, if expensivelyProcessAReallyLargeArrayOfObjects is truly an expensive function, you may want to consider implementing its own memoization outside of React, Compiler only memoizes React components and hooks, not every function React Compiler’s memoization is not shared across multiple components or hooks So if expensivelyProcessAReallyLargeArrayOfObjects was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend profiling first to see if it really is that expensive before making code more complicated. Should I try out the compiler? We encourage everyone to start using React Compiler. While the compiler is still an optional addition to React today, in the future some features may require the compiler in order to fully work. Is it safe to use? React Compiler is now stable and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you’ve followed the Rules of React. What build tools are supported? React Compiler can be installed across several build tools such as Babel, Vite, Metro, and Rsbuild. React Compiler is primarily a light Babel plugin wrapper around the core compiler, which was designed to be decoupled from Babel itself. While the initial stable version of the compiler will remain primarily a Babel plugin, we are working with the swc and oxc teams to build first class support for React Compiler so you won’t have to add Babel back to your build pipelines in the future. Next.js users can enable the swc-invoked React Compiler by using v15.3.1 and up. What should I do about useMemo, useCallback, and React.memo? By default, React Compiler will memoize your code based on its analysis and heuristics. In most cases, this memoization will be as precise, or moreso, than what you may have written. However, in some cases developers may need more control over memoization. The useMemo and useCallback hooks can continue to be used with React Compiler as an escape hatch to provide control over which values are memoized. A common use-case for this is if a memoized value is used as an effect dependency, in order to ensure that an effect does not fire repeatedly even when its dependencies do not meaningfully change. For new code, we recommend relying on the compiler for memoization and using useMemo/useCallback where needed to achieve precise control. For existing code, we recommend either leaving existing memoization in place (removing it can change compilation output) or carefully testing before removing the memoization. Try React Compiler This section will help you get started with React Compiler and understand how to use it effectively in your projects. Installation - Install React Compiler and configure it for your build tools React Version Compatibility - Support for React 17, 18, and 19 Configuration - Customize the compiler for your specific needs Incremental Adoption - Strategies for gradually rolling out the compiler in existing codebases Debugging and Troubleshooting - Identify and fix issues when using the compiler Compiling Libraries - Best practices for shipping compiled code API Reference - Detailed documentation of all configuration options Additional resources In addition to these docs, we recommend checking the React Compiler Working Group for additional information and discussion about the compiler.PreviousReact CompilerNextInstallationCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewWhat does React Compiler do? Before React Compiler After React Compiler Should I try out the compiler? Is it safe to use? What build tools are supported? What should I do about useMemo, useCallback, and React.memo? Try React Compiler Additional resources\n\nExample:\n```javascript\nimport { useMemo, useCallback, memo } from 'react';const ExpensiveComponent = memo(function ExpensiveComponent({ data, onClick }) {  const processedData = useMemo(() => {    return expensiveProcessing(data);  }, [data]);  const handleClick = useCallback((item) => {    onClick(item.id);  }, [onClick]);  return (    <div>      {processedData.map(item => (        <Item key={item.id} onClick={() => handleClick(item)} />      ))}    </div>  );});\n```\n\nExample:\n```javascript\n<Item key={item.id} onClick={() => handleClick(item)} />\n```\n\nExample:\n```javascript\nfunction ExpensiveComponent({ data, onClick }) {  const processedData = expensiveProcessing(data);  const handleClick = (item) => {    onClick(item.id);  };  return (    <div>      {processedData.map(item => (        <Item key={item.id} onClick={() => handleClick(item)} />      ))}    </div>  );}\n```\n\nExample:\n```javascript\nfunction FriendList({ friends }) {  const onlineCount = useFriendOnlineCount();  if (friends.length === 0) {    return <NoFriends />;  }  return (    <div>      <span>{onlineCount} online</span>      {friends.map((friend) => (        <FriendListCard key={friend.id} friend={friend} />      ))}      <MessageButton />    </div>  );}\n```\n\nExample:\n```javascript\n// **Not** memoized by React Compiler, since this is not a component or hookfunction expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ }// Memoized by React Compiler since this is a componentfunction TableContainer({ items }) {  // This function call would be memoized:  const data = expensivelyProcessAReallyLargeArrayOfObjects(items);  // ...}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.932Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":5,"totalLines":28,"estimatedTokens":2951}}48{"id":"doc-describing_the_ui_react-7122f123","source":"documentation","title":"Describing the UI – React","url":"https://react.dev/learn/describing-the-ui","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactCopy pageCopyDescribing the UIReact is a JavaScript library for rendering user interfaces (UI). UI is built from small units like buttons, text, and images. React lets you combine them into reusable, nestable components. From web sites to phone apps, everything on the screen can be broken down into components. In this chapter, you’ll learn to create, customize, and conditionally display React components. In this chapter How to write your first React component When and how to create multi-component files How to add markup to JavaScript with JSX How to use curly braces with JSX to access JavaScript functionality from your components How to configure components with props How to conditionally render components How to render multiple components at a time How to avoid confusing bugs by keeping components pure Why understanding your UI as trees is useful Your first component React applications are built from isolated pieces of UI called components. A React component is a JavaScript function that you can sprinkle with markup. Components can be as small as a button, or as large as an entire page. Here is a Gallery component rendering three Profile Profile() { return ( <img src=\"https://react.dev/images/docs/scientists/MK3eW3As.jpg\" alt=\"Katherine Johnson\" /> ); } export default function Gallery() { return ( <section> <h1>Amazing scientists</h1> <Profile /> <Profile /> <Profile /> </section> ); } Show more Ready to learn this topic?Read Your First Component to learn how to declare and use React components.Read More Importing and exporting components You can declare many components in one file, but large files can get difficult to navigate. To solve this, you can export a component into its own file, and then import that component from another Profile from './Profile.js'; export default function Gallery() { return ( <section> <h1>Amazing scientists</h1> <Profile /> <Profile /> <Profile /> </section> ); } Ready to learn this topic?Read Importing and Exporting Components to learn how to split components into their own files.Read More Writing markup with JSX Each React component is a JavaScript function that may contain some markup that React renders into the browser. React components use a syntax extension called JSX to represent that markup. JSX looks a lot like HTML, but it is a bit stricter and can display dynamic information. If we paste existing HTML markup into a React component, it won’t always default function TodoList() { return ( // This doesn't quite work! <h1>Hedy Lamarr's Todos</h1> <img src=\"https://react.dev/images/docs/scientists/yXOvdOSs.jpg\" alt=\"Hedy Lamarr\" class=\"photo\" > <ul> <li>Invent new traffic lights <li>Rehearse a movie scene <li>Improve spectrum technology </ul> Show more If you have existing HTML like this, you can fix it using a default function TodoList() { return ( <> <h1>Hedy Lamarr's Todos</h1> <img src=\"https://react.dev/images/docs/scientists/yXOvdOSs.jpg\" alt=\"Hedy Lamarr\" className=\"photo\" /> <ul> <li>Invent new traffic lights</li> <li>Rehearse a movie scene</li> <li>Improve spectrum technology</li> </ul> </> ); } Show more Ready to learn this topic?Read Writing Markup with JSX to learn how to write valid JSX.Read More JavaScript in JSX with curly braces JSX lets you write HTML-like markup inside a JavaScript file, keeping rendering logic and content in the same place. Sometimes you will want to add a little JavaScript logic or reference a dynamic property inside that markup. In this situation, you can use curly braces in your JSX to “open a window” to person = { name: 'Gregorio Y. Zara', theme: { backgroundColor: 'black', color: 'pink' } }; export default function TodoList() { return ( <div style={person.theme}> <h1>{person.name}'s Todos</h1> <img className=\"avatar\" src=\"https://react.dev/images/docs/scientists/7vQD0fPs.jpg\" alt=\"Gregorio Y. Zara\" /> <ul> <li>Improve the videophone</li> <li>Prepare aeronautics lectures</li> <li>Work on the alcohol-fuelled engine</li> </ul> </div> ); } Show more Ready to learn this topic?Read JavaScript in JSX with Curly Braces to learn how to access JavaScript data from JSX.Read More Passing props to a component React components use props to communicate with each other. Every parent component can pass some information to its child components by giving them props. Props might remind you of HTML attributes, but you can pass any JavaScript value through them, including objects, arrays, functions, and even JSX! App.jsutils.jsApp.jsReloadClearForkimport { getImageUrl } from './utils.js' export default function Profile() { return ( <Card> <Avatar size={100} person={{ name: 'Katsuko Saruhashi', imageId: 'YfeOqp2' }} /> </Card> ); } function Avatar({ person, size }) { return ( <img className=\"avatar\" src={getImageUrl(person)} alt={person.name} width={size} height={size} /> ); } function Card({ children }) { return ( <div className=\"card\"> {children} </div> ); } Show more Ready to learn this topic?Read Passing Props to a Component to learn how to pass and read props.Read More Conditional rendering Your components will often need to display different things depending on different conditions. In React, you can conditionally render JSX using JavaScript syntax like if statements, &&, and ? : operators. In this example, the JavaScript && operator is used to conditionally render a Item({ name, isPacked }) { return ( <li className=\"item\"> {name} {isPacked && '✅'} </li> ); } export default function PackingList() { return ( <section> <h1>Sally Ride's Packing List</h1> <ul> <Item isPacked={true} name=\"Space suit\" /> <Item isPacked={true} name=\"Helmet with a golden leaf\" /> <Item isPacked={false} name=\"Photo of Tam\" /> </ul> </section> ); } Show more Ready to learn this topic?Read Conditional Rendering to learn the different ways to render content conditionally.Read More Rendering lists You will often want to display multiple similar components from a collection of data. You can use JavaScript’s filter() and map() with React to filter and transform your array of data into an array of components. For each array item, you will need to specify a key. Usually, you will want to use an ID from the database as a key. Keys let React keep track of each item’s place in the list even if the list changes. App.jsdata.jsutils.jsApp.jsReloadClearForkimport { people } from './data.js'; import { getImageUrl } from './utils.js'; export default function List() { const listItems = people.map(person => <li key={person.id}> <img src={getImageUrl(person)} alt={person.name} /> <p> <b>{person.name}:</b> {' ' + person.profession + ' '} known for {person.accomplishment} </p> </li> ); return ( <article> <h1>Scientists</h1> <ul>{listItems}</ul> </article> ); } Show more Ready to learn this topic?Read Rendering Lists to learn how to render a list of components, and how to choose a key.Read More Keeping components pure Some JavaScript functions are pure. A pure its own business. It does not change any objects or variables that existed before it was called. Same inputs, same output. Given the same inputs, a pure function should always return the same result. By strictly only writing your components as pure functions, you can avoid an entire class of baffling bugs and unpredictable behavior as your codebase grows. Here is an example of an impure guest = 0; function Cup() { // a preexisting variable! guest = guest + 1; return <h2>Tea cup for guest #{guest}</h2>; } export default function TeaSet() { return ( <> <Cup /> <Cup /> <Cup /> </> ); } Show more You can make this component pure by passing a prop instead of modifying a preexisting Cup({ guest }) { return <h2>Tea cup for guest #{guest}</h2>; } export default function TeaSet() { return ( <> <Cup guest={1} /> <Cup guest={2} /> <Cup guest={3} /> </> ); } Ready to learn this topic?Read Keeping Components Pure to learn how to write components as pure, predictable functions.Read More Your UI as a tree React uses trees to model the relationships between components and modules. A React render tree is a representation of the parent and child relationship between components. An example React render tree. Components near the top of the tree, near the root component, are considered top-level components. Components with no child components are leaf components. This categorization of components is useful for understanding data flow and rendering performance. Modelling the relationship between JavaScript modules is another useful way to understand your app. We refer to it as a module dependency tree. An example module dependency tree. A dependency tree is often used by build tools to bundle all the relevant JavaScript code for the client to download and render. A large bundle size regresses user experience for React apps. Understanding the module dependency tree is helpful to debug such issues. Ready to learn this topic?Read Your UI as a Tree to learn how to create a render and module dependency trees for a React app and how they’re useful mental models for improving user experience and performance.Read More What’s next? Head over to Your First Component to start reading this chapter page by page! Or, if you’re already familiar with these topics, why not read about Adding Interactivity?NextYour First ComponentCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewYour first component Importing and exporting components Writing markup with JSX JavaScript in JSX with curly braces Passing props to a component Conditional rendering Rendering lists Keeping components pure Your UI as a tree What’s next?\n\nExample:\n```text\nfunction Profile() {\n  return (\n    <img\n      src=\"https://react.dev/images/docs/scientists/MK3eW3As.jpg\"\n      alt=\"Katherine Johnson\"\n    />\n  );\n}\n\nexport default function Gallery() {\n  return (\n    <section>\n      <h1>Amazing scientists</h1>\n      <Profile />\n      <Profile />\n      <Profile />\n    </section>\n  );\n}\n```\n\nExample:\n```text\nimport Profile from './Profile.js';\n\nexport default function Gallery() {\n  return (\n    <section>\n      <h1>Amazing scientists</h1>\n      <Profile />\n      <Profile />\n      <Profile />\n    </section>\n  );\n}\n```\n\nExample:\n```text\nexport default function TodoList() {\n  return (\n    // This doesn't quite work!\n    <h1>Hedy Lamarr's Todos</h1>\n    <img\n      src=\"https://react.dev/images/docs/scientists/yXOvdOSs.jpg\"\n      alt=\"Hedy Lamarr\"\n      class=\"photo\"\n    >\n    <ul>\n      <li>Invent new traffic lights\n      <li>Rehearse a movie scene\n      <li>Improve spectrum technology\n    </ul>\n```\n\nExample:\n```text\nexport default function TodoList() {\n  return (\n    <>\n      <h1>Hedy Lamarr's Todos</h1>\n      <img\n        src=\"https://react.dev/images/docs/scientists/yXOvdOSs.jpg\"\n        alt=\"Hedy Lamarr\"\n        className=\"photo\"\n      />\n      <ul>\n        <li>Invent new traffic lights</li>\n        <li>Rehearse a movie scene</li>\n        <li>Improve spectrum technology</li>\n      </ul>\n    </>\n  );\n}\n```\n\nExample:\n```text\nconst person = {\n  name: 'Gregorio Y. Zara',\n  theme: {\n    backgroundColor: 'black',\n    color: 'pink'\n  }\n};\n\nexport default function TodoList() {\n  return (\n    <div style={person.theme}>\n      <h1>{person.name}'s Todos</h1>\n      <img\n        className=\"avatar\"\n        src=\"https://react.dev/images/docs/scientists/7vQD0fPs.jpg\"\n        alt=\"Gregorio Y. Zara\"\n      />\n      <ul>\n        <li>Improve the videophone</li>\n        <li>Prepare aeronautics lectures</li>\n        <li>Work on the alcohol-fuelled engine</li>\n      </ul>\n    </div>\n  );\n}\n```\n\nExample:\n```text\nimport { getImageUrl } from './utils.js'\n\nexport default function Profile() {\n  return (\n    <Card>\n      <Avatar\n        size={100}\n        person={{\n          name: 'Katsuko Saruhashi',\n          imageId: 'YfeOqp2'\n        }}\n      />\n    </Card>\n  );\n}\n\nfunction Avatar({ person, size }) {\n  return (\n    <img\n      className=\"avatar\"\n      src={getImageUrl(person)}\n      alt={person.name}\n      width={size}\n      height={size}\n    />\n  );\n}\n\nfunction Card({ children }) {\n  return (\n    <div className=\"card\">\n      {children}\n    </div>\n  );\n}\n```\n\nExample:\n```text\nfunction Item({ name, isPacked }) {\n  return (\n    <li className=\"item\">\n      {name} {isPacked && '✅'}\n    </li>\n  );\n}\n\nexport default function PackingList() {\n  return (\n    <section>\n      <h1>Sally Ride's Packing List</h1>\n      <ul>\n        <Item\n          isPacked={true}\n          name=\"Space suit\"\n        />\n        <Item\n          isPacked={true}\n          name=\"Helmet with a golden leaf\"\n        />\n        <Item\n          isPacked={false}\n          name=\"Photo of Tam\"\n        />\n      </ul>\n    </section>\n  );\n}\n```\n\nExample:\n```text\nimport { people } from './data.js';\nimport { getImageUrl } from './utils.js';\n\nexport default function List() {\n  const listItems = people.map(person =>\n    <li key={person.id}>\n      <img\n        src={getImageUrl(person)}\n        alt={person.name}\n      />\n      <p>\n        <b>{person.name}:</b>\n        {' ' + person.profession + ' '}\n        known for {person.accomplishment}\n      </p>\n    </li>\n  );\n  return (\n    <article>\n      <h1>Scientists</h1>\n      <ul>{listItems}</ul>\n    </article>\n  );\n}\n```\n\nExample:\n```text\nlet guest = 0;\n\nfunction Cup() {\n  // Bad: changing a preexisting variable!\n  guest = guest + 1;\n  return <h2>Tea cup for guest #{guest}</h2>;\n}\n\nexport default function TeaSet() {\n  return (\n    <>\n      <Cup />\n      <Cup />\n      <Cup />\n    </>\n  );\n}\n```\n\nExample:\n```text\nfunction Cup({ guest }) {\n  return <h2>Tea cup for guest #{guest}</h2>;\n}\n\nexport default function TeaSet() {\n  return (\n    <>\n      <Cup guest={1} />\n      <Cup guest={2} />\n      <Cup guest={3} />\n    </>\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.933Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":10,"totalLines":248,"estimatedTokens":3804}}49{"id":"doc-your_first_component_react-203ca76d","source":"documentation","title":"Your First Component – React","url":"https://react.dev/learn/your-first-component","text":"Example:\n```javascript\n<article>  <h1>My First Component</h1>  <ol>    <li>Components: UI Building Blocks</li>    <li>Defining a Component</li>    <li>Using a Component</li>  </ol></article>\n```\n\nExample:\n```javascript\n<PageLayout>  <NavigationHeader>    <SearchBar />    <Link to=\"/docs\">Docs</Link>  </NavigationHeader>  <Sidebar />  <PageContent>    <TableOfContents />    <DocumentationText />  </PageContent></PageLayout>\n```\n\nExample:\n```text\nexport default function Profile() {\n  return (\n    <img\n      src=\"https://react.dev/images/docs/scientists/MK3eW3Am.jpg\"\n      alt=\"Katherine Johnson\"\n    />\n  )\n}\n```\n\nExample:\n```javascript\nreturn <img src=\"https://react.dev/images/docs/scientists/MK3eW3As.jpg\" alt=\"Katherine Johnson\" />;\n```\n\nExample:\n```javascript\nreturn (  <div>    <img src=\"https://react.dev/images/docs/scientists/MK3eW3As.jpg\" alt=\"Katherine Johnson\" />  </div>);\n```\n\nExample:\n```text\nfunction Profile() {\n  return (\n    <img\n      src=\"https://react.dev/images/docs/scientists/MK3eW3As.jpg\"\n      alt=\"Katherine Johnson\"\n    />\n  );\n}\n\nexport default function Gallery() {\n  return (\n    <section>\n      <h1>Amazing scientists</h1>\n      <Profile />\n      <Profile />\n      <Profile />\n    </section>\n  );\n}\n```\n\nExample:\n```javascript\n<section>  <h1>Amazing scientists</h1>  <img src=\"https://react.dev/images/docs/scientists/MK3eW3As.jpg\" alt=\"Katherine Johnson\" />  <img src=\"https://react.dev/images/docs/scientists/MK3eW3As.jpg\" alt=\"Katherine Johnson\" />  <img src=\"https://react.dev/images/docs/scientists/MK3eW3As.jpg\" alt=\"Katherine Johnson\" /></section>\n```\n\nExample:\n```javascript\nexport default function Gallery() {  // 🔴 Never define a component inside another component!  function Profile() {    // ...  }  // ...}\n```\n\nExample:\n```javascript\nexport default function Gallery() {  // ...}// ✅ Declare components at the top levelfunction Profile() {  // ...}\n```\n\nExample:\n```text\nfunction Profile() {\n  return (\n    <img\n      src=\"https://react.dev/images/docs/scientists/lICfvbD.jpg\"\n      alt=\"Aklilu Lemma\"\n    />\n  );\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.934Z","totalSectionsIncluded":0,"totalCodeBlocksIncluded":10,"totalLines":83,"estimatedTokens":521}}50{"id":"doc-using_typescript_react-7fc8481c","source":"documentation","title":"Using TypeScript – React","url":"https://react.dev/learn/typescript","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactSetupCopy pageCopyUsing TypeScriptTypeScript is a popular way to add type definitions to JavaScript codebases. Out of the box, TypeScript supports JSX and you can get full React Web support by adding @types/react and @types/react-dom to your project. You will learn TypeScript with React Components Examples of typing with Hooks Common types from @types/react Further learning locations Installation All production-grade React frameworks offer support for using TypeScript. Follow the framework specific guide for Remix Gatsby Expo Adding TypeScript to an existing React project To install the latest version of React’s type Copynpm install --save-dev @types/react @types/react-dom The following compiler options need to be set in your tsconfig.json: dom must be included in lib (Note: If no lib option is specified, dom is included by default). jsx must be set to one of the valid options. preserve should suffice for most applications. If you’re publishing a library, consult the jsx documentation on what value to choose. TypeScript with React Components NoteEvery file containing JSX must use the : { }) { return ( <button>{title}</button> ); } export default function MyApp() { return ( <div> <h1>Welcome to my app</h1> <MyButton title=\"I'm a button\" /> </div> ); } NoteThese sandboxes can handle TypeScript code, but they do not run the type-checker. This means you can amend the TypeScript sandboxes to learn, but you won’t get any type errors or warnings. To get type-checking, you can use the TypeScript Playground or use a more fully-featured online sandbox. This inline syntax is the simplest way to provide types for a component, though once you start to have a few fields to describe it can become unwieldy. Instead, you can use an interface or type to describe the component’s Playgroundinterface MyButtonProps { /** The text to display inside the button */ /** Whether the button can be interacted with */ } function MyButton({ title, disabled }: MyButtonProps) { return ( <button disabled={disabled}>{title}</button> ); } export default function MyApp() { return ( <div> <h1>Welcome to my app</h1> <MyButton title=\"I'm a disabled button\" disabled={true}/> </div> ); } Show more The type describing your component’s props can be as simple or as complex as you need, though they should be an object type described with either a type or interface. You can learn about how TypeScript describes objects in Object Types but you may also be interested in using Union Types to describe a prop that can be one of a few different types and the Creating Types from Types guide for more advanced use cases. Example Hooks The type definitions from @types/react include types for the built-in Hooks, so you can use them in your components without any additional setup. They are built to take into account the code you write in your component, so you will get inferred types a lot of the time and ideally do not need to handle the minutiae of providing the types. However, we can look at a few examples of how to provide types for Hooks. useState The useState Hook will re-use the value passed in as the initial state to determine what the type of the value should be. For example: // Infer the type as \"boolean\"const [enabled, setEnabled] = useState(false); This will assign the type of boolean to enabled, and setEnabled will be a function accepting either a boolean argument, or a function that returns a boolean. If you want to explicitly provide a type for the state, you can do so by providing a type argument to the useState call: // Explicitly set the type to \"boolean\"const [enabled, setEnabled] = useState<boolean>(false); This isn’t very useful in this case, but a common case where you may want to provide a type is when you have a union type. For example, status here can be one of a few different Status = \"idle\" | \"loading\" | \"success\" | \"error\";const [status, setStatus] = useState<Status>(\"idle\"); Or, as recommended in Principles for structuring state, you can group related state as an object and describe the different possibilities via object RequestState = | { status: 'idle' } | { status: 'loading' } | { status: 'success', } | { status: 'error', };const [requestState, setRequestState] = useState<RequestState>({ status: 'idle' }); useReducer The useReducer Hook is a more complex Hook that takes a reducer function and an initial state. The types for the reducer function are inferred from the initial state. You can optionally provide a type argument to the useReducer call to provide a type for the state, but it is often better to set the type on the initial state Playgroundimport {useReducer} from 'react'; interface State { }; type CounterAction = | { type: \"reset\" } | { type: \"setCount\"; [\"count\"] } const = { }; function stateReducer(state: State, ): State { switch (action.type) { case \"reset\": return initialState; case \"setCount\": return { ...state, }; new Error(\"Unknown action\"); } } export default function App() { const [state, dispatch] = useReducer(stateReducer, initialState); const addFive = () => dispatch({ type: \"setCount\", + 5 }); const reset = () => dispatch({ type: \"reset\" }); return ( <div> <h1>Welcome to my counter</h1> <p>Count: {state.count}</p> <button onClick={addFive}>Add 5</button> <button onClick={reset}>Reset</button> </div> ); } Show more We are using TypeScript in a few key State describes the shape of the reducer’s state. type CounterAction describes the different actions which can be dispatched to the reducer. const provides a type for the initial state, and also the type which is used by useReducer by default. stateReducer(state: State, ): State sets the types for the reducer function’s arguments and return value. A more explicit alternative to setting the type on initialState is to provide a type argument to { stateReducer, State } from './your-reducer-implementation';const initialState = { };export default function App() { const [state, dispatch] = useReducer<State>(stateReducer, initialState);} useContext The useContext Hook is a technique for passing data down the component tree without having to pass props through components. It is used by creating a provider component and often by creating a Hook to consume the value in a child component. The type of the value provided by the context is inferred from the value passed to the createContext Playgroundimport { createContext, useContext, useState } from 'react'; type Theme = \"light\" | \"dark\" | \"system\"; const ThemeContext = createContext<Theme>(\"system\"); const useGetTheme = () => useContext(ThemeContext); export default function MyApp() { const [theme, setTheme] = useState<Theme>('light'); return ( <ThemeContext value={theme}> <MyComponent /> </ThemeContext> ) } function MyComponent() { const theme = useGetTheme(); return ( <div> <p>Current theme: {theme}</p> </div> ) } Show more This technique works when you have a default value which makes sense - but there are occasionally cases when you do not, and in those cases null can feel reasonable as a default value. However, to allow the type-system to understand your code, you need to explicitly set ContextShape | null on the createContext. This causes the issue that you need to eliminate the | null in the type for context consumers. Our recommendation is to have the Hook do a runtime check for it’s existence and throw an error when not { createContext, useContext, useState, useMemo } from 'react';// This is a simpler example, but you can imagine a more complex object heretype ComplexObject = { };// The context is created with `| null` in the type, to accurately reflect the default value.const Context = createContext<ComplexObject | null>(null);// The `| null` will be removed via the check in the Hook.const useGetComplexObject = () => { const object = useContext(Context); if (!object) { throw new Error(\"useGetComplexObject must be used within a Provider\") } return object;}export default function MyApp() { const object = useMemo(() => ({ kind: \"complex\" }), []); return ( <Context value={object}> <MyComponent /> </Context> )}function MyComponent() { const object = useGetComplexObject(); return ( <div> <p>Current object: {object.kind}</p> </div> )} useMemo NoteReact Compiler automatically memoizes values and functions, reducing the need for manual useMemo calls. You can use the compiler to handle memoization automatically. The useMemo Hooks will create/re-access a memorized value from a function call, re-running the function only when dependencies passed as the 2nd parameter are changed. The result of calling the Hook is inferred from the return value from the function in the first parameter. You can be more explicit by providing a type argument to the Hook. // The type of visibleTodos is inferred from the return value of filterTodosconst visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]); useCallback NoteReact Compiler automatically memoizes values and functions, reducing the need for manual useCallback calls. You can use the compiler to handle memoization automatically. The useCallback provide a stable reference to a function as long as the dependencies passed into the second parameter are the same. Like useMemo, the function’s type is inferred from the return value of the function in the first parameter, and you can be more explicit by providing a type argument to the Hook. const handleClick = useCallback(() => { // ...}, [todos]); When working in TypeScript strict mode useCallback requires adding types for the parameters in your callback. This is because the type of the callback is inferred from the return value of the function, and without parameters the type cannot be fully understood. Depending on your code-style preferences, you could use the *EventHandler functions from the React types to provide the type for the event handler at the same time as defining the { useState, useCallback } from 'react';export default function Form() { const [value, setValue] = useState(\"Change me\"); const handleChange = useCallback<React.ChangeEventHandler<HTMLInputElement>>((event) => { setValue(event.currentTarget.value); }, [setValue]) return ( <> <input value={value} onChange={handleChange} /> <p>Value: {value}</p> </> );} Useful Types There is quite an expansive set of types which come from the @types/react package, it is worth a read when you feel comfortable with how React and TypeScript interact. You can find them in React’s folder in DefinitelyTyped. We will cover a few of the more common types here. DOM Events When working with DOM events in React, the type of the event can often be inferred from the event handler. However, when you want to extract a function to be passed to an event handler, you will need to explicitly set the type of the event. App.tsxApp.tsxReloadClearForkTypeScript Playgroundimport { useState } from 'react'; export default function Form() { const [value, setValue] = useState(\"Change me\"); function handleChange(event: React.ChangeEvent<HTMLInputElement>) { setValue(event.currentTarget.value); } return ( <> <input value={value} onChange={handleChange} /> <p>Value: {value}</p> </> ); } Show more There are many types of events provided in the React types - the full list can be found here which is based on the most popular events from the DOM. When determining the type you are looking for you can first look at the hover information for the event handler you are using, which will show the type of the event. If you need to use an event that is not included in this list, you can use the React.SyntheticEvent type, which is the base type for all events. Children There are two common paths to describing the children of a component. The first is to use the React.ReactNode type, which is a union of all the possible types that can be passed as children in ModalRendererProps { } This is a very broad definition of children. The second is to use the React.ReactElement type, which is only JSX elements and not JavaScript primitives like strings or ModalRendererProps { } Note, that you cannot use TypeScript to describe that the children are a certain type of JSX elements, so you cannot use the type-system to describe a component which only accepts <li> children. You can see an example of both React.ReactNode and React.ReactElement with the type-checker in this TypeScript playground. Style Props When using inline styles in React, you can use React.CSSProperties to describe the object passed to the style prop. This type is a union of all the possible CSS properties, and is a good way to ensure you are passing valid CSS properties to the style prop, and to get auto-complete in your editor. interface MyComponentProps { } Further learning This guide has covered the basics of using TypeScript with React, but there is a lot more to learn. Individual API pages on the docs may contain more in-depth documentation on how to use them with TypeScript. We recommend the following TypeScript handbook is the official documentation for TypeScript, and covers most key language features. The TypeScript release notes cover new features in depth. React TypeScript Cheatsheet is a community-maintained cheatsheet for using TypeScript with React, covering a lot of useful edge cases and providing more breadth than this document. TypeScript Community Discord is a great place to ask questions and get help with TypeScript and React issues. PreviousEditor SetupNextReact Developer ToolsCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewInstallation Adding TypeScript to an existing React project TypeScript with React Components Example Hooks useState useReducer useContext useMemo useCallback Useful Types DOM Events Children Style Props Further learning\n\nExample:\n```text\nnpm install --save-dev @types/react @types/react-dom\n```\n\nExample:\n```text\nfunction MyButton({ title }: { title: string }) {\n  return (\n    <button>{title}</button>\n  );\n}\n\nexport default function MyApp() {\n  return (\n    <div>\n      <h1>Welcome to my app</h1>\n      <MyButton title=\"I'm a button\" />\n    </div>\n  );\n}\n```\n\nExample:\n```text\ninterface MyButtonProps {\n  /** The text to display inside the button */\n  title: string;\n  /** Whether the button can be interacted with */\n  disabled: boolean;\n}\n\nfunction MyButton({ title, disabled }: MyButtonProps) {\n  return (\n    <button disabled={disabled}>{title}</button>\n  );\n}\n\nexport default function MyApp() {\n  return (\n    <div>\n      <h1>Welcome to my app</h1>\n      <MyButton title=\"I'm a disabled button\" disabled={true}/>\n    </div>\n  );\n}\n```\n\nExample:\n```javascript\n// Infer the type as \"boolean\"const [enabled, setEnabled] = useState(false);\n```\n\nExample:\n```javascript\n// Explicitly set the type to \"boolean\"const [enabled, setEnabled] = useState<boolean>(false);\n```\n\nExample:\n```javascript\ntype Status = \"idle\" | \"loading\" | \"success\" | \"error\";const [status, setStatus] = useState<Status>(\"idle\");\n```\n\nExample:\n```javascript\ntype RequestState =  | { status: 'idle' }  | { status: 'loading' }  | { status: 'success', data: any }  | { status: 'error', error: Error };const [requestState, setRequestState] = useState<RequestState>({ status: 'idle' });\n```\n\nExample:\n```text\nimport {useReducer} from 'react';\n\ninterface State {\n   count: number\n};\n\ntype CounterAction =\n  | { type: \"reset\" }\n  | { type: \"setCount\"; value: State[\"count\"] }\n\nconst initialState: State = { count: 0 };\n\nfunction stateReducer(state: State, action: CounterAction): State {\n  switch (action.type) {\n    case \"reset\":\n      return initialState;\n    case \"setCount\":\n      return { ...state, count: action.value };\n    default:\n      throw new Error(\"Unknown action\");\n  }\n}\n\nexport default function App() {\n  const [state, dispatch] = useReducer(stateReducer, initialState);\n\n  const addFive = () => dispatch({ type: \"setCount\", value: state.count + 5 });\n  const reset = () => dispatch({ type: \"reset\" });\n\n  return (\n    <div>\n      <h1>Welcome to my counter</h1>\n\n      <p>Count: {state.count}</p>\n      <button onClick={addFive}>Add 5</button>\n      <button onClick={reset}>Reset</button>\n    </div>\n  );\n}\n```\n\nExample:\n```javascript\nimport { stateReducer, State } from './your-reducer-implementation';const initialState = { count: 0 };export default function App() {  const [state, dispatch] = useReducer<State>(stateReducer, initialState);}\n```\n\nExample:\n```text\nimport { createContext, useContext, useState } from 'react';\n\ntype Theme = \"light\" | \"dark\" | \"system\";\nconst ThemeContext = createContext<Theme>(\"system\");\n\nconst useGetTheme = () => useContext(ThemeContext);\n\nexport default function MyApp() {\n  const [theme, setTheme] = useState<Theme>('light');\n\n  return (\n    <ThemeContext value={theme}>\n      <MyComponent />\n    </ThemeContext>\n  )\n}\n\nfunction MyComponent() {\n  const theme = useGetTheme();\n\n  return (\n    <div>\n      <p>Current theme: {theme}</p>\n    </div>\n  )\n}\n```\n\nExample:\n```javascript\nimport { createContext, useContext, useState, useMemo } from 'react';// This is a simpler example, but you can imagine a more complex object heretype ComplexObject = {  kind: string};// The context is created with `| null` in the type, to accurately reflect the default value.const Context = createContext<ComplexObject | null>(null);// The `| null` will be removed via the check in the Hook.const useGetComplexObject = () => {  const object = useContext(Context);  if (!object) { throw new Error(\"useGetComplexObject must be used within a Provider\") }  return object;}export default function MyApp() {  const object = useMemo(() => ({ kind: \"complex\" }), []);  return (    <Context value={object}>      <MyComponent />    </Context>  )}function MyComponent() {  const object = useGetComplexObject();  return (    <div>      <p>Current object: {object.kind}</p>    </div>  )}\n```\n\nExample:\n```javascript\n// The type of visibleTodos is inferred from the return value of filterTodosconst visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]);\n```\n\nExample:\n```javascript\nconst handleClick = useCallback(() => {  // ...}, [todos]);\n```\n\nExample:\n```javascript\nimport { useState, useCallback } from 'react';export default function Form() {  const [value, setValue] = useState(\"Change me\");  const handleChange = useCallback<React.ChangeEventHandler<HTMLInputElement>>((event) => {    setValue(event.currentTarget.value);  }, [setValue])  return (    <>      <input value={value} onChange={handleChange} />      <p>Value: {value}</p>    </>  );}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nexport default function Form() {\n  const [value, setValue] = useState(\"Change me\");\n\n  function handleChange(event: React.ChangeEvent<HTMLInputElement>) {\n    setValue(event.currentTarget.value);\n  }\n\n  return (\n    <>\n      <input value={value} onChange={handleChange} />\n      <p>Value: {value}</p>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\ninterface ModalRendererProps {  title: string;  children: React.ReactNode;}\n```\n\nExample:\n```javascript\ninterface ModalRendererProps {  title: string;  children: React.ReactElement;}\n```\n\nExample:\n```javascript\ninterface MyComponentProps {  style: React.CSSProperties;}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.936Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":18,"totalLines":204,"estimatedTokens":5163}}51{"id":"doc-tutorial_tic_tac_toe_react-35519d56","source":"documentation","title":"Tutorial: Tic-Tac-Toe – React","url":"https://react.dev/learn/tutorial-tic-tac-toe","text":"Reactv19.2Search⌘CtrlKLearnReferenceCommunityBlogGET STARTEDQuick Start Thinking in React Installation Creating a React App Build a React App from Scratch Add React to an Existing Project Setup Editor Setup Using TypeScript React Developer Tools React Compiler Introduction Installation Incremental Adoption Debugging and Troubleshooting LEARN REACTDescribing the UI Your First Component Importing and Exporting Components Writing Markup with JSX JavaScript in JSX with Curly Braces Passing Props to a Component Conditional Rendering Rendering Lists Keeping Components Pure Your UI as a Tree Adding Interactivity Responding to Events Component's Memory Render and Commit State as a Snapshot Queueing a Series of State Updates Updating Objects in State Updating Arrays in State Managing State Reacting to Input with State Choosing the State Structure Sharing State Between Components Preserving and Resetting State Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context Escape Hatches Referencing Values with Refs Manipulating the DOM with Refs Synchronizing with Effects You Might Not Need an Effect Lifecycle of Reactive Effects Separating Events from Effects Removing Effect Dependencies Reusing Logic with Custom Hooks Learn ReactQuick StartCopy will build a small tic-tac-toe game during this tutorial. This tutorial does not assume any existing React knowledge. The techniques you’ll learn in the tutorial are fundamental to building any React app, and fully understanding it will give you a deep understanding of React. NoteThis tutorial is designed for people who prefer to learn by doing and want to quickly try making something tangible. If you prefer learning each concept step by step, start with Describing the UI. The tutorial is divided into several for the tutorial will give you a starting point to follow the tutorial. Overview will teach you the fundamentals of , props, and state. Completing the game will teach you the most common techniques in React development. Adding time travel will give you a deeper insight into the unique strengths of React. What are you building? In this tutorial, you’ll build an interactive tic-tac-toe game with React. You can see what it will look like when you’re finished { useState } from 'react'; function Square({ value, onSquareClick }) { return ( <button className=\"square\" onClick={onSquareClick}> {value} </button> ); } function Board({ xIsNext, squares, onPlay }) { function handleClick(i) { if (calculateWinner(squares) || squares[i]) { return; } const nextSquares = squares.slice(); if (xIsNext) { nextSquares[i] = 'X'; } else { nextSquares[i] = 'O'; } onPlay(nextSquares); } const winner = calculateWinner(squares); let status; if (winner) { status = 'Winner: ' + winner; } else { status = 'Next player: ' + (xIsNext ? 'X' : 'O'); } return ( <> <div className=\"status\">{status}</div> <div className=\"board-row\"> <Square value={squares[0]} onSquareClick={() => handleClick(0)} /> <Square value={squares[1]} onSquareClick={() => handleClick(1)} /> <Square value={squares[2]} onSquareClick={() => handleClick(2)} /> </div> <div className=\"board-row\"> <Square value={squares[3]} onSquareClick={() => handleClick(3)} /> <Square value={squares[4]} onSquareClick={() => handleClick(4)} /> <Square value={squares[5]} onSquareClick={() => handleClick(5)} /> </div> <div className=\"board-row\"> <Square value={squares[6]} onSquareClick={() => handleClick(6)} /> <Square value={squares[7]} onSquareClick={() => handleClick(7)} /> <Square value={squares[8]} onSquareClick={() => handleClick(8)} /> </div> </> ); } export default function Game() { const [history, setHistory] = useState([Array(9).fill(null)]); const [currentMove, setCurrentMove] = useState(0); const xIsNext = currentMove % 2 === 0; const currentSquares = history[currentMove]; function handlePlay(nextSquares) { const nextHistory = [...history.slice(0, currentMove + 1), nextSquares]; setHistory(nextHistory); setCurrentMove(nextHistory.length - 1); } function jumpTo(nextMove) { setCurrentMove(nextMove); } const moves = history.map((squares, move) => { let description; if (move > 0) { description = 'Go to move #' + move; } else { description = 'Go to game start'; } return ( <li key={move}> <button onClick={() => jumpTo(move)}>{description}</button> </li> ); }); return ( <div className=\"game\"> <div className=\"game-board\"> <Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} /> </div> <div className=\"game-info\"> <ol>{moves}</ol> </div> </div> ); } function calculateWinner(squares) { const lines = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6], ]; for (let i = 0; i < lines.length; i++) { const [a, b, c] = lines[i]; if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { return squares[a]; } } return null; } Show more If the code doesn’t make sense to you yet, or if you are unfamiliar with the code’s syntax, don’t worry! The goal of this tutorial is to help you understand React and its syntax. We recommend that you check out the tic-tac-toe game above before continuing with the tutorial. One of the features that you’ll notice is that there is a numbered list to the right of the game’s board. This list gives you a history of all of the moves that have occurred in the game, and it is updated as the game progresses. Once you’ve played around with the finished tic-tac-toe game, keep scrolling. You’ll start with a simpler template in this tutorial. Our next step is to set you up so that you can start building the game. Setup for the tutorial In the live code editor below, click Fork in the top-right corner to open the editor in a new tab using the website CodeSandbox. CodeSandbox lets you write code in your browser and preview how your users will see the app you’ve created. The new tab should display an empty square and the starter code for this tutorial. App.jsApp.jsReloadClearForkexport default function Square() { return <button className=\"square\">X</button>; } NoteYou can also follow this tutorial using your local development environment. To do this, you need Node.js In the CodeSandbox tab you opened earlier, press the top-left corner button to open the menu, and then choose Download Sandbox in that menu to download an archive of the files locally Unzip the archive, then open a terminal and cd to the directory you unzipped Install the dependencies with npm install Run npm start to start a local server and follow the prompts to view the code running in a browser If you get stuck, don’t let this stop you! Follow along online instead and try a local setup again later. Overview Now that you’re set up, let’s get an overview of React! Inspecting the starter code In CodeSandbox you’ll see three main Files section with a list of files like App.js, index.js, styles.css in src folder and a folder called public The code editor where you’ll see the source code of your selected file The browser section where you’ll see how the code you’ve written will be displayed The App.js file should be selected in the Files section. The contents of that file in the code editor should default function Square() { return <button className=\"square\">X</button>;} The browser section should be displaying a square with an X in it like let’s have a look at the files in the starter code. App.js The code in App.js creates a component. In React, a component is a piece of reusable code that represents a part of a user interface. Components are used to render, manage, and update the UI elements in your application. Let’s look at the component line by line to see what’s going default function Square() { return <button className=\"square\">X</button>;} The first line defines a function called Square. The export JavaScript keyword makes this function accessible outside of this file. The default keyword tells other files using your code that it’s the main function in your file. export default function Square() { return <button className=\"square\">X</button>;} The second line returns a button. The return JavaScript keyword means whatever comes after is returned as a value to the caller of the function. <button> is a JSX element. A JSX element is a combination of JavaScript code and HTML tags that describes what you’d like to display. className=\"square\" is a button property or prop that tells CSS how to style the button. X is the text displayed inside of the button and </button> closes the JSX element to indicate that any following content shouldn’t be placed inside the button. styles.css Click on the file labeled styles.css in the Files section of CodeSandbox. This file defines the styles for your React app. The first two CSS selectors (* and body) define the style of large parts of your app while the from 'react';import { createRoot } from 'react-dom/client';import './styles.css';import App from './App'; Lines 1-5 bring all the necessary pieces React’s library to talk to web browsers (React DOM) the styles for your components the component you created in App.js. The remainder of the file brings all the pieces together and injects the final product into index.html in the public folder. Building the board Let’s get back to App.js. This is where you’ll spend the rest of the tutorial. Currently the board is only a single square, but you need nine! If you just try and copy paste your square to make two squares like default function Square() { return <button className=\"square\">X</button><button className=\"square\">X</button>;} You’ll get this /src/App.js: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX Fragment <>...</>? React components need to return a single JSX element and not multiple adjacent JSX elements like two buttons. To fix this you can use Fragments (<> and </>) to wrap multiple adjacent JSX elements like default function Square() { return ( <> <button className=\"square\">X</button> <button className=\"square\">X</button> </> );} Now you should ! Now you just need to copy-paste a few times to add nine squares and… Oh no! The squares are all in a single line, not in a grid like you need for our board. To fix this you’ll need to group your squares into rows with divs and add some CSS classes. While you’re at it, you’ll give each square a number to make sure you know where each square is displayed. In the App.js file, update the Square component to look like default function Square() { return ( <> <div className=\"board-row\"> <button className=\"square\">1</button> <button className=\"square\">2</button> <button className=\"square\">3</button> </div> <div className=\"board-row\"> <button className=\"square\">4</button> <button className=\"square\">5</button> <button className=\"square\">6</button> </div> <div className=\"board-row\"> <button className=\"square\">7</button> <button className=\"square\">8</button> <button className=\"square\">9</button> </div> </> );} The CSS defined in styles.css styles the divs with the className of board-row. Now that you’ve grouped your components into rows with the styled divs you have your tic-tac-toe you now have a problem. Your component named Square, really isn’t a square anymore. Let’s fix that by changing the name to default function Board() { //...} At this point your code should look something like default function Board() { return ( <> <div className=\"board-row\"> <button className=\"square\">1</button> <button className=\"square\">2</button> <button className=\"square\">3</button> </div> <div className=\"board-row\"> <button className=\"square\">4</button> <button className=\"square\">5</button> <button className=\"square\">6</button> </div> <div className=\"board-row\"> <button className=\"square\">7</button> <button className=\"square\">8</button> <button className=\"square\">9</button> </div> </> ); } Show more NotePsssst… That’s a lot to type! It’s okay to copy and paste code from this page. However, if you’re up for a little challenge, we recommend only copying code that you’ve manually typed at least once yourself. Passing data through props Next, you’ll want to change the value of a square from empty to “X” when the user clicks on the square. With how you’ve built the board so far you would need to copy-paste the code that updates the square nine times (once for each square you have)! Instead of copy-pasting, React’s component architecture allows you to create a reusable component to avoid messy, duplicated code. First, you are going to copy the line defining your first square (<button className=\"square\">1</button>) from your Board component into a new Square Square() { return <button className=\"square\">1</button>;}export default function Board() { // ...} Then you’ll update the Board component to render that Square component using JSX syntax: // ...export default function Board() { return ( <> <div className=\"board-row\"> <Square /> <Square /> <Square /> </div> <div className=\"board-row\"> <Square /> <Square /> <Square /> </div> <div className=\"board-row\"> <Square /> <Square /> <Square /> </div> </> );} Note how unlike the browser divs, your own components Board and Square must start with a capital letter. Let’s take a no! You lost the numbered squares you had before. Now each square says “1”. To fix this, you will use props to pass the value each square should have from the parent component (Board) to its child (Square). Update the Square component to read the value prop that you’ll pass from the Square({ value }) { return <button className=\"square\">1</button>;} function Square({ value }) indicates the Square component can be passed a prop called value. Now you want to display that value instead of 1 inside every square. Try doing it like Square({ value }) { return <button className=\"square\">value</button>;} Oops, this is not what you wanted to render the JavaScript variable called value from your component, not the word “value”. To “escape into JavaScript” from JSX, you need curly braces. Add curly braces around value in JSX like Square({ value }) { return <button className=\"square\">{value}</button>;} For now, you should see an empty is because the Board component hasn’t passed the value prop to each Square component it renders yet. To fix it you’ll add the value prop to each Square component rendered by the Board default function Board() { return ( <> <div className=\"board-row\"> <Square value=\"1\" /> <Square value=\"2\" /> <Square value=\"3\" /> </div> <div className=\"board-row\"> <Square value=\"4\" /> <Square value=\"5\" /> <Square value=\"6\" /> </div> <div className=\"board-row\"> <Square value=\"7\" /> <Square value=\"8\" /> <Square value=\"9\" /> </div> </> );} Now you should see a grid of numbers updated code should look like Square({ value }) { return <button className=\"square\">{value}</button>; } export default function Board() { return ( <> <div className=\"board-row\"> <Square value=\"1\" /> <Square value=\"2\" /> <Square value=\"3\" /> </div> <div className=\"board-row\"> <Square value=\"4\" /> <Square value=\"5\" /> <Square value=\"6\" /> </div> <div className=\"board-row\"> <Square value=\"7\" /> <Square value=\"8\" /> <Square value=\"9\" /> </div> </> ); } Show more Making an interactive component Let’s fill the Square component with an X when you click it. Declare a function called handleClick inside of the Square. Then, add onClick to the props of the button JSX element returned from the Square({ value }) { function handleClick() { console.log('clicked!'); } return ( <button className=\"square\" onClick={handleClick} > {value} </button> );} If you click on a square now, you should see a log saying \"clicked!\" in the Console tab at the bottom of the Browser section in CodeSandbox. Clicking the square more than once will log \"clicked!\" again. Repeated console logs with the same message will not create more lines in the console. Instead, you will see an incrementing counter next to your first \"clicked!\" log. NoteIf you are following this tutorial using your local development environment, you need to open your browser’s Console. For example, if you use the Chrome browser, you can view the Console with the keyboard shortcut Shift + Ctrl + J (on Windows/Linux) or Option + ⌘ + J (on macOS). As a next step, you want the Square component to “remember” that it got clicked, and fill it with an “X” mark. To “remember” things, components use state. React provides a special function called useState that you can call from your component to let it “remember” things. Let’s store the current value of the Square in state, and change it when the Square is clicked. Import useState at the top of the file. Remove the value prop from the Square component. Instead, add a new line at the start of the Square that calls useState. Have it return a state variable called { useState } from 'react';function Square() { const [value, setValue] = useState(null); function handleClick() { //... value stores the value and setValue is a function that can be used to change the value. The null passed to useState is used as the initial value for this state variable, so value here starts off equal to null. Since the Square component no longer accepts props anymore, you’ll remove the value prop from all nine of the Square components created by the Board component: // ...export default function Board() { return ( <> <div className=\"board-row\"> <Square /> <Square /> <Square /> </div> <div className=\"board-row\"> <Square /> <Square /> <Square /> </div> <div className=\"board-row\"> <Square /> <Square /> <Square /> </div> </> );} Now you’ll change Square to display an “X” when clicked. Replace the console.log(\"clicked!\"); event handler with setValue('X');. Now your Square component looks like Square() { const [value, setValue] = useState(null); function handleClick() { setValue('X'); } return ( <button className=\"square\" onClick={handleClick} > {value} </button> );} By calling this set function from an onClick handler, you’re telling React to re-render that Square whenever its <button> is clicked. After the update, the Square’s value will be 'X', so you’ll see the “X” on the game board. Click on any Square, and “X” should show Square has its own value stored in each Square is completely independent of the others. When you call a set function in a component, React automatically updates the child components inside too. After you’ve made the above changes, your code will look like { useState } from 'react'; function Square() { const [value, setValue] = useState(null); function handleClick() { setValue('X'); } return ( <button className=\"square\" onClick={handleClick} > {value} </button> ); } export default function Board() { return ( <> <div className=\"board-row\"> <Square /> <Square /> <Square /> </div> <div className=\"board-row\"> <Square /> <Square /> <Square /> </div> <div className=\"board-row\"> <Square /> <Square /> <Square /> </div> </> ); } Show more React Developer Tools React Developer Tools let you check the props and the state of your React components. It is available as a Chrome, Firefox, and Edge browser extension. After you install it, a new Components tab will appear in your browser Developer Tools for sites using React. If you’re following along in CodeSandbox, you’d need to first open your sandbox preview in a new , on the preview page, open your browser’s DevTools and find the Components inspect a particular component on the screen, use the button in the top left corner of the Components the game By this point, you have all the basic building blocks for your tic-tac-toe game. To have a complete game, you now need to alternate placing “X”s and “O”s on the board, and you need a way to determine a winner. Lifting state up Currently, each Square component maintains a part of the game’s state. To check for a winner in a tic-tac-toe game, the Board would need to somehow know the state of each of the 9 Square components. How would you approach that? At first, you might guess that the Board needs to “ask” each Square for that Square’s state. Although this approach is technically possible in React, we discourage it because the code becomes difficult to understand, susceptible to bugs, and hard to refactor. Instead, the best approach is to store the game’s state in the parent Board component instead of in each Square. The Board component can tell each Square what to display by passing a prop, like you did when you passed a number to each Square. To collect data from multiple children, or to have two child components communicate with each other, declare the shared state in their parent component instead. The parent component can pass that state back down to the children via props. This keeps the child components in sync with each other and with their parent. Lifting state into a parent component is common when React components are refactored. Let’s take this opportunity to try it out. Edit the Board component so that it declares a state variable named squares that defaults to an array of 9 nulls corresponding to the 9 squares: // ...export default function Board() { const [squares, setSquares] = useState(Array(9).fill(null)); return ( // ... );} Array(9).fill(null) creates an array with nine elements and sets each of them to null. The useState() call around it declares a squares state variable that’s initially set to that array. Each entry in the array corresponds to the value of a square. When you fill the board in later, the squares array will look like this: ['O', null, 'X', 'X', 'X', 'O', 'O', null, null] Now your Board component needs to pass the value prop down to each Square that it default function Board() { const [squares, setSquares] = useState(Array(9).fill(null)); return ( <> <div className=\"board-row\"> <Square value={squares[0]} /> <Square value={squares[1]} /> <Square value={squares[2]} /> </div> <div className=\"board-row\"> <Square value={squares[3]} /> <Square value={squares[4]} /> <Square value={squares[5]} /> </div> <div className=\"board-row\"> <Square value={squares[6]} /> <Square value={squares[7]} /> <Square value={squares[8]} /> </div> </> );} Next, you’ll edit the Square component to receive the value prop from the Board component. This will require removing the Square component’s own stateful tracking of value and the button’s onClick Square({value}) { return <button className=\"square\">{value}</button>;} At this point you should see an empty tic-tac-toe your code should look like { useState } from 'react'; function Square({ value }) { return <button className=\"square\">{value}</button>; } export default function Board() { const [squares, setSquares] = useState(Array(9).fill(null)); return ( <> <div className=\"board-row\"> <Square value={squares[0]} /> <Square value={squares[1]} /> <Square value={squares[2]} /> </div> <div className=\"board-row\"> <Square value={squares[3]} /> <Square value={squares[4]} /> <Square value={squares[5]} /> </div> <div className=\"board-row\"> <Square value={squares[6]} /> <Square value={squares[7]} /> <Square value={squares[8]} /> </div> </> ); } Show more Each Square will now receive a value prop that will either be 'X', 'O', or null for empty squares. Next, you need to change what happens when a Square is clicked. The Board component now maintains which squares are filled. You’ll need to create a way for the Square to update the Board’s state. Since state is private to a component that defines it, you cannot update the Board’s state directly from Square. Instead, you’ll pass down a function from the Board component to the Square component, and you’ll have Square call that function when a square is clicked. You’ll start with the function that the Square component will call when it is clicked. You’ll call that function Square({ value }) { return ( <button className=\"square\" onClick={onSquareClick}> {value} </button> );} Next, you’ll add the onSquareClick function to the Square component’s Square({ value, onSquareClick }) { return ( <button className=\"square\" onClick={onSquareClick}> {value} </button> );} Now you’ll connect the onSquareClick prop to a function in the Board component that you’ll name handleClick. To connect onSquareClick to handleClick you’ll pass a function to the onSquareClick prop of the first Square default function Board() { const [squares, setSquares] = useState(Array(9).fill(null)); return ( <> <div className=\"board-row\"> <Square value={squares[0]} onSquareClick={handleClick} /> //... );} Lastly, you will define the handleClick function inside the Board component to update the squares array holding your board’s default function Board() { const [squares, setSquares] = useState(Array(9).fill(null)); function handleClick() { const nextSquares = squares.slice(); nextSquares[0] = \"X\"; setSquares(nextSquares); } return ( // ... )} The handleClick function creates a copy of the squares array (nextSquares) with the JavaScript slice() Array method. Then, handleClick updates the nextSquares array to add X to the first ([0] index) square. Calling the setSquares function lets React know the state of the component has changed. This will trigger a re-render of the components that use the squares state (Board) as well as its child components (the Square components that make up the board). NoteJavaScript supports closures which means an inner function (e.g. handleClick) has access to variables and functions defined in an outer function (e.g. Board). The handleClick function can read the squares state and call the setSquares method because they are both defined inside of the Board function. Now you can add X’s to the board… but only to the upper left square. Your handleClick function is hardcoded to update the index for the upper left square (0). Let’s update handleClick to be able to update any square. Add an argument i to the handleClick function that takes the index of the square to default function Board() { const [squares, setSquares] = useState(Array(9).fill(null)); function handleClick(i) { const nextSquares = squares.slice(); nextSquares[i] = \"X\"; setSquares(nextSquares); } return ( // ... )} Next, you will need to pass that i to handleClick. You could try to set the onSquareClick prop of square to be handleClick(0) directly in the JSX like this, but it won’t work: <Square value={squares[0]} onSquareClick={handleClick(0)} /> Here is why this doesn’t work. The handleClick(0) call will be a part of rendering the board component. Because handleClick(0) alters the state of the board component by calling setSquares, your entire board component will be re-rendered again. But this runs handleClick(0) again, leading to an infinite many re-renders. React limits the number of renders to prevent an infinite loop. Why didn’t this problem happen earlier? When you were passing onSquareClick={handleClick}, you were passing the handleClick function down as a prop. You were not calling it! But now you are calling that function right away—notice the parentheses in handleClick(0)—and that’s why it runs too early. You don’t want to call handleClick until the user clicks! You could fix this by creating a function like handleFirstSquareClick that calls handleClick(0), a function like handleSecondSquareClick that calls handleClick(1), and so on. You would pass (rather than call) these functions down as props like onSquareClick={handleFirstSquareClick}. This would solve the infinite loop. However, defining nine different functions and giving each of them a name is too verbose. Instead, let’s do default function Board() { // ... return ( <> <div className=\"board-row\"> <Square value={squares[0]} onSquareClick={() => handleClick(0)} /> // ... );} Notice the new () => syntax. Here, () => handleClick(0) is an arrow function, which is a shorter way to define functions. When the square is clicked, the code after the => “arrow” will run, calling handleClick(0). Now you need to update the other eight squares to call handleClick from the arrow functions you pass. Make sure that the argument for each call of the handleClick corresponds to the index of the correct default function Board() { // ... return ( <> <div className=\"board-row\"> <Square value={squares[0]} onSquareClick={() => handleClick(0)} /> <Square value={squares[1]} onSquareClick={() => handleClick(1)} /> <Square value={squares[2]} onSquareClick={() => handleClick(2)} /> </div> <div className=\"board-row\"> <Square value={squares[3]} onSquareClick={() => handleClick(3)} /> <Square value={squares[4]} onSquareClick={() => handleClick(4)} /> <Square value={squares[5]} onSquareClick={() => handleClick(5)} /> </div> <div className=\"board-row\"> <Square value={squares[6]} onSquareClick={() => handleClick(6)} /> <Square value={squares[7]} onSquareClick={() => handleClick(7)} /> <Square value={squares[8]} onSquareClick={() => handleClick(8)} /> </div> </> );}; Now you can again add X’s to any square on the board by clicking on this time all the state management is handled by the Board component! This is what your code should look { useState } from 'react'; function Square({ value, onSquareClick }) { return ( <button className=\"square\" onClick={onSquareClick}> {value} </button> ); } export default function Board() { const [squares, setSquares] = useState(Array(9).fill(null)); function handleClick(i) { const nextSquares = squares.slice(); nextSquares[i] = 'X'; setSquares(nextSquares); } return ( <> <div className=\"board-row\"> <Square value={squares[0]} onSquareClick={() => handleClick(0)} /> <Square value={squares[1]} onSquareClick={() => handleClick(1)} /> <Square value={squares[2]} onSquareClick={() => handleClick(2)} /> </div> <div className=\"board-row\"> <Square value={squares[3]} onSquareClick={() => handleClick(3)} /> <Square value={squares[4]} onSquareClick={() => handleClick(4)} /> <Square value={squares[5]} onSquareClick={() => handleClick(5)} /> </div> <div className=\"board-row\"> <Square value={squares[6]} onSquareClick={() => handleClick(6)} /> <Square value={squares[7]} onSquareClick={() => handleClick(7)} /> <Square value={squares[8]} onSquareClick={() => handleClick(8)} /> </div> </> ); } Show more Now that your state handling is in the Board component, the parent Board component passes props to the child Square components so that they can be displayed correctly. When clicking on a Square, the child Square component now asks the parent Board component to update the state of the board. When the Board’s state changes, both the Board component and every child Square re-renders automatically. Keeping the state of all squares in the Board component will allow it to determine the winner in the future. Let’s recap what happens when a user clicks the top left square on your board to add an X to on the upper left square runs the function that the button received as its onClick prop from the Square. The Square component received that function as its onSquareClick prop from the Board. The Board component defined that function directly in the JSX. It calls handleClick with an argument of 0. handleClick uses the argument (0) to update the first element of the squares array from null to X. The squares state of the Board component was updated, so the Board and all of its children re-render. This causes the value prop of the Square component with index 0 to change from null to X. In the end the user sees that the upper left square has changed from empty to having an X after clicking it. NoteThe DOM <button> element’s onClick attribute has a special meaning to React because it is a built-in component. For custom components like Square, the naming is up to you. You could give any name to the Square’s onSquareClick prop or Board’s handleClick function, and the code would work the same. In React, it’s conventional to use onSomething names for props which represent events and handleSomething for the function definitions which handle those events. Why immutability is important Note how in handleClick, you call Each time a player moves, xIsNext (a boolean) will be flipped to determine which player goes next and the game’s state will be saved. You’ll update the Board’s handleClick function to flip the value of default function Board() { const [xIsNext, setXIsNext] = useState(true); const [squares, setSquares] = useState(Array(9).fill(null)); function handleClick(i) { const nextSquares = squares.slice(); if (xIsNext) { nextSquares[i] = \"X\"; } else { nextSquares[i] = \"O\"; } setSquares(nextSquares); setXIsNext(!xIsNext); } return ( //... );} Now, as you click on different squares, they will alternate between X and O, as they should! But wait, there’s a problem. Try clicking on the same square multiple X is overwritten by an O! While this would add a very interesting twist to the game, we’re going to stick to the original rules for now. When you mark a square with an X or an O you aren’t first checking to see if the square already has an X or O value. You can fix this by returning early. You’ll check to see if the square already has an X or an O. If the square is already filled, you will return in the handleClick function early—before it tries to update the board state. function handleClick(i) { if (squares[i]) { return; } const nextSquares = squares.slice(); //...} Now you can only add X’s or O’s to empty squares! Here is what your code should look like at this { useState } from 'react'; function Square({value, onSquareClick}) { return ( <button className=\"square\" onClick={onSquareClick}> {value} </button> ); } export default function Board() { const [xIsNext, setXIsNext] = useState(true); const [squares, setSquares] = useState(Array(9).fill(null)); function handleClick(i) { if (squares[i]) { return; } const nextSquares = squares.slice(); if (xIsNext) { nextSquares[i] = 'X'; } else { nextSquares[i] = 'O'; } setSquares(nextSquares); setXIsNext(!xIsNext); } return ( <> <div className=\"board-row\"> <Square value={squares[0]} onSquareClick={() => handleClick(0)} /> <Square value={squares[1]} onSquareClick={() => handleClick(1)} /> <Square value={squares[2]} onSquareClick={() => handleClick(2)} /> </div> <div className=\"board-row\"> <Square value={squares[3]} onSquareClick={() => handleClick(3)} /> <Square value={squares[4]} onSquareClick={() => handleClick(4)} /> <Square value={squares[5]} onSquareClick={() => handleClick(5)} /> </div> <div className=\"board-row\"> <Square value={squares[6]} onSquareClick={() => handleClick(6)} /> <Square value={squares[7]} onSquareClick={() => handleClick(7)} /> <Square value={squares[8]} onSquareClick={() => handleClick(8)} /> </div> </> ); } Show more Declaring a winner Now that the players can take turns, you’ll want to show when the game is won and there are no more turns to make. To do this you’ll add a helper function called calculateWinner that takes an array of 9 squares, checks for a winner and returns 'X', 'O', or null as appropriate. Don’t worry too much about the calculateWinner function; it’s not specific to default function Board() { //...}function calculateWinner(squares) { const lines = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6] ]; for (let i = 0; i < lines.length; i++) { const [a, b, c] = lines[i]; if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { return squares[a]; } } return null;} NoteIt does not matter whether you define calculateWinner before or after the Board. Let’s put it at the end so that you don’t have to scroll past it every time you edit your components. You will call calculateWinner(squares) in the Board component’s handleClick function to check if a player has won. You can perform this check at the same time you check if a user has clicked a square that already has an X or an O. We’d like to return early in both handleClick(i) { if (squares[i] || calculateWinner(squares)) { return; } const nextSquares = squares.slice(); //...} To let the players know when the game is over, you can display text such as “Winner: X” or “Winner: O”. To do that you’ll add a status section to the Board component. The status will display the winner if the game is over and if the game is ongoing you’ll display which player’s turn is default function Board() { // ... const winner = calculateWinner(squares); let status; if (winner) { status = \"Winner: \" + winner; } else { status = \"Next player: \" + (xIsNext ? \"X\" : \"O\"); } return ( <> <div className=\"status\">{status}</div> <div className=\"board-row\"> // ... )} Congratulations! You now have a working tic-tac-toe game. And you’ve just learned the basics of React too. So you are the real winner here. Here is what the code should look { useState } from 'react'; function Square({value, onSquareClick}) { return ( <button className=\"square\" onClick={onSquareClick}> {value} </button> ); } export default function Board() { const [xIsNext, setXIsNext] = useState(true); const [squares, setSquares] = useState(Array(9).fill(null)); function handleClick(i) { if (calculateWinner(squares) || squares[i]) { return; } const nextSquares = squares.slice(); if (xIsNext) { nextSquares[i] = 'X'; } else { nextSquares[i] = 'O'; } setSquares(nextSquares); setXIsNext(!xIsNext); } const winner = calculateWinner(squares); let status; if (winner) { status = 'Winner: ' + winner; } else { status = 'Next player: ' + (xIsNext ? 'X' : 'O'); } return ( <> <div className=\"status\">{status}</div> <div className=\"board-row\"> <Square value={squares[0]} onSquareClick={() => handleClick(0)} /> <Square value={squares[1]} onSquareClick={() => handleClick(1)} /> <Square value={squares[2]} onSquareClick={() => handleClick(2)} /> </div> <div className=\"board-row\"> <Square value={squares[3]} onSquareClick={() => handleClick(3)} /> <Square value={squares[4]} onSquareClick={() => handleClick(4)} /> <Square value={squares[5]} onSquareClick={() => handleClick(5)} /> </div> <div className=\"board-row\"> <Square value={squares[6]} onSquareClick={() => handleClick(6)} /> <Square value={squares[7]} onSquareClick={() => handleClick(7)} /> <Square value={squares[8]} onSquareClick={() => handleClick(8)} /> </div> </> ); } function calculateWinner(squares) { const lines = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6], ]; for (let i = 0; i < lines.length; i++) { const [a, b, c] = lines[i]; if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { return squares[a]; } } return null; } Show more Adding time travel As a final exercise, let’s make it possible to “go back in time” to the previous moves in the game. Storing a history of moves If you mutated the squares array, implementing time travel would be very difficult. However, you used slice() to create a new copy of the squares array after every move, and treated it as immutable. This will allow you to store every past version of the squares array, and navigate between the turns that have already happened. You’ll store the past squares arrays in another array called history, which you’ll store as a new state variable. The history array represents all board states, from the first to the last move, and has a shape like this: [ // Before first move [null, null, null, null, null, null, null, null, null], // After first move [null, null, null, null, 'X', null, null, null, null], // After second move [null, null, null, null, 'X', null, null, null, 'O'], // ...] Lifting state up, again You will now write a new top-level component called Game to display a list of past moves. That’s where you will place the history state that contains the entire game history. Placing the history state into the Game component will let you remove the squares state from its child Board component. Just like you “lifted state up” from the Square component into the Board component, you will now lift it up from the Board into the top-level Game component. This gives the Game component full control over the Board’s data and lets it instruct the Board to render previous turns from the history. First, add a Game component with export default. Have it render the Board component and some Board() { // ...}export default function Game() { return ( <div className=\"game\"> <div className=\"game-board\"> <Board /> </div> <div className=\"game-info\"> <ol>{/*TODO*/}</ol> </div> </div> );} Note that you are removing the export default keywords before the function Board() { declaration and adding them before the function Game() { declaration. This tells your index.js file to use the Game component as the top-level component instead of your Board component. The additional divs returned by the Game component are making room for the game information you’ll add to the board later. Add some state to the Game component to track which player is next and the history of default function Game() { const [xIsNext, setXIsNext] = useState(true); const [history, setHistory] = useState([Array(9).fill(null)]); // ... Notice how [Array(9).fill(null)] is an array with a single item, which itself is an array of 9 nulls. To render the squares for the current move, you’ll want to read the last squares array from the history. You don’t need useState for this—you already have enough information to calculate it during default function Game() { const [xIsNext, setXIsNext] = useState(true); const [history, setHistory] = useState([Array(9).fill(null)]); const currentSquares = history[history.length - 1]; // ... Next, create a handlePlay function inside the Game component that will be called by the Board component to update the game. Pass xIsNext, currentSquares and handlePlay as props to the Board default function Game() { const [xIsNext, setXIsNext] = useState(true); const [history, setHistory] = useState([Array(9).fill(null)]); const currentSquares = history[history.length - 1]; function handlePlay(nextSquares) { // TODO } return ( <div className=\"game\"> <div className=\"game-board\"> <Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} /> //... )} Let’s make the Board component fully controlled by the props it receives. Change the Board component to take three , squares, and a new onPlay function that Board can call with the updated squares array when a player makes a move. Next, remove the first two lines of the Board function that call Board({ xIsNext, squares, onPlay }) { function handleClick(i) { //... } // ...} Now replace the setSquares and setXIsNext calls in handleClick in the Board component with a single call to your new onPlay function so the Game component can update the Board when the user clicks a Board({ xIsNext, squares, onPlay }) { function handleClick(i) { if (calculateWinner(squares) || squares[i]) { return; } const nextSquares = squares.slice(); if (xIsNext) { nextSquares[i] = \"X\"; } else { nextSquares[i] = \"O\"; } onPlay(nextSquares); } //...} The Board component is fully controlled by the props passed to it by the Game component. You need to implement the handlePlay function in the Game component to get the game working again. What should handlePlay do when called? Remember that Board used to call setSquares with an updated array; now it passes the updated squares array to onPlay. The handlePlay function needs to update Game’s state to trigger a re-render, but you don’t have a setSquares function that you can call any more—you’re now using the history state variable to store this information. You’ll want to update history by appending the updated squares array as a new history entry. You also want to toggle xIsNext, just as Board used to default function Game() { //... function handlePlay(nextSquares) { setHistory([...history, nextSquares]); setXIsNext(!xIsNext); } //...} Here, [...history, nextSquares] creates a new array that contains all the items in history, followed by nextSquares. (You can read the ...history spread syntax as “enumerate all the items in history”.) For example, if history is [[null,null,null], [\"X\",null,null]] and nextSquares is [\"X\",null,\"O\"], then the new [...history, nextSquares] array will be [[null,null,null], [\"X\",null,null], [\"X\",null,\"O\"]]. At this point, you’ve moved the state to live in the Game component, and the UI should be fully working, just as it was before the refactor. Here is what the code should look like at this { useState } from 'react'; function Square({ value, onSquareClick }) { return ( <button className=\"square\" onClick={onSquareClick}> {value} </button> ); } function Board({ xIsNext, squares, onPlay }) { function handleClick(i) { if (calculateWinner(squares) || squares[i]) { return; } const nextSquares = squares.slice(); if (xIsNext) { nextSquares[i] = 'X'; } else { nextSquares[i] = 'O'; } onPlay(nextSquares); } const winner = calculateWinner(squares); let status; if (winner) { status = 'Winner: ' + winner; } else { status = 'Next player: ' + (xIsNext ? 'X' : 'O'); } return ( <> <div className=\"status\">{status}</div> <div className=\"board-row\"> <Square value={squares[0]} onSquareClick={() => handleClick(0)} /> <Square value={squares[1]} onSquareClick={() => handleClick(1)} /> <Square value={squares[2]} onSquareClick={() => handleClick(2)} /> </div> <div className=\"board-row\"> <Square value={squares[3]} onSquareClick={() => handleClick(3)} /> <Square value={squares[4]} onSquareClick={() => handleClick(4)} /> <Square value={squares[5]} onSquareClick={() => handleClick(5)} /> </div> <div className=\"board-row\"> <Square value={squares[6]} onSquareClick={() => handleClick(6)} /> <Square value={squares[7]} onSquareClick={() => handleClick(7)} /> <Square value={squares[8]} onSquareClick={() => handleClick(8)} /> </div> </> ); } export default function Game() { const [xIsNext, setXIsNext] = useState(true); const [history, setHistory] = useState([Array(9).fill(null)]); const currentSquares = history[history.length - 1]; function handlePlay(nextSquares) { setHistory([...history, nextSquares]); setXIsNext(!xIsNext); } return ( <div className=\"game\"> <div className=\"game-board\"> <Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} /> </div> <div className=\"game-info\"> <ol>{/*TODO*/}</ol> </div> </div> ); } function calculateWinner(squares) { const lines = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6], ]; for (let i = 0; i < lines.length; i++) { const [a, b, c] = lines[i]; if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { return squares[a]; } } return null; } Show more Showing the past moves Since you are recording the tic-tac-toe game’s history, you can now display a list of past moves to the player. React elements like <button> are regular JavaScript objects; you can pass them around in your application. To render multiple items in React, you can use an array of React elements. You already have an array of history moves in state, so now you need to transform it to an array of React elements. In JavaScript, to transform one array into another, you can use the array map method: [1, 2, 3].map((x) => x * 2) // [2, 4, 6] You’ll use map to transform your history of moves into React elements representing buttons on the screen, and display a list of buttons to “jump” to past moves. Let’s map over the history in the Game default function Game() { const [xIsNext, setXIsNext] = useState(true); const [history, setHistory] = useState([Array(9).fill(null)]); const currentSquares = history[history.length - 1]; function handlePlay(nextSquares) { setHistory([...history, nextSquares]); setXIsNext(!xIsNext); } function jumpTo(nextMove) { // TODO } const moves = history.map((squares, move) => { let description; if (move > 0) { description = 'Go to move #' + move; } else { description = 'Go to game start'; } return ( <li> <button onClick={() => jumpTo(move)}>{description}</button> </li> ); }); return ( <div className=\"game\"> <div className=\"game-board\"> <Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} /> </div> <div className=\"game-info\"> <ol>{moves}</ol> </div> </div> );} You can see what your code should look like below. Note that you should see an error in the developer tools console that : Each child in an array or iterator should have a unique “key” prop. Check the render method of `Game`. You’ll fix this error in the next section. App.jsApp.jsReloadClearForkimport { useState } from 'react'; function Square({ value, onSquareClick }) { return ( <button className=\"square\" onClick={onSquareClick}> {value} </button> ); } function Board({ xIsNext, squares, onPlay }) { function handleClick(i) { if (calculateWinner(squares) || squares[i]) { return; } const nextSquares = squares.slice(); if (xIsNext) { nextSquares[i] = 'X'; } else { nextSquares[i] = 'O'; } onPlay(nextSquares); } const winner = calculateWinner(squares); let status; if (winner) { status = 'Winner: ' + winner; } else { status = 'Next player: ' + (xIsNext ? 'X' : 'O'); } return ( <> <div className=\"status\">{status}</div> <div className=\"board-row\"> <Square value={squares[0]} onSquareClick={() => handleClick(0)} /> <Square value={squares[1]} onSquareClick={() => handleClick(1)} /> <Square value={squares[2]} onSquareClick={() => handleClick(2)} /> </div> <div className=\"board-row\"> <Square value={squares[3]} onSquareClick={() => handleClick(3)} /> <Square value={squares[4]} onSquareClick={() => handleClick(4)} /> <Square value={squares[5]} onSquareClick={() => handleClick(5)} /> </div> <div className=\"board-row\"> <Square value={squares[6]} onSquareClick={() => handleClick(6)} /> <Square value={squares[7]} onSquareClick={() => handleClick(7)} /> <Square value={squares[8]} onSquareClick={() => handleClick(8)} /> </div> </> ); } export default function Game() { const [xIsNext, setXIsNext] = useState(true); const [history, setHistory] = useState([Array(9).fill(null)]); const currentSquares = history[history.length - 1]; function handlePlay(nextSquares) { setHistory([...history, nextSquares]); setXIsNext(!xIsNext); } function jumpTo(nextMove) { // TODO } const moves = history.map((squares, move) => { let description; if (move > 0) { description = 'Go to move #' + move; } else { description = 'Go to game start'; } return ( <li> <button onClick={() => jumpTo(move)}>{description}</button> </li> ); }); return ( <div className=\"game\"> <div className=\"game-board\"> <Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} /> </div> <div className=\"game-info\"> <ol>{moves}</ol> </div> </div> ); } function calculateWinner(squares) { const lines = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6], ]; for (let i = 0; i < lines.length; i++) { const [a, b, c] = lines[i]; if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { return squares[a]; } } return null; } Show more As you iterate through the history array inside the function you passed to map, the squares argument goes through each element of history, and the move argument goes through each array , 1, 2, …. (In most cases, you’d need the actual array elements, but to render a list of moves you will only need indexes.) For each move in the tic-tac-toe game’s history, you create a list item <li> which contains a button <button>. The button has an onClick handler which calls a function called jumpTo (that you haven’t implemented yet). For now, you should see a list of the moves that occurred in the game and an error in the developer tools console. Let’s discuss what the “key” error means. Picking a key When you render a list, React stores some information about each rendered list item. When you update a list, React needs to determine what has changed. You could have added, removed, re-arranged, or updated the list’s items. Imagine transitioning from <li>Alexa: 7 tasks left</li><li>Ben: 5 tasks left</li> to <li>Ben: 9 tasks left</li><li>Claudia: 8 tasks left</li><li>Alexa: 5 tasks left</li> In addition to the updated counts, a human reading this would probably say that you swapped Alexa and Ben’s ordering and inserted Claudia between Alexa and Ben. However, React is a computer program and does not know what you intended, so you need to specify a key property for each list item to differentiate each list item from its siblings. If your data was from a database, Alexa, Ben, and Claudia’s database IDs could be used as keys. <li key={user.id}> {user.name}: {user.taskCount} tasks left</li> When a list is re-rendered, React takes each list item’s key and searches the previous list’s items for a matching key. If the current list has a key that didn’t exist before, React creates a component. If the current list is missing a key that existed in the previous list, React destroys the previous component. If two keys match, the corresponding component is moved. Keys tell React about the identity of each component, which allows React to maintain state between re-renders. If a component’s key changes, the component will be destroyed and re-created with a new state. key is a special and reserved property in React. When an element is created, React extracts the key property and stores the key directly on the returned element. Even though key may look like it is passed as props, React automatically uses key to decide which components to update. There’s no way for a component to ask what key its parent specified. It’s strongly recommended that you assign proper keys whenever you build dynamic lists. If you don’t have an appropriate key, you may want to consider restructuring your data so that you do. If no key is specified, React will report an error and use the array index as a key by default. Using the array index as a key is problematic when trying to re-order a list’s items or inserting/removing list items. Explicitly passing key={i} silences the error but has the same problems as array indices and is not recommended in most cases. Keys do not need to be globally unique; they only need to be unique between components and their siblings. Implementing time travel In the tic-tac-toe game’s history, each past move has a unique ID associated with ’s the sequential number of the move. Moves will never be re-ordered, deleted, or inserted in the middle, so it’s safe to use the move index as a key. In the Game function, you can add the key as <li key={move}>, and if you reload the rendered game, React’s “key” error should moves = history.map((squares, move) => { //... return ( <li key={move}> <button onClick={() => jumpTo(move)}>{description}</button> </li> );}); App.jsApp.jsReloadClearForkimport { useState } from 'react'; function Square({ value, onSquareClick }) { return ( <button className=\"square\" onClick={onSquareClick}> {value} </button> ); } function Board({ xIsNext, squares, onPlay }) { function handleClick(i) { if (calculateWinner(squares) || squares[i]) { return; } const nextSquares = squares.slice(); if (xIsNext) { nextSquares[i] = 'X'; } else { nextSquares[i] = 'O'; } onPlay(nextSquares); } const winner = calculateWinner(squares); let status; if (winner) { status = 'Winner: ' + winner; } else { status = 'Next player: ' + (xIsNext ? 'X' : 'O'); } return ( <> <div className=\"status\">{status}</div> <div className=\"board-row\"> <Square value={squares[0]} onSquareClick={() => handleClick(0)} /> <Square value={squares[1]} onSquareClick={() => handleClick(1)} /> <Square value={squares[2]} onSquareClick={() => handleClick(2)} /> </div> <div className=\"board-row\"> <Square value={squares[3]} onSquareClick={() => handleClick(3)} /> <Square value={squares[4]} onSquareClick={() => handleClick(4)} /> <Square value={squares[5]} onSquareClick={() => handleClick(5)} /> </div> <div className=\"board-row\"> <Square value={squares[6]} onSquareClick={() => handleClick(6)} /> <Square value={squares[7]} onSquareClick={() => handleClick(7)} /> <Square value={squares[8]} onSquareClick={() => handleClick(8)} /> </div> </> ); } export default function Game() { const [xIsNext, setXIsNext] = useState(true); const [history, setHistory] = useState([Array(9).fill(null)]); const currentSquares = history[history.length - 1]; function handlePlay(nextSquares) { setHistory([...history, nextSquares]); setXIsNext(!xIsNext); } function jumpTo(nextMove) { // TODO } const moves = history.map((squares, move) => { let description; if (move > 0) { description = 'Go to move #' + move; } else { description = 'Go to game start'; } return ( <li key={move}> <button onClick={() => jumpTo(move)}>{description}</button> </li> ); }); return ( <div className=\"game\"> <div className=\"game-board\"> <Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} /> </div> <div className=\"game-info\"> <ol>{moves}</ol> </div> </div> ); } function calculateWinner(squares) { const lines = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6], ]; for (let i = 0; i < lines.length; i++) { const [a, b, c] = lines[i]; if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { return squares[a]; } } return null; } Show more Before you can implement jumpTo, you need the Game component to keep track of which step the user is currently viewing. To do this, define a new state variable called currentMove, defaulting to default function Game() { const [xIsNext, setXIsNext] = useState(true); const [history, setHistory] = useState([Array(9).fill(null)]); const [currentMove, setCurrentMove] = useState(0); const currentSquares = history[history.length - 1]; //...} Next, update the jumpTo function inside Game to update that currentMove. You’ll also set xIsNext to true if the number that you’re changing currentMove to is even. export default function Game() { // ... function jumpTo(nextMove) { setCurrentMove(nextMove); setXIsNext(nextMove % 2 === 0); } //...} You will now make two changes to the Game’s handlePlay function which is called when you click on a square. If you “go back in time” and then make a new move from that point, you only want to keep the history up to that point. Instead of adding nextSquares after all items (... spread syntax) in history, you’ll add it after all items in history.slice(0, currentMove + 1) so that you’re only keeping that portion of the old history. Each time a move is made, you need to update currentMove to point to the latest history entry. function handlePlay(nextSquares) { const nextHistory = [...history.slice(0, currentMove + 1), nextSquares]; setHistory(nextHistory); setCurrentMove(nextHistory.length - 1); setXIsNext(!xIsNext);} Finally, you will modify the Game component to render the currently selected move, instead of always rendering the final default function Game() { const [xIsNext, setXIsNext] = useState(true); const [history, setHistory] = useState([Array(9).fill(null)]); const [currentMove, setCurrentMove] = useState(0); const currentSquares = history[currentMove]; // ...} If you click on any step in the game’s history, the tic-tac-toe board should immediately update to show what the board looked like after that step occurred. App.jsApp.jsReloadClearForkimport { useState } from 'react'; function Square({value, onSquareClick}) { return ( <button className=\"square\" onClick={onSquareClick}> {value} </button> ); } function Board({ xIsNext, squares, onPlay }) { function handleClick(i) { if (calculateWinner(squares) || squares[i]) { return; } const nextSquares = squares.slice(); if (xIsNext) { nextSquares[i] = 'X'; } else { nextSquares[i] = 'O'; } onPlay(nextSquares); } const winner = calculateWinner(squares); let status; if (winner) { status = 'Winner: ' + winner; } else { status = 'Next player: ' + (xIsNext ? 'X' : 'O'); } return ( <> <div className=\"status\">{status}</div> <div className=\"board-row\"> <Square value={squares[0]} onSquareClick={() => handleClick(0)} /> <Square value={squares[1]} onSquareClick={() => handleClick(1)} /> <Square value={squares[2]} onSquareClick={() => handleClick(2)} /> </div> <div className=\"board-row\"> <Square value={squares[3]} onSquareClick={() => handleClick(3)} /> <Square value={squares[4]} onSquareClick={() => handleClick(4)} /> <Square value={squares[5]} onSquareClick={() => handleClick(5)} /> </div> <div className=\"board-row\"> <Square value={squares[6]} onSquareClick={() => handleClick(6)} /> <Square value={squares[7]} onSquareClick={() => handleClick(7)} /> <Square value={squares[8]} onSquareClick={() => handleClick(8)} /> </div> </> ); } export default function Game() { const [xIsNext, setXIsNext] = useState(true); const [history, setHistory] = useState([Array(9).fill(null)]); const [currentMove, setCurrentMove] = useState(0); const currentSquares = history[currentMove]; function handlePlay(nextSquares) { const nextHistory = [...history.slice(0, currentMove + 1), nextSquares]; setHistory(nextHistory); setCurrentMove(nextHistory.length - 1); setXIsNext(!xIsNext); } function jumpTo(nextMove) { setCurrentMove(nextMove); setXIsNext(nextMove % 2 === 0); } const moves = history.map((squares, move) => { let description; if (move > 0) { description = 'Go to move #' + move; } else { description = 'Go to game start'; } return ( <li key={move}> <button onClick={() => jumpTo(move)}>{description}</button> </li> ); }); return ( <div className=\"game\"> <div className=\"game-board\"> <Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} /> </div> <div className=\"game-info\"> <ol>{moves}</ol> </div> </div> ); } function calculateWinner(squares) { const lines = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6], ]; for (let i = 0; i < lines.length; i++) { const [a, b, c] = lines[i]; if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { return squares[a]; } } return null; } Show more Final cleanup If you look at the code very closely, you may notice that xIsNext === true when currentMove is even and xIsNext === false when currentMove is odd. In other words, if you know the value of currentMove, then you can always figure out what xIsNext should be. There’s no reason for you to store both of these in state. In fact, always try to avoid redundant state. Simplifying what you store in state reduces bugs and makes your code easier to understand. Change Game so that it doesn’t store xIsNext as a separate state variable and instead figures it out based on the default function Game() { const [history, setHistory] = useState([Array(9).fill(null)]); const [currentMove, setCurrentMove] = useState(0); const xIsNext = currentMove % 2 === 0; const currentSquares = history[currentMove]; function handlePlay(nextSquares) { const nextHistory = [...history.slice(0, currentMove + 1), nextSquares]; setHistory(nextHistory); setCurrentMove(nextHistory.length - 1); } function jumpTo(nextMove) { setCurrentMove(nextMove); } // ...} You no longer need the xIsNext state declaration or the calls to setXIsNext. Now, there’s no chance for xIsNext to get out of sync with currentMove, even if you make a mistake while coding the components. Wrapping up Congratulations! You’ve created a tic-tac-toe game you play tic-tac-toe, Indicates when a player has won the game, Stores a game’s history as a game progresses, Allows players to review a game’s history and see previous versions of a game’s board. Nice work! We hope you now feel like you have a decent grasp of how React works. Check out the final result { useState } from 'react'; function Square({ value, onSquareClick }) { return ( <button className=\"square\" onClick={onSquareClick}> {value} </button> ); } function Board({ xIsNext, squares, onPlay }) { function handleClick(i) { if (calculateWinner(squares) || squares[i]) { return; } const nextSquares = squares.slice(); if (xIsNext) { nextSquares[i] = 'X'; } else { nextSquares[i] = 'O'; } onPlay(nextSquares); } const winner = calculateWinner(squares); let status; if (winner) { status = 'Winner: ' + winner; } else { status = 'Next player: ' + (xIsNext ? 'X' : 'O'); } return ( <> <div className=\"status\">{status}</div> <div className=\"board-row\"> <Square value={squares[0]} onSquareClick={() => handleClick(0)} /> <Square value={squares[1]} onSquareClick={() => handleClick(1)} /> <Square value={squares[2]} onSquareClick={() => handleClick(2)} /> </div> <div className=\"board-row\"> <Square value={squares[3]} onSquareClick={() => handleClick(3)} /> <Square value={squares[4]} onSquareClick={() => handleClick(4)} /> <Square value={squares[5]} onSquareClick={() => handleClick(5)} /> </div> <div className=\"board-row\"> <Square value={squares[6]} onSquareClick={() => handleClick(6)} /> <Square value={squares[7]} onSquareClick={() => handleClick(7)} /> <Square value={squares[8]} onSquareClick={() => handleClick(8)} /> </div> </> ); } export default function Game() { const [history, setHistory] = useState([Array(9).fill(null)]); const [currentMove, setCurrentMove] = useState(0); const xIsNext = currentMove % 2 === 0; const currentSquares = history[currentMove]; function handlePlay(nextSquares) { const nextHistory = [...history.slice(0, currentMove + 1), nextSquares]; setHistory(nextHistory); setCurrentMove(nextHistory.length - 1); } function jumpTo(nextMove) { setCurrentMove(nextMove); } const moves = history.map((squares, move) => { let description; if (move > 0) { description = 'Go to move #' + move; } else { description = 'Go to game start'; } return ( <li key={move}> <button onClick={() => jumpTo(move)}>{description}</button> </li> ); }); return ( <div className=\"game\"> <div className=\"game-board\"> <Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} /> </div> <div className=\"game-info\"> <ol>{moves}</ol> </div> </div> ); } function calculateWinner(squares) { const lines = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6], ]; for (let i = 0; i < lines.length; i++) { const [a, b, c] = lines[i]; if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { return squares[a]; } } return null; } Show more If you have extra time or want to practice your new React skills, here are some ideas for improvements that you could make to the tic-tac-toe game, listed in order of increasing the current move only, show “You are at move #…” instead of a button. Rewrite Board to use two loops to make the squares instead of hardcoding them. Add a toggle button that lets you sort the moves in either ascending or descending order. When someone wins, highlight the three squares that caused the win (and when no one wins, display a message about the result being a draw). Display the location for each move in the format (row, col) in the move history list. Throughout this tutorial, you’ve touched on React concepts including elements, components, props, and state. Now that you’ve seen how these concepts work when building a game, check out Thinking in React to see how the same React concepts work when building an app’s UI.PreviousQuick StartNextThinking in ReactCopyright © Meta Platforms, Incno uwu plzuwu?Logo by@sawaratsuki1004Learn ReactQuick StartInstallationDescribing the UIAdding InteractivityManaging StateEscape HatchesAPI ReferenceReact APIsReact DOM APIsCommunityCode of ConductMeet the TeamDocs ContributorsAcknowledgementsMoreBlogReact NativePrivacyTermsOn this pageOverviewWhat are you building? Setup for the tutorial Overview Inspecting the starter code Building the board Passing data through props Making an interactive component React Developer Tools Completing the game Lifting state up Why immutability is important Taking turns Declaring a winner Adding time travel Storing a history of moves Lifting state up, again Showing the past moves Picking a key Implementing time travel Final cleanup Wrapping up\n\nExample:\n```text\nimport { useState } from 'react';\n\nfunction Square({ value, onSquareClick }) {\n  return (\n    <button className=\"square\" onClick={onSquareClick}>\n      {value}\n    </button>\n  );\n}\n\nfunction Board({ xIsNext, squares, onPlay }) {\n  function handleClick(i) {\n    if (calculateWinner(squares) || squares[i]) {\n      return;\n    }\n    const nextSquares = squares.slice();\n    if (xIsNext) {\n      nextSquares[i] = 'X';\n    } else {\n      nextSquares[i] = 'O';\n    }\n    onPlay(nextSquares);\n  }\n\n  const winner = calculateWinner(squares);\n  let status;\n  if (winner) {\n    status = 'Winner: ' + winner;\n  } else {\n    status = 'Next player: ' + (xIsNext ? 'X' : 'O');\n  }\n\n  return (\n    <>\n      <div className=\"status\">{status}</div>\n      <div className=\"board-row\">\n        <Square value={squares[0]} onSquareClick={() => handleClick(0)} />\n        <Square value={squares[1]} onSquareClick={() => handleClick(1)} />\n        <Square value={squares[2]} onSquareClick={() => handleClick(2)} />\n      </div>\n      <div className=\"board-row\">\n        <Square value={squares[3]} onSquareClick={() => handleClick(3)} />\n        <Square value={squares[4]} onSquareClick={() => handleClick(4)} />\n        <Square value={squares[5]} onSquareClick={() => handleClick(5)} />\n      </div>\n      <div className=\"board-row\">\n        <Square value={squares[6]} onSquareClick={() => handleClick(6)} />\n        <Square value={squares[7]} onSquareClick={() => handleClick(7)} />\n        <Square value={squares[8]} onSquareClick={() => handleClick(8)} />\n      </div>\n    </>\n  );\n}\n\nexport default function Game() {\n  const [history, setHistory] = useState([Array(9).fill(null)]);\n  const [currentMove, setCurrentMove] = useState(0);\n  const xIsNext = currentMove % 2 === 0;\n  const currentSquares = history[currentMove];\n\n  function handlePlay(nextSquares) {\n    const nextHistory = [...history.slice(0, currentMove + 1), nextSquares];\n    setHistory(nextHistory);\n    setCurrentMove(nextHistory.length - 1);\n  }\n\n  function jumpTo(nextMove) {\n    setCurrentMove(nextMove);\n  }\n\n  const moves = history.map((squares, move) => {\n    let description;\n    if (move > 0) {\n      description = 'Go to move #' + move;\n    } else {\n      description = 'Go to game start';\n    }\n    return (\n      <li key={move}>\n        <button onClick={() => jumpTo(move)}>{description}</button>\n      </li>\n    );\n  });\n\n  return (\n    <div className=\"game\">\n      <div className=\"game-board\">\n        <Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} />\n      </div>\n      <div className=\"game-info\">\n        <ol>{moves}</ol>\n      </div>\n    </div>\n  );\n}\n\nfunction calculateWinner(squares) {\n  const lines = [\n    [0, 1, 2],\n    [3, 4, 5],\n    [6, 7, 8],\n    [0, 3, 6],\n    [1, 4, 7],\n    [2, 5, 8],\n    [0, 4, 8],\n    [2, 4, 6],\n  ];\n  for (let i = 0; i < lines.length; i++) {\n    const [a, b, c] = lines[i];\n    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {\n      return squares[a];\n    }\n  }\n  return null;\n}\n```\n\nExample:\n```text\nexport default function Square() {\n  return <button className=\"square\">X</button>;\n}\n```\n\nExample:\n```javascript\nexport default function Square() {  return <button className=\"square\">X</button>;}\n```\n\nExample:\n```javascript\nimport { StrictMode } from 'react';import { createRoot } from 'react-dom/client';import './styles.css';import App from './App';\n```\n\nExample:\n```javascript\nexport default function Square() {  return <button className=\"square\">X</button><button className=\"square\">X</button>;}\n```\n\nExample:\n```javascript\nexport default function Square() {  return (    <>      <button className=\"square\">X</button>      <button className=\"square\">X</button>    </>  );}\n```\n\nExample:\n```javascript\nexport default function Square() {  return (    <>      <div className=\"board-row\">        <button className=\"square\">1</button>        <button className=\"square\">2</button>        <button className=\"square\">3</button>      </div>      <div className=\"board-row\">        <button className=\"square\">4</button>        <button className=\"square\">5</button>        <button className=\"square\">6</button>      </div>      <div className=\"board-row\">        <button className=\"square\">7</button>        <button className=\"square\">8</button>        <button className=\"square\">9</button>      </div>    </>  );}\n```\n\nExample:\n```javascript\nexport default function Board() {  //...}\n```\n\nExample:\n```text\nexport default function Board() {\n  return (\n    <>\n      <div className=\"board-row\">\n        <button className=\"square\">1</button>\n        <button className=\"square\">2</button>\n        <button className=\"square\">3</button>\n      </div>\n      <div className=\"board-row\">\n        <button className=\"square\">4</button>\n        <button className=\"square\">5</button>\n        <button className=\"square\">6</button>\n      </div>\n      <div className=\"board-row\">\n        <button className=\"square\">7</button>\n        <button className=\"square\">8</button>\n        <button className=\"square\">9</button>\n      </div>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nfunction Square() {  return <button className=\"square\">1</button>;}export default function Board() {  // ...}\n```\n\nExample:\n```javascript\n// ...export default function Board() {  return (    <>      <div className=\"board-row\">        <Square />        <Square />        <Square />      </div>      <div className=\"board-row\">        <Square />        <Square />        <Square />      </div>      <div className=\"board-row\">        <Square />        <Square />        <Square />      </div>    </>  );}\n```\n\nExample:\n```javascript\nfunction Square({ value }) {  return <button className=\"square\">1</button>;}\n```\n\nExample:\n```javascript\nfunction Square({ value }) {  return <button className=\"square\">value</button>;}\n```\n\nExample:\n```javascript\nfunction Square({ value }) {  return <button className=\"square\">{value}</button>;}\n```\n\nExample:\n```javascript\nexport default function Board() {  return (    <>      <div className=\"board-row\">        <Square value=\"1\" />        <Square value=\"2\" />        <Square value=\"3\" />      </div>      <div className=\"board-row\">        <Square value=\"4\" />        <Square value=\"5\" />        <Square value=\"6\" />      </div>      <div className=\"board-row\">        <Square value=\"7\" />        <Square value=\"8\" />        <Square value=\"9\" />      </div>    </>  );}\n```\n\nExample:\n```text\nfunction Square({ value }) {\n  return <button className=\"square\">{value}</button>;\n}\n\nexport default function Board() {\n  return (\n    <>\n      <div className=\"board-row\">\n        <Square value=\"1\" />\n        <Square value=\"2\" />\n        <Square value=\"3\" />\n      </div>\n      <div className=\"board-row\">\n        <Square value=\"4\" />\n        <Square value=\"5\" />\n        <Square value=\"6\" />\n      </div>\n      <div className=\"board-row\">\n        <Square value=\"7\" />\n        <Square value=\"8\" />\n        <Square value=\"9\" />\n      </div>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nfunction Square({ value }) {  function handleClick() {    console.log('clicked!');  }  return (    <button      className=\"square\"      onClick={handleClick}    >      {value}    </button>  );}\n```\n\nExample:\n```javascript\nimport { useState } from 'react';function Square() {  const [value, setValue] = useState(null);  function handleClick() {    //...\n```\n\nExample:\n```javascript\nfunction Square() {  const [value, setValue] = useState(null);  function handleClick() {    setValue('X');  }  return (    <button      className=\"square\"      onClick={handleClick}    >      {value}    </button>  );}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nfunction Square() {\n  const [value, setValue] = useState(null);\n\n  function handleClick() {\n    setValue('X');\n  }\n\n  return (\n    <button\n      className=\"square\"\n      onClick={handleClick}\n    >\n      {value}\n    </button>\n  );\n}\n\nexport default function Board() {\n  return (\n    <>\n      <div className=\"board-row\">\n        <Square />\n        <Square />\n        <Square />\n      </div>\n      <div className=\"board-row\">\n        <Square />\n        <Square />\n        <Square />\n      </div>\n      <div className=\"board-row\">\n        <Square />\n        <Square />\n        <Square />\n      </div>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\n// ...export default function Board() {  const [squares, setSquares] = useState(Array(9).fill(null));  return (    // ...  );}\n```\n\nExample:\n```javascript\n['O', null, 'X', 'X', 'X', 'O', 'O', null, null]\n```\n\nExample:\n```javascript\nexport default function Board() {  const [squares, setSquares] = useState(Array(9).fill(null));  return (    <>      <div className=\"board-row\">        <Square value={squares[0]} />        <Square value={squares[1]} />        <Square value={squares[2]} />      </div>      <div className=\"board-row\">        <Square value={squares[3]} />        <Square value={squares[4]} />        <Square value={squares[5]} />      </div>      <div className=\"board-row\">        <Square value={squares[6]} />        <Square value={squares[7]} />        <Square value={squares[8]} />      </div>    </>  );}\n```\n\nExample:\n```javascript\nfunction Square({value}) {  return <button className=\"square\">{value}</button>;}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nfunction Square({ value }) {\n  return <button className=\"square\">{value}</button>;\n}\n\nexport default function Board() {\n  const [squares, setSquares] = useState(Array(9).fill(null));\n  return (\n    <>\n      <div className=\"board-row\">\n        <Square value={squares[0]} />\n        <Square value={squares[1]} />\n        <Square value={squares[2]} />\n      </div>\n      <div className=\"board-row\">\n        <Square value={squares[3]} />\n        <Square value={squares[4]} />\n        <Square value={squares[5]} />\n      </div>\n      <div className=\"board-row\">\n        <Square value={squares[6]} />\n        <Square value={squares[7]} />\n        <Square value={squares[8]} />\n      </div>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nfunction Square({ value }) {  return (    <button className=\"square\" onClick={onSquareClick}>      {value}    </button>  );}\n```\n\nExample:\n```javascript\nfunction Square({ value, onSquareClick }) {  return (    <button className=\"square\" onClick={onSquareClick}>      {value}    </button>  );}\n```\n\nExample:\n```javascript\nexport default function Board() {  const [squares, setSquares] = useState(Array(9).fill(null));  return (    <>      <div className=\"board-row\">        <Square value={squares[0]} onSquareClick={handleClick} />        //...  );}\n```\n\nExample:\n```javascript\nexport default function Board() {  const [squares, setSquares] = useState(Array(9).fill(null));  function handleClick() {    const nextSquares = squares.slice();    nextSquares[0] = \"X\";    setSquares(nextSquares);  }  return (    // ...  )}\n```\n\nExample:\n```javascript\nexport default function Board() {  const [squares, setSquares] = useState(Array(9).fill(null));  function handleClick(i) {    const nextSquares = squares.slice();    nextSquares[i] = \"X\";    setSquares(nextSquares);  }  return (    // ...  )}\n```\n\nExample:\n```javascript\n<Square value={squares[0]} onSquareClick={handleClick(0)} />\n```\n\nExample:\n```javascript\nexport default function Board() {  // ...  return (    <>      <div className=\"board-row\">        <Square value={squares[0]} onSquareClick={() => handleClick(0)} />        // ...  );}\n```\n\nExample:\n```javascript\nexport default function Board() {  // ...  return (    <>      <div className=\"board-row\">        <Square value={squares[0]} onSquareClick={() => handleClick(0)} />        <Square value={squares[1]} onSquareClick={() => handleClick(1)} />        <Square value={squares[2]} onSquareClick={() => handleClick(2)} />      </div>      <div className=\"board-row\">        <Square value={squares[3]} onSquareClick={() => handleClick(3)} />        <Square value={squares[4]} onSquareClick={() => handleClick(4)} />        <Square value={squares[5]} onSquareClick={() => handleClick(5)} />      </div>      <div className=\"board-row\">        <Square value={squares[6]} onSquareClick={() => handleClick(6)} />        <Square value={squares[7]} onSquareClick={() => handleClick(7)} />        <Square value={squares[8]} onSquareClick={() => handleClick(8)} />      </div>    </>  );};\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nfunction Square({ value, onSquareClick }) {\n  return (\n    <button className=\"square\" onClick={onSquareClick}>\n      {value}\n    </button>\n  );\n}\n\nexport default function Board() {\n  const [squares, setSquares] = useState(Array(9).fill(null));\n\n  function handleClick(i) {\n    const nextSquares = squares.slice();\n    nextSquares[i] = 'X';\n    setSquares(nextSquares);\n  }\n\n  return (\n    <>\n      <div className=\"board-row\">\n        <Square value={squares[0]} onSquareClick={() => handleClick(0)} />\n        <Square value={squares[1]} onSquareClick={() => handleClick(1)} />\n        <Square value={squares[2]} onSquareClick={() => handleClick(2)} />\n      </div>\n      <div className=\"board-row\">\n        <Square value={squares[3]} onSquareClick={() => handleClick(3)} />\n        <Square value={squares[4]} onSquareClick={() => handleClick(4)} />\n        <Square value={squares[5]} onSquareClick={() => handleClick(5)} />\n      </div>\n      <div className=\"board-row\">\n        <Square value={squares[6]} onSquareClick={() => handleClick(6)} />\n        <Square value={squares[7]} onSquareClick={() => handleClick(7)} />\n        <Square value={squares[8]} onSquareClick={() => handleClick(8)} />\n      </div>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nconst squares = [null, null, null, null, null, null, null, null, null];squares[0] = 'X';// Now `squares` is [\"X\", null, null, null, null, null, null, null, null];\n```\n\nExample:\n```javascript\nconst squares = [null, null, null, null, null, null, null, null, null];const nextSquares = ['X', null, null, null, null, null, null, null, null];// Now `squares` is unchanged, but `nextSquares` first element is 'X' rather than `null`\n```\n\nExample:\n```javascript\nfunction Board() {  const [xIsNext, setXIsNext] = useState(true);  const [squares, setSquares] = useState(Array(9).fill(null));  // ...}\n```\n\nExample:\n```javascript\nexport default function Board() {  const [xIsNext, setXIsNext] = useState(true);  const [squares, setSquares] = useState(Array(9).fill(null));  function handleClick(i) {    const nextSquares = squares.slice();    if (xIsNext) {      nextSquares[i] = \"X\";    } else {      nextSquares[i] = \"O\";    }    setSquares(nextSquares);    setXIsNext(!xIsNext);  }  return (    //...  );}\n```\n\nExample:\n```javascript\nfunction handleClick(i) {  if (squares[i]) {    return;  }  const nextSquares = squares.slice();  //...}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nfunction Square({value, onSquareClick}) {\n  return (\n    <button className=\"square\" onClick={onSquareClick}>\n      {value}\n    </button>\n  );\n}\n\nexport default function Board() {\n  const [xIsNext, setXIsNext] = useState(true);\n  const [squares, setSquares] = useState(Array(9).fill(null));\n\n  function handleClick(i) {\n    if (squares[i]) {\n      return;\n    }\n    const nextSquares = squares.slice();\n    if (xIsNext) {\n      nextSquares[i] = 'X';\n    } else {\n      nextSquares[i] = 'O';\n    }\n    setSquares(nextSquares);\n    setXIsNext(!xIsNext);\n  }\n\n  return (\n    <>\n      <div className=\"board-row\">\n        <Square value={squares[0]} onSquareClick={() => handleClick(0)} />\n        <Square value={squares[1]} onSquareClick={() => handleClick(1)} />\n        <Square value={squares[2]} onSquareClick={() => handleClick(2)} />\n      </div>\n      <div className=\"board-row\">\n        <Square value={squares[3]} onSquareClick={() => handleClick(3)} />\n        <Square value={squares[4]} onSquareClick={() => handleClick(4)} />\n        <Square value={squares[5]} onSquareClick={() => handleClick(5)} />\n      </div>\n      <div className=\"board-row\">\n        <Square value={squares[6]} onSquareClick={() => handleClick(6)} />\n        <Square value={squares[7]} onSquareClick={() => handleClick(7)} />\n        <Square value={squares[8]} onSquareClick={() => handleClick(8)} />\n      </div>\n    </>\n  );\n}\n```\n\nExample:\n```javascript\nexport default function Board() {  //...}function calculateWinner(squares) {  const lines = [    [0, 1, 2],    [3, 4, 5],    [6, 7, 8],    [0, 3, 6],    [1, 4, 7],    [2, 5, 8],    [0, 4, 8],    [2, 4, 6]  ];  for (let i = 0; i < lines.length; i++) {    const [a, b, c] = lines[i];    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {      return squares[a];    }  }  return null;}\n```\n\nExample:\n```javascript\nfunction handleClick(i) {  if (squares[i] || calculateWinner(squares)) {    return;  }  const nextSquares = squares.slice();  //...}\n```\n\nExample:\n```javascript\nexport default function Board() {  // ...  const winner = calculateWinner(squares);  let status;  if (winner) {    status = \"Winner: \" + winner;  } else {    status = \"Next player: \" + (xIsNext ? \"X\" : \"O\");  }  return (    <>      <div className=\"status\">{status}</div>      <div className=\"board-row\">        // ...  )}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nfunction Square({value, onSquareClick}) {\n  return (\n    <button className=\"square\" onClick={onSquareClick}>\n      {value}\n    </button>\n  );\n}\n\nexport default function Board() {\n  const [xIsNext, setXIsNext] = useState(true);\n  const [squares, setSquares] = useState(Array(9).fill(null));\n\n  function handleClick(i) {\n    if (calculateWinner(squares) || squares[i]) {\n      return;\n    }\n    const nextSquares = squares.slice();\n    if (xIsNext) {\n      nextSquares[i] = 'X';\n    } else {\n      nextSquares[i] = 'O';\n    }\n    setSquares(nextSquares);\n    setXIsNext(!xIsNext);\n  }\n\n  const winner = calculateWinner(squares);\n  let status;\n  if (winner) {\n    status = 'Winner: ' + winner;\n  } else {\n    status = 'Next player: ' + (xIsNext ? 'X' : 'O');\n  }\n\n  return (\n    <>\n      <div className=\"status\">{status}</div>\n      <div className=\"board-row\">\n        <Square value={squares[0]} onSquareClick={() => handleClick(0)} />\n        <Square value={squares[1]} onSquareClick={() => handleClick(1)} />\n        <Square value={squares[2]} onSquareClick={() => handleClick(2)} />\n      </div>\n      <div className=\"board-row\">\n        <Square value={squares[3]} onSquareClick={() => handleClick(3)} />\n        <Square value={squares[4]} onSquareClick={() => handleClick(4)} />\n        <Square value={squares[5]} onSquareClick={() => handleClick(5)} />\n      </div>\n      <div className=\"board-row\">\n        <Square value={squares[6]} onSquareClick={() => handleClick(6)} />\n        <Square value={squares[7]} onSquareClick={() => handleClick(7)} />\n        <Square value={squares[8]} onSquareClick={() => handleClick(8)} />\n      </div>\n    </>\n  );\n}\n\nfunction calculateWinner(squares) {\n  const lines = [\n    [0, 1, 2],\n    [3, 4, 5],\n    [6, 7, 8],\n    [0, 3, 6],\n    [1, 4, 7],\n    [2, 5, 8],\n    [0, 4, 8],\n    [2, 4, 6],\n  ];\n  for (let i = 0; i < lines.length; i++) {\n    const [a, b, c] = lines[i];\n    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {\n      return squares[a];\n    }\n  }\n  return null;\n}\n```\n\nExample:\n```javascript\n[  // Before first move  [null, null, null, null, null, null, null, null, null],  // After first move  [null, null, null, null, 'X', null, null, null, null],  // After second move  [null, null, null, null, 'X', null, null, null, 'O'],  // ...]\n```\n\nExample:\n```javascript\nfunction Board() {  // ...}export default function Game() {  return (    <div className=\"game\">      <div className=\"game-board\">        <Board />      </div>      <div className=\"game-info\">        <ol>{/*TODO*/}</ol>      </div>    </div>  );}\n```\n\nExample:\n```javascript\nexport default function Game() {  const [xIsNext, setXIsNext] = useState(true);  const [history, setHistory] = useState([Array(9).fill(null)]);  // ...\n```\n\nExample:\n```javascript\nexport default function Game() {  const [xIsNext, setXIsNext] = useState(true);  const [history, setHistory] = useState([Array(9).fill(null)]);  const currentSquares = history[history.length - 1];  // ...\n```\n\nExample:\n```javascript\nexport default function Game() {  const [xIsNext, setXIsNext] = useState(true);  const [history, setHistory] = useState([Array(9).fill(null)]);  const currentSquares = history[history.length - 1];  function handlePlay(nextSquares) {    // TODO  }  return (    <div className=\"game\">      <div className=\"game-board\">        <Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} />        //...  )}\n```\n\nExample:\n```javascript\nfunction Board({ xIsNext, squares, onPlay }) {  function handleClick(i) {    //...  }  // ...}\n```\n\nExample:\n```javascript\nfunction Board({ xIsNext, squares, onPlay }) {  function handleClick(i) {    if (calculateWinner(squares) || squares[i]) {      return;    }    const nextSquares = squares.slice();    if (xIsNext) {      nextSquares[i] = \"X\";    } else {      nextSquares[i] = \"O\";    }    onPlay(nextSquares);  }  //...}\n```\n\nExample:\n```javascript\nexport default function Game() {  //...  function handlePlay(nextSquares) {    setHistory([...history, nextSquares]);    setXIsNext(!xIsNext);  }  //...}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nfunction Square({ value, onSquareClick }) {\n  return (\n    <button className=\"square\" onClick={onSquareClick}>\n      {value}\n    </button>\n  );\n}\n\nfunction Board({ xIsNext, squares, onPlay }) {\n  function handleClick(i) {\n    if (calculateWinner(squares) || squares[i]) {\n      return;\n    }\n    const nextSquares = squares.slice();\n    if (xIsNext) {\n      nextSquares[i] = 'X';\n    } else {\n      nextSquares[i] = 'O';\n    }\n    onPlay(nextSquares);\n  }\n\n  const winner = calculateWinner(squares);\n  let status;\n  if (winner) {\n    status = 'Winner: ' + winner;\n  } else {\n    status = 'Next player: ' + (xIsNext ? 'X' : 'O');\n  }\n\n  return (\n    <>\n      <div className=\"status\">{status}</div>\n      <div className=\"board-row\">\n        <Square value={squares[0]} onSquareClick={() => handleClick(0)} />\n        <Square value={squares[1]} onSquareClick={() => handleClick(1)} />\n        <Square value={squares[2]} onSquareClick={() => handleClick(2)} />\n      </div>\n      <div className=\"board-row\">\n        <Square value={squares[3]} onSquareClick={() => handleClick(3)} />\n        <Square value={squares[4]} onSquareClick={() => handleClick(4)} />\n        <Square value={squares[5]} onSquareClick={() => handleClick(5)} />\n      </div>\n      <div className=\"board-row\">\n        <Square value={squares[6]} onSquareClick={() => handleClick(6)} />\n        <Square value={squares[7]} onSquareClick={() => handleClick(7)} />\n        <Square value={squares[8]} onSquareClick={() => handleClick(8)} />\n      </div>\n    </>\n  );\n}\n\nexport default function Game() {\n  const [xIsNext, setXIsNext] = useState(true);\n  const [history, setHistory] = useState([Array(9).fill(null)]);\n  const currentSquares = history[history.length - 1];\n\n  function handlePlay(nextSquares) {\n    setHistory([...history, nextSquares]);\n    setXIsNext(!xIsNext);\n  }\n\n  return (\n    <div className=\"game\">\n      <div className=\"game-board\">\n        <Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} />\n      </div>\n      <div className=\"game-info\">\n        <ol>{/*TODO*/}</ol>\n      </div>\n    </div>\n  );\n}\n\nfunction calculateWinner(squares) {\n  const lines = [\n    [0, 1, 2],\n    [3, 4, 5],\n    [6, 7, 8],\n    [0, 3, 6],\n    [1, 4, 7],\n    [2, 5, 8],\n    [0, 4, 8],\n    [2, 4, 6],\n  ];\n  for (let i = 0; i < lines.length; i++) {\n    const [a, b, c] = lines[i];\n    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {\n      return squares[a];\n    }\n  }\n  return null;\n}\n```\n\nExample:\n```javascript\n[1, 2, 3].map((x) => x * 2) // [2, 4, 6]\n```\n\nExample:\n```javascript\nexport default function Game() {  const [xIsNext, setXIsNext] = useState(true);  const [history, setHistory] = useState([Array(9).fill(null)]);  const currentSquares = history[history.length - 1];  function handlePlay(nextSquares) {    setHistory([...history, nextSquares]);    setXIsNext(!xIsNext);  }  function jumpTo(nextMove) {    // TODO  }  const moves = history.map((squares, move) => {    let description;    if (move > 0) {      description = 'Go to move #' + move;    } else {      description = 'Go to game start';    }    return (      <li>        <button onClick={() => jumpTo(move)}>{description}</button>      </li>    );  });  return (    <div className=\"game\">      <div className=\"game-board\">        <Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} />      </div>      <div className=\"game-info\">        <ol>{moves}</ol>      </div>    </div>  );}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nfunction Square({ value, onSquareClick }) {\n  return (\n    <button className=\"square\" onClick={onSquareClick}>\n      {value}\n    </button>\n  );\n}\n\nfunction Board({ xIsNext, squares, onPlay }) {\n  function handleClick(i) {\n    if (calculateWinner(squares) || squares[i]) {\n      return;\n    }\n    const nextSquares = squares.slice();\n    if (xIsNext) {\n      nextSquares[i] = 'X';\n    } else {\n      nextSquares[i] = 'O';\n    }\n    onPlay(nextSquares);\n  }\n\n  const winner = calculateWinner(squares);\n  let status;\n  if (winner) {\n    status = 'Winner: ' + winner;\n  } else {\n    status = 'Next player: ' + (xIsNext ? 'X' : 'O');\n  }\n\n  return (\n    <>\n      <div className=\"status\">{status}</div>\n      <div className=\"board-row\">\n        <Square value={squares[0]} onSquareClick={() => handleClick(0)} />\n        <Square value={squares[1]} onSquareClick={() => handleClick(1)} />\n        <Square value={squares[2]} onSquareClick={() => handleClick(2)} />\n      </div>\n      <div className=\"board-row\">\n        <Square value={squares[3]} onSquareClick={() => handleClick(3)} />\n        <Square value={squares[4]} onSquareClick={() => handleClick(4)} />\n        <Square value={squares[5]} onSquareClick={() => handleClick(5)} />\n      </div>\n      <div className=\"board-row\">\n        <Square value={squares[6]} onSquareClick={() => handleClick(6)} />\n        <Square value={squares[7]} onSquareClick={() => handleClick(7)} />\n        <Square value={squares[8]} onSquareClick={() => handleClick(8)} />\n      </div>\n    </>\n  );\n}\n\nexport default function Game() {\n  const [xIsNext, setXIsNext] = useState(true);\n  const [history, setHistory] = useState([Array(9).fill(null)]);\n  const currentSquares = history[history.length - 1];\n\n  function handlePlay(nextSquares) {\n    setHistory([...history, nextSquares]);\n    setXIsNext(!xIsNext);\n  }\n\n  function jumpTo(nextMove) {\n    // TODO\n  }\n\n  const moves = history.map((squares, move) => {\n    let description;\n    if (move > 0) {\n      description = 'Go to move #' + move;\n    } else {\n      description = 'Go to game start';\n    }\n    return (\n      <li>\n        <button onClick={() => jumpTo(move)}>{description}</button>\n      </li>\n    );\n  });\n\n  return (\n    <div className=\"game\">\n      <div className=\"game-board\">\n        <Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} />\n      </div>\n      <div className=\"game-info\">\n        <ol>{moves}</ol>\n      </div>\n    </div>\n  );\n}\n\nfunction calculateWinner(squares) {\n  const lines = [\n    [0, 1, 2],\n    [3, 4, 5],\n    [6, 7, 8],\n    [0, 3, 6],\n    [1, 4, 7],\n    [2, 5, 8],\n    [0, 4, 8],\n    [2, 4, 6],\n  ];\n  for (let i = 0; i < lines.length; i++) {\n    const [a, b, c] = lines[i];\n    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {\n      return squares[a];\n    }\n  }\n  return null;\n}\n```\n\nExample:\n```javascript\nconst moves = history.map((squares, move) => {  //...  return (    <li key={move}>      <button onClick={() => jumpTo(move)}>{description}</button>    </li>  );});\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nfunction Square({ value, onSquareClick }) {\n  return (\n    <button className=\"square\" onClick={onSquareClick}>\n      {value}\n    </button>\n  );\n}\n\nfunction Board({ xIsNext, squares, onPlay }) {\n  function handleClick(i) {\n    if (calculateWinner(squares) || squares[i]) {\n      return;\n    }\n    const nextSquares = squares.slice();\n    if (xIsNext) {\n      nextSquares[i] = 'X';\n    } else {\n      nextSquares[i] = 'O';\n    }\n    onPlay(nextSquares);\n  }\n\n  const winner = calculateWinner(squares);\n  let status;\n  if (winner) {\n    status = 'Winner: ' + winner;\n  } else {\n    status = 'Next player: ' + (xIsNext ? 'X' : 'O');\n  }\n\n  return (\n    <>\n      <div className=\"status\">{status}</div>\n      <div className=\"board-row\">\n        <Square value={squares[0]} onSquareClick={() => handleClick(0)} />\n        <Square value={squares[1]} onSquareClick={() => handleClick(1)} />\n        <Square value={squares[2]} onSquareClick={() => handleClick(2)} />\n      </div>\n      <div className=\"board-row\">\n        <Square value={squares[3]} onSquareClick={() => handleClick(3)} />\n        <Square value={squares[4]} onSquareClick={() => handleClick(4)} />\n        <Square value={squares[5]} onSquareClick={() => handleClick(5)} />\n      </div>\n      <div className=\"board-row\">\n        <Square value={squares[6]} onSquareClick={() => handleClick(6)} />\n        <Square value={squares[7]} onSquareClick={() => handleClick(7)} />\n        <Square value={squares[8]} onSquareClick={() => handleClick(8)} />\n      </div>\n    </>\n  );\n}\n\nexport default function Game() {\n  const [xIsNext, setXIsNext] = useState(true);\n  const [history, setHistory] = useState([Array(9).fill(null)]);\n  const currentSquares = history[history.length - 1];\n\n  function handlePlay(nextSquares) {\n    setHistory([...history, nextSquares]);\n    setXIsNext(!xIsNext);\n  }\n\n  function jumpTo(nextMove) {\n    // TODO\n  }\n\n  const moves = history.map((squares, move) => {\n    let description;\n    if (move > 0) {\n      description = 'Go to move #' + move;\n    } else {\n      description = 'Go to game start';\n    }\n    return (\n      <li key={move}>\n        <button onClick={() => jumpTo(move)}>{description}</button>\n      </li>\n    );\n  });\n\n  return (\n    <div className=\"game\">\n      <div className=\"game-board\">\n        <Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} />\n      </div>\n      <div className=\"game-info\">\n        <ol>{moves}</ol>\n      </div>\n    </div>\n  );\n}\n\nfunction calculateWinner(squares) {\n  const lines = [\n    [0, 1, 2],\n    [3, 4, 5],\n    [6, 7, 8],\n    [0, 3, 6],\n    [1, 4, 7],\n    [2, 5, 8],\n    [0, 4, 8],\n    [2, 4, 6],\n  ];\n  for (let i = 0; i < lines.length; i++) {\n    const [a, b, c] = lines[i];\n    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {\n      return squares[a];\n    }\n  }\n  return null;\n}\n```\n\nExample:\n```javascript\nexport default function Game() {  const [xIsNext, setXIsNext] = useState(true);  const [history, setHistory] = useState([Array(9).fill(null)]);  const [currentMove, setCurrentMove] = useState(0);  const currentSquares = history[history.length - 1];  //...}\n```\n\nExample:\n```javascript\nexport default function Game() {  // ...  function jumpTo(nextMove) {    setCurrentMove(nextMove);    setXIsNext(nextMove % 2 === 0);  }  //...}\n```\n\nExample:\n```javascript\nfunction handlePlay(nextSquares) {  const nextHistory = [...history.slice(0, currentMove + 1), nextSquares];  setHistory(nextHistory);  setCurrentMove(nextHistory.length - 1);  setXIsNext(!xIsNext);}\n```\n\nExample:\n```javascript\nexport default function Game() {  const [xIsNext, setXIsNext] = useState(true);  const [history, setHistory] = useState([Array(9).fill(null)]);  const [currentMove, setCurrentMove] = useState(0);  const currentSquares = history[currentMove];  // ...}\n```\n\nExample:\n```text\nimport { useState } from 'react';\n\nfunction Square({value, onSquareClick}) {\n  return (\n    <button className=\"square\" onClick={onSquareClick}>\n      {value}\n    </button>\n  );\n}\n\nfunction Board({ xIsNext, squares, onPlay }) {\n  function handleClick(i) {\n    if (calculateWinner(squares) || squares[i]) {\n      return;\n    }\n    const nextSquares = squares.slice();\n    if (xIsNext) {\n      nextSquares[i] = 'X';\n    } else {\n      nextSquares[i] = 'O';\n    }\n    onPlay(nextSquares);\n  }\n\n  const winner = calculateWinner(squares);\n  let status;\n  if (winner) {\n    status = 'Winner: ' + winner;\n  } else {\n    status = 'Next player: ' + (xIsNext ? 'X' : 'O');\n  }\n\n  return (\n    <>\n      <div className=\"status\">{status}</div>\n      <div className=\"board-row\">\n        <Square value={squares[0]} onSquareClick={() => handleClick(0)} />\n        <Square value={squares[1]} onSquareClick={() => handleClick(1)} />\n        <Square value={squares[2]} onSquareClick={() => handleClick(2)} />\n      </div>\n      <div className=\"board-row\">\n        <Square value={squares[3]} onSquareClick={() => handleClick(3)} />\n        <Square value={squares[4]} onSquareClick={() => handleClick(4)} />\n        <Square value={squares[5]} onSquareClick={() => handleClick(5)} />\n      </div>\n      <div className=\"board-row\">\n        <Square value={squares[6]} onSquareClick={() => handleClick(6)} />\n        <Square value={squares[7]} onSquareClick={() => handleClick(7)} />\n        <Square value={squares[8]} onSquareClick={() => handleClick(8)} />\n      </div>\n    </>\n  );\n}\n\nexport default function Game() {\n  const [xIsNext, setXIsNext] = useState(true);\n  const [history, setHistory] = useState([Array(9).fill(null)]);\n  const [currentMove, setCurrentMove] = useState(0);\n  const currentSquares = history[currentMove];\n\n  function handlePlay(nextSquares) {\n    const nextHistory = [...history.slice(0, currentMove + 1), nextSquares];\n    setHistory(nextHistory);\n    setCurrentMove(nextHistory.length - 1);\n    setXIsNext(!xIsNext);\n  }\n\n  function jumpTo(nextMove) {\n    setCurrentMove(nextMove);\n    setXIsNext(nextMove % 2 === 0);\n  }\n\n  const moves = history.map((squares, move) => {\n    let description;\n    if (move > 0) {\n      description = 'Go to move #' + move;\n    } else {\n      description = 'Go to game start';\n    }\n    return (\n      <li key={move}>\n        <button onClick={() => jumpTo(move)}>{description}</button>\n      </li>\n    );\n  });\n\n  return (\n    <div className=\"game\">\n      <div className=\"game-board\">\n        <Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} />\n      </div>\n      <div className=\"game-info\">\n        <ol>{moves}</ol>\n      </div>\n    </div>\n  );\n}\n\nfunction calculateWinner(squares) {\n  const lines = [\n    [0, 1, 2],\n    [3, 4, 5],\n    [6, 7, 8],\n    [0, 3, 6],\n    [1, 4, 7],\n    [2, 5, 8],\n    [0, 4, 8],\n    [2, 4, 6],\n  ];\n  for (let i = 0; i < lines.length; i++) {\n    const [a, b, c] = lines[i];\n    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {\n      return squares[a];\n    }\n  }\n  return null;\n}\n```\n\nExample:\n```javascript\nexport default function Game() {  const [history, setHistory] = useState([Array(9).fill(null)]);  const [currentMove, setCurrentMove] = useState(0);  const xIsNext = currentMove % 2 === 0;  const currentSquares = history[currentMove];  function handlePlay(nextSquares) {    const nextHistory = [...history.slice(0, currentMove + 1), nextSquares];    setHistory(nextHistory);    setCurrentMove(nextHistory.length - 1);  }  function jumpTo(nextMove) {    setCurrentMove(nextMove);  }  // ...}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:21:32.943Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":64,"totalLines":1144,"estimatedTokens":25691}}52