diff --git "a/react_docs_chunks.json" "b/react_docs_chunks.json" new file mode 100644--- /dev/null +++ "b/react_docs_chunks.json" @@ -0,0 +1,12537 @@ +[ + { + "content": "Your First Component\nComponents are one of the core concepts of React. They are the foundation upon which you build user interfaces (UI), which makes them the perfect place to start your React journey!\nYou will learn\nWhat a component is\nWhat role components play in a React application\nHow to write your first React component\nComponents: UI building blocks\nOn the Web, HTML lets us create rich structured documents with its built-in set of tags like

and
  • :\n

    \n
  • ", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "

    \n
  • \n

    My First Component

    1. Components: UI Building Blocks
    2. Defining a Component
    3. Using a Component
    \n

    My First Component

    1. Components: UI Building Blocks
    2. Defining a Component
    3. Using a Component
    ", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "This markup represents this article
    , its heading

    , and an (abbreviated) table of contents as an ordered list
      . Markup like this, combined with CSS for style, and JavaScript for interactivity, lies behind every sidebar, avatar, modal, dropdown\u2014every piece of UI you see on the Web.\n
      \n

      \n
        ", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "
        \n

        \n
          \nReact lets you combine your markup, CSS, and JavaScript into custom \u201ccomponents\u201d, reusable UI elements for your app. The table of contents code you saw above could be turned into a component you could render on every page. Under the hood, it still uses the same HTML tags like
          ,

          , etc.\n\n
          \n

          ", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "\n
          \n

          \nJust like with HTML tags, you can compose, order and nest components to design whole pages. For example, the documentation page you\u2019re reading is made out of React components:\n Docs ", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": " Docs ", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "As your project grows, you will notice that many of your designs can be composed by reusing components you already wrote, speeding up your development. Our table of contents above could be added to any screen with ! You can even jumpstart your project with the thousands of components shared by the React open source community like Chakra UI and Material UI.\n\nDefining a component", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "Defining a component\nTraditionally when creating web pages, web developers marked up their content and then added interaction by sprinkling on some JavaScript. This worked great when interaction was a nice-to-have on the web. Now it is expected for many sites and all apps. React puts interactivity first while still using the same technology: a React component is a JavaScript function that you can sprinkle with markup. Here\u2019s what that looks like (you can edit the example below):", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "export default function Profile() {\n return (\n \n )\n}\nAnd here\u2019s how to build a component:\nStep 1: Export the component\nThe export default prefix is a standard JavaScript syntax (not specific to React). It lets you mark the main function in a file so that you can later import it from other files. (More on importing in Importing and Exporting Components!)\nexport default\nStep 2: Define the function", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "export default\nStep 2: Define the function\nWith function Profile() { } you define a JavaScript function with the name Profile.\nfunction Profile() { }\nProfile\nPitfall\nReact components are regular JavaScript functions, but their names must start with a capital letter or they won\u2019t work!\nStep 3: Add markup", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "Step 3: Add markup\nThe component returns an tag with src and alt attributes. is written like HTML, but it is actually JavaScript under the hood! This syntax is called JSX, and it lets you embed markup inside JavaScript.\n\nsrc\nalt\n\nReturn statements can be written all on one line, as in this component:\nreturn \"Katherine;\nreturn \"Katherine;", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "return \"Katherine;\nBut if your markup isn\u2019t all on the same line as the return keyword, you must wrap it in a pair of parentheses:\nreturn\nreturn (
          \"Katherine
          );\nreturn (
          \"Katherine
          );\nPitfall\nWithout parentheses, any code on the lines after return will be ignored!\nreturn", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "Pitfall\nWithout parentheses, any code on the lines after return will be ignored!\nreturn\nUsing a component\nNow that you\u2019ve defined your Profile component, you can nest it inside other components. For example, you can export a Gallery component that uses multiple Profile components:\nProfile\nGallery\nProfile\nfunction Profile() {\n return (\n \n );\n}", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "export default function Gallery() {\n return (\n
          \n

          Amazing scientists

          \n \n \n \n
          \n );\n}\nWhat the browser sees\nNotice the difference in casing:\n
          is lowercase, so React knows we refer to an HTML tag.\n
          \n starts with a capital P, so React knows that we want to use our component called Profile.\n\nP\nProfile", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "\nP\nProfile\nAnd Profile contains even more HTML: . In the end, this is what the browser sees:\nProfile\n\n

          Amazing scientists

          \"Katherine \"Katherine \"Katherine
          ", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "

          Amazing scientists

          \"Katherine \"Katherine \"Katherine
          \nNesting and organizing components", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "Nesting and organizing components\nComponents are regular JavaScript functions, so you can keep multiple components in the same file. This is convenient when components are relatively small or tightly related to each other. If this file gets crowded, you can always move Profile to a separate file. You will learn how to do this shortly on the page about imports.\nProfile", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "Profile\nBecause the Profile components are rendered inside Gallery\u2014even several times!\u2014we can say that Gallery is a parent component, rendering each Profile as a \u201cchild\u201d. This is part of the magic of React: you can define a component once, and then use it in as many places and as many times as you like.\nProfile\nGallery\nGallery\nProfile\nPitfall\nComponents can render other components, but you must never nest their definitions:", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "Profile\nPitfall\nComponents can render other components, but you must never nest their definitions:\nexport default function Gallery() { // \ud83d\udd34 Never define a component inside another component! function Profile() { // ... } // ...}\nexport default function Gallery() { // \ud83d\udd34 Never define a component inside another component! function Profile() { // ... } // ...}\nThe snippet above is very slow and causes bugs. Instead, define every component at the top level:", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "The snippet above is very slow and causes bugs. Instead, define every component at the top level:\nexport default function Gallery() { // ...}// \u2705 Declare components at the top levelfunction Profile() { // ...}\nexport default function Gallery() { // ...}// \u2705 Declare components at the top levelfunction Profile() { // ...}\nWhen a child component needs some data from a parent, pass it by props instead of nesting definitions.", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "Your React application begins at a \u201croot\u201d component. Usually, it is created automatically when you start a new project. For example, if you use CodeSandbox or if you use the framework Next.js, the root component is defined in pages/index.js. In these examples, you\u2019ve been exporting root components.\npages/index.js", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "pages/index.js\nMost React apps use components all the way down. This means that you won\u2019t only use components for reusable pieces like buttons, but also for larger pieces like sidebars, lists, and ultimately, complete pages! Components are a handy way to organize UI code and markup, even if some of them are only used once.", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "React-based frameworks take this a step further. Instead of using an empty HTML file and letting React \u201ctake over\u201d managing the page with JavaScript, they also generate the HTML automatically from your React components. This allows your app to show some content before the JavaScript code loads.", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "Still, many websites only use React to add interactivity to existing HTML pages. They have many root components instead of a single one for the entire page. You can use as much\u2014or as little\u2014React as you need.\nRecap\nYou\u2019ve just gotten your first taste of React! Let\u2019s recap some key points.\nReact lets you create components, reusable UI elements for your app.\nReact lets you create components, reusable UI elements for your app.\nIn a React app, every piece of UI is a component.", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "In a React app, every piece of UI is a component.\nIn a React app, every piece of UI is a component.\nReact components are regular JavaScript functions except:", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "Their names always begin with a capital letter.\nThey return JSX markup.\nReact components are regular JavaScript functions except:\nTheir names always begin with a capital letter.\nThey return JSX markup.\nTry out some challenges\nThis sandbox doesn\u2019t work because the root component is not exported:\nfunction Profile() {\n return (\n \n );\n}\nTry to fix it yourself before looking at the solution!", + "title": "Your First Component \u2013 React", + "url": "https://react.dev/learn/your-first-component" + }, + { + "content": "Writing Markup with JSX\nJSX is a syntax extension for JavaScript that lets you write HTML-like markup inside a JavaScript file. Although there are other ways to write components, most React developers prefer the conciseness of JSX, and most codebases use it.\nYou will learn\nWhy React mixes markup with rendering logic\nHow JSX is different from HTML\nHow to display information with JSX\nJSX: Putting markup into JavaScript", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "How to display information with JSX\nJSX: Putting markup into JavaScript\nThe Web has been built on HTML, CSS, and JavaScript. For many years, web developers kept content in HTML, design in CSS, and logic in JavaScript\u2014often in separate files! Content was marked up inside HTML while the page\u2019s logic lived separately in JavaScript:\nHTML\nJavaScript", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "HTML\nJavaScript\nBut as the Web became more interactive, logic increasingly determined content. JavaScript was in charge of the HTML! This is why in React, rendering logic and markup live together in the same place\u2014components.\nSidebar.js React component\nSidebar.js\nForm.js React component\nForm.js", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "Sidebar.js React component\nSidebar.js\nForm.js React component\nForm.js\nKeeping a button\u2019s rendering logic and markup together ensures that they stay in sync with each other on every edit. Conversely, details that are unrelated, such as the button\u2019s markup and a sidebar\u2019s markup, are isolated from each other, making it safer to change either of them on their own.", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "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. The best way to understand this is to convert some HTML markup to JSX markup.\nNote", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "Note\nJSX and React are two separate things. They\u2019re often used together, but you can use them independently of each other. JSX is a syntax extension, while React is a JavaScript library.\nConverting HTML to JSX\nSuppose that you have some (perfectly valid) HTML:\n

          Hedy Lamarr's Todos

          \"Hedy
          • Invent new traffic lights
          • Rehearse a movie scene
          • Improve the spectrum technology
          ", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "

          Hedy Lamarr's Todos

          \"Hedy
          • Invent new traffic lights
          • Rehearse a movie scene
          • Improve the spectrum technology
          \nAnd you want to put it into your component:\nexport default function TodoList() { return ( // ??? )}\nexport default function TodoList() { return ( // ??? )}\nIf you copy and paste it as is, it will not work:\nexport default function TodoList() {\n return (", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "If you copy and paste it as is, it will not work:\nexport default function TodoList() {\n return (\n // This doesn't quite work!\n

          Hedy Lamarr's Todos

          \n \"Hedy\n
            \n
          • Invent new traffic lights\n
          • Rehearse a movie scene\n
          • Improve the spectrum technology\n
          ", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "
        1. Rehearse a movie scene\n
        2. Improve the spectrum technology\n \nThis is because JSX is stricter and has a few more rules than HTML! If you read the error messages above, they\u2019ll guide you to fix the markup, or you can follow the guide below.\nNote\nMost of the time, React\u2019s on-screen error messages will help you find where the problem is. Give them a read if you get stuck!\nThe Rules of JSX\n1. Return a single root element", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "The Rules of JSX\n1. Return a single root element\nTo return multiple elements from a component, wrap them with a single parent tag.\nFor example, you can use a
          :\n
          \n

          Hedy Lamarr's Todos

          \"Hedy
            ...
          \n

          Hedy Lamarr's Todos

          \"Hedy
            ...
          ", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "If you don\u2019t want to add an extra
          to your markup, you can write <> and instead:\n
          \n<>\n\n<>

          Hedy Lamarr's Todos

          \"Hedy
            ...
          \n<>

          Hedy Lamarr's Todos

          \"Hedy
            ...
          ", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "This empty tag is called a Fragment. Fragments let you group things without leaving any trace in the browser HTML tree.\nJSX looks like HTML, but under the hood it is transformed into plain JavaScript objects. You can\u2019t return two objects from a function without wrapping them into an array. This explains why you also can\u2019t return two JSX tags without wrapping them into another tag or a Fragment.\n2. Close all the tags", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "2. Close all the tags\nJSX requires tags to be explicitly closed: self-closing tags like must become , and wrapping tags like
        3. oranges must be written as
        4. oranges
        5. .\n\n\n
        6. oranges\n
        7. oranges
        8. \nThis is how Hedy Lamarr\u2019s image and list items look closed:", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "\n
        9. oranges\n
        10. oranges
        11. \nThis is how Hedy Lamarr\u2019s image and list items look closed:\n<> \"Hedy
          • Invent new traffic lights
          • Rehearse a movie scene
          • Improve the spectrum technology
          ", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "<> \"Hedy
          • Invent new traffic lights
          • Rehearse a movie scene
          • Improve the spectrum technology
          \n3. camelCase all most of the things!", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "3. camelCase all most of the things!\nJSX turns into JavaScript and attributes written in JSX become keys of JavaScript objects. In your own components, you will often want to read those attributes into variables. But JavaScript has limitations on variable names. For example, their names can\u2019t contain dashes or be reserved words like class.\nclass", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "class\nThis is why, in React, many HTML and SVG attributes are written in camelCase. For example, instead of stroke-width you use strokeWidth. Since class is a reserved word, in React you write className instead, named after the corresponding DOM property:\nstroke-width\nstrokeWidth\nclass\nclassName\n\"Hedy\n\"Hedy", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "\"Hedy\nYou can find all these attributes in the list of DOM component props. If you get one wrong, don\u2019t worry\u2014React will print a message with a possible correction to the browser console.\nPitfall\nFor historical reasons, aria-* and data-* attributes are written as in HTML with dashes.\naria-*\ndata-*\nPro-tip: Use a JSX Converter", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "aria-*\ndata-*\nPro-tip: Use a JSX Converter\nConverting all these attributes in existing markup can be tedious! We recommend using a converter to translate your existing HTML and SVG to JSX. Converters are very useful in practice, but it\u2019s still worth understanding what is going on so that you can comfortably write JSX on your own.\nHere is your final result:\nexport default function TodoList() {\n return (\n <>\n

          Hedy Lamarr's Todos

          \n \n

          Hedy Lamarr's Todos

          \n \"Hedy\n
            \n
          • Invent new traffic lights
          • \n
          • Rehearse a movie scene
          • \n
          • Improve the spectrum technology
          • \n
          \n \n );\n}\nRecap\nNow you know why JSX exists and how to use it in components:\nReact components group rendering logic together with markup because they are related.", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "React components group rendering logic together with markup because they are related.\nJSX is similar to HTML, with a few differences. You can use a converter if you need to.\nError messages will often point you in the right direction to fixing your markup.\nTry out some challenges\nThis HTML was pasted into a component, but it\u2019s not valid JSX. Fix it:\nexport default function Bio() {\n return (\n
          \n

          Welcome to my website!

          \n
          \n

          ", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "

          \n

          Welcome to my website!

          \n
          \n

          \n You can find my thoughts here.\n

          \n And pictures of scientists!\n

          \n );\n}\nWhether to do it by hand or using the converter is up to you!", + "title": "Writing Markup with JSX \u2013 React", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "content": "Keeping Components Pure\nSome 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.\nYou will learn\nWhat purity is and how it helps you avoid bugs\nHow to keep components pure by keeping changes out of the render phase", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "How to keep components pure by keeping changes out of the render phase\nHow to use Strict Mode to find mistakes in your components\nPurity: Components as formulas\nIn computer science (and especially the world of functional programming), a pure function is a function with the following characteristics:\nIt minds its own business. It does not change any objects or variables that existed before it was called.", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "Same inputs, same output. Given the same inputs, a pure function should always return the same result.\nYou might already be familiar with one example of pure functions: formulas in math.\nConsider this math formula: y = 2x.\nIf x = 2 then y = 4. Always.\nIf x = 3 then y = 6. Always.\nIf x = 3, y won\u2019t sometimes be 9 or \u20131 or 2.5 depending on the time of day or the state of the stock market.\nIf y = 2x and x = 3, y will always be 6.\nIf we made this into a JavaScript function, it would look like this:", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "If we made this into a JavaScript function, it would look like this:\nfunction double(number) { return 2 * number;}\nfunction double(number) { return 2 * number;}\nIn the above example, double is a pure function. If you pass it 3, it will return 6. Always.\ndouble\n3\n6\nReact 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 inputs:", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "function Recipe({ drinkers }) {\n return (\n
            \n
          1. Boil {drinkers} cups of water.
          2. \n
          3. Add {drinkers} spoons of tea and {0.5 * drinkers} spoons of spice.
          4. \n
          5. Add {0.5 * drinkers} cups of milk to boil and sugar to taste.
          6. \n
          \n );\n}", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "export default function App() {\n return (\n
          \n

          Spiced Chai Recipe

          \n

          For two

          \n \n

          For a gathering

          \n \n
          \n );\n}\nWhen you pass drinkers={2} to Recipe, it will return JSX containing 2 cups of water. Always.\ndrinkers={2}\nRecipe\n2 cups of water\nIf you pass drinkers={4}, it will return JSX containing 4 cups of water. Always.\ndrinkers={4}\n4 cups of water\nJust like a math formula.", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "drinkers={4}\n4 cups of water\nJust like a math formula.\nYou could think of your components as recipes: if you follow them and don\u2019t introduce new ingredients during the cooking process, you will get the same dish every time. That \u201cdish\u201d is the JSX that the component serves to React to render.\nIllustrated by Rachel Lee Nabors\nSide Effects: (un)intended consequences", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "Illustrated by Rachel Lee Nabors\nSide Effects: (un)intended consequences\nReact\u2019s rendering process must always be pure. Components should only return their JSX, and not change any objects or variables that existed before rendering\u2014that would make them impure!\nHere is a component that breaks this rule:\nlet guest = 0;", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "function Cup() {\n // Bad: changing a preexisting variable!\n guest = guest + 1;\n return

          Tea cup for guest #{guest}

          ;\n}", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "export default function TeaSet() {\n return (\n <>\n \n \n \n \n );\n}\nThis 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\u2019s more, if other components read guest, they will produce different JSX, too, depending on when they were rendered! That\u2019s not predictable.\nguest\nguest", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "guest\nguest\nGoing 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\u2014you can see how this would lead to confusing bugs!\nYou can fix this component by passing guest as a prop instead:\nguest\nfunction Cup({ guest }) {\n return

          Tea cup for guest #{guest}

          ;\n}", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "export default function TeaSet() {\n return (\n <>\n \n \n \n \n );\n}\nNow your component is pure, as the JSX it returns only depends on the guest prop.\nguest", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "guest\nIn general, you should not expect your components to be rendered in any particular order. It doesn\u2019t matter if you call y = 2x before or after y = 5x: both formulas will resolve independently of each other. In the same way, each component should only \u201cthink for itself\u201d, and not attempt to coordinate with or depend upon others during rendering. Rendering is like a school exam: each component should calculate JSX on their own!", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "Although you might not have used them all yet, in React there are three kinds of inputs that you can read while rendering: props, state, and context. You should always treat these inputs as read-only.\nWhen 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.", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "React offers a \u201cStrict Mode\u201d in which it calls each component\u2019s function twice during development. By calling the component functions twice, Strict Mode helps find components that break these rules.", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "Notice how the original example displayed \u201cGuest #2\u201d, \u201cGuest #4\u201d, and \u201cGuest #6\u201d instead of \u201cGuest #1\u201d, \u201cGuest #2\u201d, and \u201cGuest #3\u201d. The original function was impure, so calling it twice broke it. But the fixed pure version works even if the function is called twice every time. Pure functions only calculate, so calling them twice won\u2019t change anything\u2014just like calling double(2) twice doesn\u2019t change what\u2019s returned, and solving y = 2x twice doesn\u2019t change what y is. Same inputs, same outputs.", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "what\u2019s returned, and solving y = 2x twice doesn\u2019t change what y is. Same inputs, same outputs. Always.", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "double(2)\nStrict Mode has no effect in production, so it won\u2019t slow down the app for your users. To opt into Strict Mode, you can wrap your root component into . Some frameworks do this by default.\n\nLocal mutation: Your component\u2019s little secret", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "\nLocal mutation: Your component\u2019s little secret\nIn the above example, the problem was that the component changed a preexisting variable while rendering. This is often called a \u201cmutation\u201d to make it sound a bit scarier. Pure functions don\u2019t mutate variables outside of the function\u2019s scope or objects that were created before the call\u2014that makes them impure!", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "However, it\u2019s completely fine to change variables and objects that you\u2019ve just created while rendering. In this example, you create an [] array, assign it to a cups variable, and then push a dozen cups into it:\n[]\ncups\npush\nfunction Cup({ guest }) {\n return

          Tea cup for guest #{guest}

          ;\n}", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "export default function TeaGathering() {\n const cups = [];\n for (let i = 1; i <= 12; i++) {\n cups.push();\n }\n return cups;\n}\nIf 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.\ncups\n[]\nTeaGathering", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "cups\n[]\nTeaGathering\nHowever, it\u2019s fine because you\u2019ve created them during the same render, inside TeaGathering. No code outside of TeaGathering will ever know that this happened. This is called \u201clocal mutation\u201d\u2014it\u2019s like your component\u2019s little secret.\nTeaGathering\nTeaGathering\nWhere you can cause side effects", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "TeaGathering\nTeaGathering\nWhere you can cause side effects\nWhile functional programming relies heavily on purity, at some point, somewhere, something has to change. That\u2019s kind of the point of programming! These changes\u2014updating the screen, starting an animation, changing the data\u2014are called side effects. They\u2019re things that happen \u201con the side\u201d, not during rendering.", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "In React, side effects usually belong inside event handlers. Event handlers are functions that React runs when you perform some action\u2014for example, when you click a button. Even though event handlers are defined inside your component, they don\u2019t run during rendering! So event handlers don\u2019t need to be pure.", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "If you\u2019ve exhausted all other options and can\u2019t 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.\nuseEffect\nWhen possible, try to express your logic with rendering alone. You\u2019ll be surprised how far this can take you!", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "Writing pure functions takes some habit and discipline. But it also unlocks marvelous opportunities:\nYour components could run in a different environment\u2014for example, on the server! Since they return the same result for the same inputs, one component can serve many user requests.\nYou 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.", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "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.\nEvery new React feature we\u2019re building takes advantage of purity. From data fetching to animations to performance, keeping components pure unlocks the power of the React paradigm.\nRecap\nA component must be pure, meaning:", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "It minds its own business. It should not change any objects or variables that existed before rendering.\nSame inputs, same output. Given the same inputs, a component should always return the same JSX.\nIt minds its own business. It should not change any objects or variables that existed before rendering.\nSame inputs, same output. Given the same inputs, a component should always return the same JSX.", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "Same inputs, same output. Given the same inputs, a component should always return the same JSX.\nRendering can happen at any time, so components should not depend on each others\u2019 rendering sequence.\nYou should not mutate any of the inputs that your components use for rendering. That includes props, state, and context. To update the screen, \u201cset\u201d state instead of mutating preexisting objects.", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "Strive to express your component\u2019s logic in the JSX you return. When you need to \u201cchange things\u201d, you\u2019ll usually want to do it in an event handler. As a last resort, you can useEffect.\nuseEffect\nWriting pure functions takes a bit of practice, but it unlocks the power of React\u2019s paradigm.\nTry out some challenges", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "Try out some challenges\nThis component tries to set the

          \u2019s CSS class to \"night\" during the time from midnight to six hours in the morning, and \"day\" at all other times. However, it doesn\u2019t work. Can you fix this component?\n

          \n\"night\"\n\"day\"\nYou can verify whether your solution works by temporarily changing the computer\u2019s timezone. When the current time is between midnight and six in the morning, the clock should have inverted colors!\nexport default function Clock({ time }) {", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "export 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

          \n {time.toLocaleTimeString()}\n

          \n );\n}", + "title": "Keeping Components Pure \u2013 React", + "url": "https://react.dev/learn/keeping-components-pure" + }, + { + "content": "Reusing Logic with Custom Hooks\nReact comes with several built-in Hooks like useState, useContext, and useEffect. Sometimes, you\u2019ll wish that there was a Hook for some more specific purpose: for 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\u2019s needs.\nuseState\nuseContext\nuseEffect\nYou will learn\nWhat custom Hooks are, and how to write your own", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "useState\nuseContext\nuseEffect\nYou will learn\nWhat custom Hooks are, and how to write your own\nHow to reuse logic between components\nHow to name and structure your custom Hooks\nWhen and why to extract custom Hooks\nCustom Hooks: Sharing logic between components", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "When and why to extract custom Hooks\nCustom Hooks: Sharing logic between components\nImagine you\u2019re 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\u2019ll need two things in your component:\nA piece of state that tracks whether the network is online.", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "A piece of state that tracks whether the network is online.\nAn Effect that subscribes to the global online and offline events, and updates that state.\nonline\noffline\nThis will keep your component synchronized with the network status. You might start with something like this:\nimport { useState, useEffect } from 'react';", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export 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 }, []);", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "return

          {isOnline ? '\u2705 Online' : '\u274c Disconnected'}

          ;\n}\nTry turning your network on and off, and notice how this StatusBar updates in response to your actions.\nStatusBar\nNow 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 \u201cReconnecting\u2026\u201d instead of \u201cSave\u201d while the network is off.\nTo start, you can copy and paste the isOnline state and the Effect into SaveButton:\nisOnline\nSaveButton", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "isOnline\nSaveButton\nimport { useState, useEffect } from 'react';", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export 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 }, []);", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "function handleSaveClick() {\n console.log('\u2705 Progress saved');\n }", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "return (\n \n );\n}\nVerify that, if you turn off the network, the button will change its appearance.\nThese 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.\nExtracting your own custom Hook from a component", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "Extracting your own custom Hook from a component\nImagine 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 them:\nuseState\nuseEffect\nuseOnlineStatus", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "useState\nuseEffect\nuseOnlineStatus\nfunction StatusBar() { const isOnline = useOnlineStatus(); return

          {isOnline ? '\u2705 Online' : '\u274c Disconnected'}

          ;}function SaveButton() { const isOnline = useOnlineStatus(); function handleSaveClick() { console.log('\u2705 Progress saved'); } return ( );}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "function StatusBar() { const isOnline = useOnlineStatus(); return

          {isOnline ? '\u2705 Online' : '\u274c Disconnected'}

          ;}function SaveButton() { const isOnline = useOnlineStatus(); function handleSaveClick() { console.log('\u2705 Progress saved'); } return ( );}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "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 earlier:\nuseOnlineStatus", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "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;}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "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;}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "At the end of the function, return isOnline. This lets your components read that value:\nisOnline\nimport { useOnlineStatus } from './useOnlineStatus.js';", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "function StatusBar() {\n const isOnline = useOnlineStatus();\n return

          {isOnline ? '\u2705 Online' : '\u274c Disconnected'}

          ;\n}\n\nfunction SaveButton() {\n const isOnline = useOnlineStatus();\n\n function handleSaveClick() {\n console.log('\u2705 Progress saved');\n }\n\n return (\n \n );\n}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export default function App() {\n return (\n <>\n \n \n \n );\n}\nVerify that switching the network on and off updates both components.\nNow your components don\u2019t 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).", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "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.\nHook names always start with use\nuse\nReact applications are built from components. Components are built from Hooks, whether built-in or custom. You\u2019ll likely often use custom Hooks created by others, but occasionally you might write one yourself!\nYou must follow these naming conventions:", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "You must follow these naming conventions:\nReact 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.\nStatusBar\nSaveButton\nHook 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.\nuse\nuseState\nuseOnlineStatus", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "use\nuseState\nuseOnlineStatus\nThis convention guarantees that you can always look at a component and know where its state, Effects, and other React features might \u201chide\u201d. For example, if you see a getColor() function call inside your component, you can be sure that it can\u2019t possibly contain React state inside because its name doesn\u2019t start with use. However, a function call like useOnlineStatus() will most likely contain calls to other Hooks inside!\ngetColor()\nuse\nuseOnlineStatus()\nNote", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "getColor()\nuse\nuseOnlineStatus()\nNote\nIf 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\u2019t allow you to call useState or useEffect inside of it anymore. Only Hooks and components can call other Hooks!\nuseOnlineStatus\ngetOnlineStatus\nuseState\nuseEffect\nNo. Functions that don\u2019t call Hooks don\u2019t need to be Hooks.", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "getOnlineStatus\nuseState\nuseEffect\nNo. Functions that don\u2019t call Hooks don\u2019t need to be Hooks.\nIf your function doesn\u2019t call any Hooks, avoid the use prefix. Instead, write it as a regular function without the use prefix. For example, useSorted below doesn\u2019t call Hooks, so call it getSorted instead:\nuse\nuse\nuseSorted\ngetSorted", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "use\nuse\nuseSorted\ngetSorted\n// \ud83d\udd34 Avoid: A Hook that doesn't use Hooksfunction useSorted(items) { return items.slice().sort();}// \u2705 Good: A regular function that doesn't use Hooksfunction getSorted(items) { return items.slice().sort();}\n// \ud83d\udd34 Avoid: A Hook that doesn't use Hooksfunction useSorted(items) { return items.slice().sort();}// \u2705 Good: A regular function that doesn't use Hooksfunction getSorted(items) { return items.slice().sort();}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "This ensures that your code can call this regular function anywhere, including conditions:\nfunction List({ items, shouldSort }) { let displayedItems = items; if (shouldSort) { // \u2705 It's ok to call getSorted() conditionally because it's not a Hook displayedItems = getSorted(items); } // ...}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "function List({ items, shouldSort }) { let displayedItems = items; if (shouldSort) { // \u2705 It's ok to call getSorted() conditionally because it's not a Hook displayedItems = getSorted(items); } // ...}\nYou should give use prefix to a function (and thus make it a Hook) if it uses at least one Hook inside of it:\nuse\n// \u2705 Good: A Hook that uses other Hooksfunction useAuth() { return useContext(Auth);}\n// \u2705 Good: A Hook that uses other Hooksfunction useAuth() { return useContext(Auth);}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "// \u2705 Good: A Hook that uses other Hooksfunction useAuth() { return useContext(Auth);}\nTechnically, this isn\u2019t enforced by React. In principle, you could make a Hook that doesn\u2019t call other Hooks. This is often confusing and limiting so it\u2019s best to avoid that pattern. However, there may be rare cases where it is helpful. For example, maybe your function doesn\u2019t 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:", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "use\n// \u2705 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// \u2705 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;}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "Then components won\u2019t be able to call it conditionally. This will become important when you actually add Hook calls inside. If you don\u2019t plan to use Hooks inside it (now or later), don\u2019t make it a Hook.\nCustom Hooks let you share stateful logic, not state itself\nIn the earlier example, when you turned the network on and off, both components updated together. However, it\u2019s wrong to think that a single isOnline state variable is shared between them. Look at this code:\nisOnline", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "isOnline\nfunction StatusBar() { const isOnline = useOnlineStatus(); // ...}function SaveButton() { const isOnline = useOnlineStatus(); // ...}\nfunction StatusBar() { const isOnline = useOnlineStatus(); // ...}function SaveButton() { const isOnline = useOnlineStatus(); // ...}\nIt works the same way as before you extracted the duplication:", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "It works the same way as before you extracted the duplication:\nfunction StatusBar() { const [isOnline, setIsOnline] = useState(true); useEffect(() => { // ... }, []); // ...}function SaveButton() { const [isOnline, setIsOnline] = useState(true); useEffect(() => { // ... }, []); // ...}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "function StatusBar() { const [isOnline, setIsOnline] = useState(true); useEffect(() => { // ... }, []); // ...}function SaveButton() { const [isOnline, setIsOnline] = useState(true); useEffect(() => { // ... }, []); // ...}\nThese 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).", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "To better illustrate this, we\u2019ll need a different example. Consider this Form component:\nForm\nimport { useState } from 'react';", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export 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 }", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "return (\n <>\n \n \n

          Good morning, {firstName} {lastName}.

          \n \n );\n}\nThere\u2019s some repetitive logic for each form field:\nThere\u2019s a piece of state (firstName and lastName).\nfirstName\nlastName", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "There\u2019s a piece of state (firstName and lastName).\nfirstName\nlastName\nThere\u2019s a change handler (handleFirstNameChange and handleLastNameChange).\nhandleFirstNameChange\nhandleLastNameChange\nThere\u2019s a piece of JSX that specifies the value and onChange attributes for that input.\nvalue\nonChange\nYou can extract the repetitive logic into this useFormInput custom Hook:\nuseFormInput\nimport { useState } from 'react';", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export 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 };", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "return inputProps;\n}\nNotice that it only declares one state variable called value.\nvalue\nHowever, the Form component calls useFormInput two times:\nForm\nuseFormInput\nfunction Form() { const firstNameProps = useFormInput('Mary'); const lastNameProps = useFormInput('Poppins'); // ...\nfunction Form() { const firstNameProps = useFormInput('Mary'); const lastNameProps = useFormInput('Poppins'); // ...\nThis is why it works like declaring two separate state variables!", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "This is why it works like declaring two separate state variables!\nCustom 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\u2019d like, scroll back up and compare them. The behavior before and after extracting a custom Hook is identical.", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "When you need to share the state itself between multiple components, lift it up and pass it down instead.\nPassing reactive values between Hooks\nThe 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\u2019 code as part of your component\u2019s body!", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "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 room:\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';\nimport { showNotification } from './notifications.js';", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export 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]);", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "return (\n <>\n \n

          Welcome to the {roomId} room!

          \n \n );\n}\nWhen you change serverUrl or roomId, the Effect \u201creacts\u201d 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\u2019s dependencies.\nserverUrl\nroomId\nNow move the Effect\u2019s code into a custom Hook:", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "serverUrl\nroomId\nNow move the Effect\u2019s code into a custom Hook:\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]);}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export 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]);}\nThis lets your ChatRoom component call your custom Hook without worrying about how it works inside:\nChatRoom", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "ChatRoom\nexport default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useChatRoom({ roomId: roomId, serverUrl: serverUrl }); return ( <>

          Welcome to the {roomId} room!

          );}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useChatRoom({ roomId: roomId, serverUrl: serverUrl }); return ( <>

          Welcome to the {roomId} room!

          );}\nThis looks much simpler! (But it does the same thing.)", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "This looks much simpler! (But it does the same thing.)\nNotice that the logic still responds to prop and state changes. Try editing the server URL or the selected room:\nimport { useState } from 'react';\nimport { useChatRoom } from './useChatRoom.js';", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export default function ChatRoom({ roomId }) {\n const [serverUrl, setServerUrl] = useState('https://localhost:1234');\n\n useChatRoom({\n roomId: roomId,\n serverUrl: serverUrl\n });", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "return (\n <>\n \n

          Welcome to the {roomId} room!

          \n \n );\n}\nNotice how you\u2019re taking the return value of one Hook:\nexport default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useChatRoom({ roomId: roomId, serverUrl: serverUrl }); // ...", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useChatRoom({ roomId: roomId, serverUrl: serverUrl }); // ...\nand passing it as an input to another Hook:\nexport default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useChatRoom({ roomId: roomId, serverUrl: serverUrl }); // ...", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useChatRoom({ roomId: roomId, serverUrl: serverUrl }); // ...", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "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\u2019s as if the output of useState \u201cfeeds into\u201d the input of the useChatRoom.)\nChatRoom\nroomId\nserverUrl\nuseState\nuseChatRoom", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "ChatRoom\nroomId\nserverUrl\nuseState\nuseChatRoom\nPassing event handlers to custom Hooks\nUnder Construction\nThis section describes an experimental API that has not yet been released in a stable version of React.\nAs 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 Hook:\nuseChatRoom", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "useChatRoom\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]);}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export 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]);}\nLet\u2019s say you want to move this logic back to your component:", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "Let\u2019s say you want to move this logic back to your component:\nexport default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useChatRoom({ roomId: roomId, serverUrl: serverUrl, onReceiveMessage(msg) { showNotification('New message: ' + msg); } }); // ...", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useChatRoom({ roomId: roomId, serverUrl: serverUrl, onReceiveMessage(msg) { showNotification('New message: ' + msg); } }); // ...\nTo make this work, change your custom Hook to take onReceiveMessage as one of its named options:\nonReceiveMessage", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "onReceiveMessage\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]); // \u2705 All dependencies declared}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export 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]); // \u2705 All dependencies declared}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "This will work, but there\u2019s one more improvement you can do when your custom Hook accepts event handlers.\nAdding 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 dependencies:\nonReceiveMessage", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "import { 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]); // \u2705 All", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "onMessage(msg); }); return () => connection.disconnect(); }, [roomId, serverUrl]); // \u2705 All dependencies declared}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "import { 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]); // \u2705 All", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "onMessage(msg); }); return () => connection.disconnect(); }, [roomId, serverUrl]); // \u2705 All dependencies declared}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "Now the chat won\u2019t 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 with:\nChatRoom\nimport { useState } from 'react';\nimport { useChatRoom } from './useChatRoom.js';\nimport { showNotification } from './notifications.js';", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export 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 });", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "return (\n <>\n \n

          Welcome to the {roomId} room!

          \n \n );\n}\nNotice 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\u2019s the power of custom Hooks.\nuseChatRoom\nWhen to use custom Hooks", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "useChatRoom\nWhen to use custom Hooks\nYou don\u2019t 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.\nuseFormInput\nuseState", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "useFormInput\nuseState\nHowever, whenever you write an Effect, consider whether it would be clearer to also wrap it in a custom Hook. You shouldn\u2019t need Effects very often, so if you\u2019re writing one, it means that you need to \u201cstep outside React\u201d to synchronize with some external system or to do something that React doesn\u2019t 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.", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "For example, consider a ShippingForm component that displays two dropdowns: one 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 this:\nShippingForm", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "function 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", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "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]); // ...", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "function 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", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "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]); // ...", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "Although this code is quite repetitive, it\u2019s correct to keep these Effects separate from each other. They synchronize two different things, so you shouldn\u2019t merge them into one Effect. Instead, you can simplify the ShippingForm component above by extracting the common logic between them into your own useData Hook:\nShippingForm\nuseData", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "ShippingForm\nuseData\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;}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "function 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;}\nNow you can replace both Effects in the ShippingForm components with calls to useData:\nShippingForm\nuseData", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "ShippingForm\nuseData\nfunction ShippingForm({ country }) { const cities = useData(`/api/cities?country=${country}`); const [city, setCity] = useState(null); const areas = useData(city ? `/api/areas?city=${city}` : null); // ...\nfunction ShippingForm({ country }) { const cities = useData(`/api/cities?country=${country}`); const [city, setCity] = useState(null); const areas = useData(city ? `/api/areas?city=${city}` : null); // ...", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "Extracting a custom Hook makes the data flow explicit. You feed the url in and you get the data out. By \u201chiding\u201d 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\u2019s Effects will be in custom Hooks.\nurl\ndata\nuseData\nShippingForm", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "url\ndata\nuseData\nShippingForm\nStart by choosing your custom Hook\u2019s name. If you struggle to pick a clear name, it might mean that your Effect is too coupled to the rest of your component\u2019s logic, and is not yet ready to be extracted.\nIdeally, your custom Hook\u2019s name should be clear enough that even a person who doesn\u2019t write code often could have a good guess about what your custom Hook does, what it takes, and what it returns:\n\u2705 useData(url)\nuseData(url)", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "\u2705 useData(url)\nuseData(url)\n\u2705 useImpressionLog(eventName, extraData)\nuseImpressionLog(eventName, extraData)\n\u2705 useChatRoom(options)\nuseChatRoom(options)\nWhen you synchronize with an external system, your custom Hook name may be more technical and use jargon specific to that system. It\u2019s good as long as it would be clear to a person familiar with that system:\n\u2705 useMediaQuery(query)\nuseMediaQuery(query)\n\u2705 useSocket(url)\nuseSocket(url)\n\u2705 useIntersectionObserver(ref, options)", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "useMediaQuery(query)\n\u2705 useSocket(url)\nuseSocket(url)\n\u2705 useIntersectionObserver(ref, options)\nuseIntersectionObserver(ref, options)\nKeep custom Hooks focused on concrete high-level use cases. Avoid creating and using custom \u201clifecycle\u201d Hooks that act as alternatives and convenience wrappers for the useEffect API itself:\nuseEffect\n\ud83d\udd34 useMount(fn)\nuseMount(fn)\n\ud83d\udd34 useEffectOnce(fn)\nuseEffectOnce(fn)\n\ud83d\udd34 useUpdateEffect(fn)\nuseUpdateEffect(fn)", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "useMount(fn)\n\ud83d\udd34 useEffectOnce(fn)\nuseEffectOnce(fn)\n\ud83d\udd34 useUpdateEffect(fn)\nuseUpdateEffect(fn)\nFor example, this useMount Hook tries to ensure some code only runs \u201con mount\u201d:\nuseMount", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "useMount\nfunction ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // \ud83d\udd34 Avoid: using custom \"lifecycle\" Hooks useMount(() => { const connection = createConnection({ roomId, serverUrl }); connection.connect(); post('/analytics/event', { eventName: 'visit_chat' }); }); // ...}// \ud83d\udd34 Avoid: creating custom \"lifecycle\" Hooksfunction useMount(fn) { useEffect(() => { fn(); }, []); // \ud83d\udd34 React Hook useEffect has a missing dependency: 'fn'}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // \ud83d\udd34 Avoid: using custom \"lifecycle\" Hooks useMount(() => { const connection = createConnection({ roomId, serverUrl }); connection.connect(); post('/analytics/event', { eventName: 'visit_chat' }); }); // ...}// \ud83d\udd34 Avoid: creating custom \"lifecycle\" Hooksfunction useMount(fn) { useEffect(() => { fn(); }, []); // \ud83d\udd34 React Hook useEffect has a missing dependency: 'fn'}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "Custom \u201clifecycle\u201d Hooks like useMount don\u2019t fit well into the React paradigm. For example, this code example has a mistake (it doesn\u2019t \u201creact\u201d to roomId or serverUrl changes), but the linter won\u2019t warn you about it because the linter only checks direct useEffect calls. It won\u2019t know about your Hook.\nuseMount\nroomId\nserverUrl\nuseEffect\nIf you\u2019re writing an Effect, start by using the React API directly:", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // \u2705 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]); // ...}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // \u2705 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]); // ...}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "Then, you can (but don\u2019t have to) extract custom Hooks for different high-level use cases:\nfunction ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // \u2705 Great: custom Hooks named after their purpose useChatRoom({ serverUrl, roomId }); useImpressionLog('visit_chat', { roomId }); // ...}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // \u2705 Great: custom Hooks named after their purpose useChatRoom({ serverUrl, roomId }); useImpressionLog('visit_chat', { roomId }); // ...}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "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\u2019t constrain the use cases and is very abstract, in the long run it\u2019s likely to introduce more problems than it solves.\nuseChatRoom(options)\nuseImpressionLog(eventName, extraData)", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "useChatRoom(options)\nuseImpressionLog(eventName, extraData)\nCustom Hooks help you migrate to better patterns", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "Custom Hooks help you migrate to better patterns\nEffects are an \u201cescape hatch\u201d: you use them when you need to \u201cstep outside React\u201d and when there is no better built-in solution for your use case. With time, the React team\u2019s 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.", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "Let\u2019s return to this example:\nimport { useState, useEffect } from 'react';", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export 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 }, []);", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "window.removeEventListener('offline', handleOffline);\n };\n }, []);\n return isOnline;\n}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "In the above example, useOnlineStatus is implemented with a pair of useState and useEffect. However, this isn\u2019t the best possible solution. There is a number of edge cases it doesn\u2019t 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", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "but using it directly would not work on the server for generating the initial HTML. In short, this code could be improved.", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "useOnlineStatus\nuseState\nuseEffect\nisOnline\ntrue\nnavigator.onLine\nReact 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 API:\nuseSyncExternalStore\nuseOnlineStatus\nimport { useSyncExternalStore } from 'react';", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "function 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}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export 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}\nNotice how you didn\u2019t need to change any of the components to make this migration:\nfunction StatusBar() { const isOnline = useOnlineStatus(); // ...}function SaveButton() { const isOnline = useOnlineStatus(); // ...}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "function StatusBar() { const isOnline = useOnlineStatus(); // ...}function SaveButton() { const isOnline = useOnlineStatus(); // ...}\nThis is another reason for why wrapping Effects in custom Hooks is often beneficial:\nYou make the data flow to and from your Effects very explicit.\nYou let your components focus on the intent rather than on the exact implementation of your Effects.\nWhen React adds new features, you can remove those Effects without changing any of your components.", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "When React adds new features, you can remove those Effects without changing any of your components.\nSimilar to a design system, you might find it helpful to start extracting common idioms from your app\u2019s components into custom Hooks. This will keep your components\u2019 code focused on the intent, and let you avoid writing raw Effects very often. Many excellent custom Hooks are maintained by the React community.", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "We\u2019re still working out the details, but we expect that in the future, you\u2019ll write data fetching like this:\nimport { use } from 'react'; // Not available yet!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; // ...", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "import { use } from 'react'; // Not available yet!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; // ...", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "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.\nuseData\nThere is more than one way to do it", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "useData\nThere is more than one way to do it\nLet\u2019s 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 this:\nrequestAnimationFrame\n1\nimport { useState, useEffect, useRef } from 'react';", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "function 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 }", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "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

          \n Welcome\n

          \n );\n}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export default function App() {\n const [show, setShow] = useState(false);\n return (\n <>\n \n
          \n {show && }\n \n );\n}\nTo make the component more readable, you might extract the logic into a useFadeIn custom Hook:\nuseFadeIn\nimport { useState, useEffect, useRef } from 'react';\nimport { useFadeIn } from './useFadeIn.js';\n\nfunction Welcome() {\n const ref = useRef(null);", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "function Welcome() {\n const ref = useRef(null);\n\n useFadeIn(ref, 1000);\n\n return (\n

          \n Welcome\n

          \n );\n}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export default function App() {\n const [show, setShow] = useState(false);\n return (\n <>\n \n
          \n {show && }\n \n );\n}\nYou 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 Hook:\nuseFadeIn\nuseFadeIn\nuseAnimationLoop", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "useFadeIn\nuseFadeIn\nuseAnimationLoop\nimport { useState, useEffect } from 'react';\nimport { experimental_useEffectEvent as useEffectEvent } from 'react';", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export 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 }", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "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 }", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "tick();\n return () => cancelAnimationFrame(frameId);\n }, [isRunning]);\n}\nHowever, you didn\u2019t 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 class:\nimport { useState, useEffect } from 'react';\nimport { FadeInAnimation } from './animation.js';", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export 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}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "animation.stop();\n };\n }, [ref, duration]);\n}\nEffects 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 \u201cexternal system\u201d. This lets your Effects stay simple because they only need to send messages to the system you\u2019ve moved outside React.", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "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 Animation:\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%);", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "animation: fadeIn 1000ms;\n}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "@keyframes fadeIn {\n 0% { opacity: 0; }\n 100% { opacity: 1; }\n}\nSometimes, you don\u2019t even need a Hook!\nRecap\nCustom Hooks let you share logic between components.\nCustom Hooks must be named starting with use followed by a capital letter.\nuse\nCustom Hooks only share stateful logic, not state itself.\nYou can pass reactive values from one Hook to another, and they stay up-to-date.\nAll Hooks re-run every time your component re-renders.", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "All Hooks re-run every time your component re-renders.\nThe code of your custom Hooks should be pure, like your component\u2019s code.\nWrap event handlers received by custom Hooks into Effect Events.\nDon\u2019t create custom Hooks like useMount. Keep their purpose specific.\nuseMount\nIt\u2019s up to you how and where to choose the boundaries of your code.\nTry out some challenges\nuseCounter\nuseInterval\nuseCounter\nuseCounter", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "Try out some challenges\nuseCounter\nuseInterval\nuseCounter\nuseCounter\nThis 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 this:\nuseCounter\nCounter\nexport default function Counter() { const count = useCounter(); return

          Seconds passed: {count}

          ;}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export default function Counter() { const count = useCounter(); return

          Seconds passed: {count}

          ;}\nYou\u2019ll need to write your custom Hook in useCounter.js and import it into the App.js file.\nuseCounter.js\nApp.js\nimport { useState, useEffect } from 'react';", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "export 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

          Seconds passed: {count}

          ;\n}", + "title": "Reusing Logic with Custom Hooks \u2013 React", + "url": "https://react.dev/learn/reusing-logic-with-custom-hooks" + }, + { + "content": "Thinking in React\nReact can change how you think about the designs you look at and the apps you build. When you build a user interface with React, you will first break it apart into pieces called components. Then, you will describe the different visual states for each of your components. Finally, you will connect your components together so that the data flows through them. In this tutorial, we\u2019ll guide you through the thought process of building a searchable product data table with React.", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "Start with the mockup\nImagine that you already have a JSON API and a mockup from a designer.\nThe JSON API returns some data that looks like this:", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "The JSON API returns some data that looks like this:\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\" }]", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "[ { 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\" }]\nThe mockup looks like this:", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "The mockup looks like this:\nTo implement a UI in React, you will usually follow the same five steps.\nStep 1: Break the UI into a component hierarchy\nStart by drawing boxes around every component and subcomponent in the mockup and naming them. If you work with a designer, they may have already named these components in their design tool. Ask them!\nDepending on your background, you can think about splitting up a design into components in different ways:", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "Programming\u2014use the same techniques for deciding if you should create a new function or object. One such technique is the single responsibility principle, that is, a component should ideally only do one thing. If it ends up growing, it should be decomposed into smaller subcomponents.\nCSS\u2014consider what you would make class selectors for. (However, components are a bit less granular.)\nDesign\u2014consider how you would organize the design\u2019s layers.", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "Design\u2014consider how you would organize the design\u2019s layers.\nIf your JSON is well-structured, you\u2019ll often find that it naturally maps to the component structure of your UI. That\u2019s because UI and data models often have the same information architecture\u2014that is, the same shape. Separate your UI into components, where each component matches one piece of your data model.\nThere are five components on this screen:\nFilterableProductTable (grey) contains the entire app.\nFilterableProductTable", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "FilterableProductTable (grey) contains the entire app.\nFilterableProductTable\nSearchBar (blue) receives the user input.\nSearchBar\nProductTable (lavender) displays and filters the list according to the user input.\nProductTable\nProductCategoryRow (green) displays a heading for each category.\nProductCategoryRow\nProductRow\t(yellow) displays a row for each product.\nProductRow", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "ProductRow\t(yellow) displays a row for each product.\nProductRow\nIf you look at ProductTable (lavender), you\u2019ll see that the table header (containing the \u201cName\u201d and \u201cPrice\u201d labels) isn\u2019t its own component. This is a matter of preference, and you could go either way. For this example, it is a part of ProductTable because it appears inside the ProductTable\u2019s list. However, if this header grows to be complex (e.g., if you add sorting), you can move it into its own ProductTableHeader component.", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "ProductTable\nProductTable\nProductTable\nProductTableHeader\nNow that you\u2019ve identified the components in the mockup, arrange them into a hierarchy. Components that appear within another component in the mockup should appear as a child in the hierarchy:\nFilterableProductTable", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "SearchBar\nProductTable\n\nProductCategoryRow\nProductRow\nFilterableProductTable\nSearchBar\nSearchBar\nProductTable", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "ProductCategoryRow\nProductRow\nProductTable\nProductCategoryRow\nProductCategoryRow\nProductRow\nProductRow\nStep 2: Build a static version in React", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "ProductRow\nStep 2: Build a static version in React\nNow that you have your component hierarchy, it\u2019s time to implement your app. The most straightforward approach is to build a version that renders the UI from your data model without adding any interactivity\u2026 yet! It\u2019s often easier to build the static version first and add interactivity later. Building a static version requires a lot of typing and no thinking, but adding interactivity requires a lot of thinking and not a lot of typing.", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "To build a static version of your app that renders your data model, you\u2019ll want to build components that reuse other components and pass data using props. Props are a way of passing data from parent to child. (If you\u2019re familiar with the concept of state, don\u2019t use state at all to build this static version. State is reserved only for interactivity, that is, data that changes over time. Since this is a static version of the app, you don\u2019t need it.)", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "You can either build \u201ctop down\u201d by starting with building the components higher up in the hierarchy (like FilterableProductTable) or \u201cbottom up\u201d by working from components lower down (like ProductRow). In simpler examples, it\u2019s usually easier to go top-down, and on larger projects, it\u2019s easier to go bottom-up.\nFilterableProductTable\nProductRow\nfunction ProductCategoryRow({ category }) {\n return (\n \n \n {category}\n \n \n );\n}", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "function ProductRow({ product }) {\n const name = product.stocked ? product.name :\n \n {product.name}\n ;\n\n return (\n \n {name}\n {product.price}\n \n );\n}\n\nfunction ProductTable({ products }) {\n const rows = [];\n let lastCategory = null;", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "function ProductTable({ products }) {\n const rows = [];\n let lastCategory = null;\n\n products.forEach((product) => {\n if (product.category !== lastCategory) {\n rows.push(\n \n );\n }\n rows.push(\n \n );\n lastCategory = product.category;\n });", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "return (\n \n \n \n \n \n \n \n {rows}\n
          NamePrice
          \n );\n}\n\nfunction SearchBar() {\n return (\n
          \n \n \n
          \n );\n}", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "function FilterableProductTable({ products }) {\n return (\n
          \n \n \n
          \n );\n}", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "const 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];", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "export default function App() {\n return ;\n}\n(If this code looks intimidating, go through the Quick Start first!)", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "}\n(If this code looks intimidating, go through the Quick Start first!)\nAfter building your components, you\u2019ll have a library of reusable components that render your data model. Because this is a static app, the components will only return JSX. The component at the top of the hierarchy (FilterableProductTable) will take your data model as a prop. This is called one-way data flow because the data flows down from the top-level component to the ones at the bottom of the tree.\nFilterableProductTable", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "FilterableProductTable\nPitfall\nAt this point, you should not be using any state values. That\u2019s for the next step!\nStep 3: Find the minimal but complete representation of UI state\nTo make the UI interactive, you need to let users change your underlying data model. You will use state for this.", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "Think of state as the minimal set of changing data that your app needs to remember. The most important principle for structuring state is to keep it DRY (Don\u2019t Repeat Yourself). Figure out the absolute minimal representation of the state your application needs and compute everything else on-demand. For example, if you\u2019re building a shopping list, you can store the items as an array in state. If you want to also display the number of items in the list, don\u2019t store the number of items as another", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "want to also display the number of items in the list, don\u2019t store the number of items as another state value\u2014instead, read the length of your array.", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "Now think of all of the pieces of data in this example application:\nThe original list of products\nThe search text the user has entered\nThe value of the checkbox\nThe filtered list of products\nWhich of these are state? Identify the ones that are not:\nDoes it remain unchanged over time? If so, it isn\u2019t state.\nIs it passed in from a parent via props? If so, it isn\u2019t state.\nCan you compute it based on existing state or props in your component? If so, it definitely isn\u2019t state!", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "What\u2019s left is probably state.\nLet\u2019s go through them one by one again:\nThe original list of products is passed in as props, so it\u2019s not state.\nThe search text seems to be state since it changes over time and can\u2019t be computed from anything.\nThe value of the checkbox seems to be state since it changes over time and can\u2019t be computed from anything.", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "The filtered list of products isn\u2019t state because it can be computed by taking the original list of products and filtering it according to the search text and value of the checkbox.\nThis means only the search text and the value of the checkbox are state! Nicely done!\nThere are two types of \u201cmodel\u201d data in React: props and state. The two are very different:", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "There are two types of \u201cmodel\u201d data in React: props and state. The two are very different:\nProps are like arguments you pass to a function. They let a parent component pass data to a child component and customize its appearance. For example, a Form can pass a color prop to a Button.\nForm\ncolor\nButton\nState is like a component\u2019s memory. It lets a component keep track of some information and change it in response to interactions. For example, a Button might keep track of isHovered state.\nButton", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "Button\nisHovered\nProps and state are different, but they work together. A parent component will often keep some information in state (so that it can change it), and pass it down to child components as their props. It\u2019s okay if the difference still feels fuzzy on the first read. It takes a bit of practice for it to really stick!\nStep 4: Identify where your state should live", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "Step 4: Identify where your state should live\nAfter identifying your app\u2019s minimal state data, you need to identify which component is responsible for changing this state, or owns the state. Remember: React uses one-way data flow, passing data down the component hierarchy from parent to child component. It may not be immediately clear which component should own what state. This can be challenging if you\u2019re new to this concept, but you can figure it out by following these steps!", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "For each piece of state in your application:\nIdentify every component that renders something based on that state.\nFind their closest common parent component\u2014a component above them all in the hierarchy.\nDecide where the state should live:", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "Often, you can put the state directly into their common parent.\nYou can also put the state into some component above their common parent.\nIf you can\u2019t find a component where it makes sense to own the state, create a new component solely for holding the state and add it somewhere in the hierarchy above the common parent component.\nOften, you can put the state directly into their common parent.\nYou can also put the state into some component above their common parent.", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "You can also put the state into some component above their common parent.\nIf you can\u2019t find a component where it makes sense to own the state, create a new component solely for holding the state and add it somewhere in the hierarchy above the common parent component.\nIn the previous step, you found two pieces of state in this application: the search input text, and the value of the checkbox. In this example, they always appear together, so it makes sense to put them into the same place.", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "Now let\u2019s run through our strategy for them:\nIdentify components that use state:", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "ProductTable needs to filter the product list based on that state (search text and checkbox value).\nSearchBar needs to display that state (search text and checkbox value).\nProductTable needs to filter the product list based on that state (search text and checkbox value).\nProductTable\nSearchBar needs to display that state (search text and checkbox value).\nSearchBar\nFind their common parent: The first parent component both components share is FilterableProductTable.\nFilterableProductTable", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "FilterableProductTable\nDecide where the state lives: We\u2019ll keep the filter text and checked state values in FilterableProductTable.\nFilterableProductTable\nSo the state values will live in FilterableProductTable.\nFilterableProductTable\nAdd state to the component with the useState() Hook. Hooks are special functions that let you \u201chook into\u201d React. Add two state variables at the top of FilterableProductTable and specify their initial state:\nuseState()\nFilterableProductTable", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "useState()\nFilterableProductTable\nfunction FilterableProductTable({ products }) { const [filterText, setFilterText] = useState(''); const [inStockOnly, setInStockOnly] = useState(false);\nfunction FilterableProductTable({ products }) { const [filterText, setFilterText] = useState(''); const [inStockOnly, setInStockOnly] = useState(false);\nThen, pass filterText and inStockOnly to ProductTable and SearchBar as props:\nfilterText\ninStockOnly\nProductTable\nSearchBar", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "filterText\ninStockOnly\nProductTable\nSearchBar\n
          \n
          ", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "You can start seeing how your application will behave. Edit the filterText initial value from useState('') to useState('fruit') in the sandbox code below. You\u2019ll see both the search input text and the table update:\nfilterText\nuseState('')\nuseState('fruit')\nimport { useState } from 'react';", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "function FilterableProductTable({ products }) {\n const [filterText, setFilterText] = useState('');\n const [inStockOnly, setInStockOnly] = useState(false);\n\n return (\n
          \n \n \n
          \n );\n}", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "function ProductCategoryRow({ category }) {\n return (\n \n \n {category}\n \n \n );\n}\n\nfunction ProductRow({ product }) {\n const name = product.stocked ? product.name :\n \n {product.name}\n ;\n\n return (\n \n {name}\n {product.price}\n \n );\n}\n\nfunction ProductTable({ products, filterText, inStockOnly }) {\n const rows = [];\n let lastCategory = null;", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "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 \n );\n }\n rows.push(\n \n );", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "rows.push(\n \n );\n lastCategory = product.category;\n });", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "return (\n \n \n \n \n \n \n \n {rows}\n
          NamePrice
          \n );\n}", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "function SearchBar({ filterText, inStockOnly }) {\n return (\n
          \n \n \n
          \n );\n}", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "const 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];", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "export default function App() {\n return ;\n}\nNotice that editing the form doesn\u2019t work yet. There is a console error in the sandbox above explaining why:\nIn the sandbox above, ProductTable and SearchBar read the filterText and inStockOnly props to render the table, the input, and the checkbox. For example, here is how SearchBar populates the input value:\nProductTable\nSearchBar\nfilterText\ninStockOnly\nSearchBar", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "ProductTable\nSearchBar\nfilterText\ninStockOnly\nSearchBar\nfunction SearchBar({ filterText, inStockOnly }) { return (
          \nfunction SearchBar({ filterText, inStockOnly }) { return ( \nHowever, you haven\u2019t added any code to respond to the user actions like typing yet. This will be your final step.", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "Step 5: Add inverse data flow\nCurrently your app renders correctly with props and state flowing down the hierarchy. But to change the state according to user input, you will need to support data flowing the other way: the form components deep in the hierarchy need to update the state in FilterableProductTable.\nFilterableProductTable", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "FilterableProductTable\nReact makes this data flow explicit, but it requires a little more typing than two-way data binding. If you try to type or check the box in the example above, you\u2019ll see that React ignores your input. This is intentional. By writing , you\u2019ve set the value prop of the input to always be equal to the filterText state passed in from FilterableProductTable. Since filterText state is never set, the input never changes.\n", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "\nvalue\ninput\nfilterText\nFilterableProductTable\nfilterText\nYou want to make it so whenever the user changes the form inputs, the state updates to reflect those changes. The state is owned by FilterableProductTable, so only it can call setFilterText and setInStockOnly. To let SearchBar update the FilterableProductTable\u2019s state, you need to pass these functions down to SearchBar:\nFilterableProductTable\nsetFilterText\nsetInStockOnly\nSearchBar\nFilterableProductTable", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "FilterableProductTable\nsetFilterText\nsetInStockOnly\nSearchBar\nFilterableProductTable\nSearchBar\nfunction FilterableProductTable({ products }) { const [filterText, setFilterText] = useState(''); const [inStockOnly, setInStockOnly] = useState(false); return (
          ", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "function FilterableProductTable({ products }) { const [filterText, setFilterText] = useState(''); const [inStockOnly, setInStockOnly] = useState(false); return (
          \nInside the SearchBar, you will add the onChange event handlers and set the parent state from them:\nSearchBar\nonChange", + "title": "Thinking in React \u2013 React", + "url": "https://react.dev/learn/thinking-in-react" + }, + { + "content": "SearchBar\nonChange\nfunction SearchBar({ filterText, inStockOnly, onFilterTextChange, onInStockOnlyChange}) { return ( onFilterTextChange(e.target.value)} />

          \n );\n}\nReady to learn this topic?\nRead Rendering Lists to learn how to render a list of components, and how to choose a key.\nKeeping components pure\nSome JavaScript functions are pure. A pure function:\nMinds its own business. It does not change any objects or variables that existed before it was called.\nSame inputs, same output. Given the same inputs, a pure function should always return the same result.", + "title": "Describing the UI \u2013 React", + "url": "https://react.dev/learn/describing-the-ui" + }, + { + "content": "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 component:\nlet guest = 0;", + "title": "Describing the UI \u2013 React", + "url": "https://react.dev/learn/describing-the-ui" + }, + { + "content": "function Cup() {\n // Bad: changing a preexisting variable!\n guest = guest + 1;\n return

          Tea cup for guest #{guest}

          ;\n}\n\nexport default function TeaSet() {\n return (\n <>\n \n \n \n \n );\n}\nYou can make this component pure by passing a prop instead of modifying a preexisting variable:\nfunction Cup({ guest }) {\n return

          Tea cup for guest #{guest}

          ;\n}", + "title": "Describing the UI \u2013 React", + "url": "https://react.dev/learn/describing-the-ui" + }, + { + "content": "export default function TeaSet() {\n return (\n <>\n \n \n \n \n );\n}\nReady to learn this topic?\nRead Keeping Components Pure to learn how to write components as pure, predictable functions.\nYour UI as a tree\nReact uses trees to model the relationships between components and modules.\nA React render tree is a representation of the parent and child relationship between components.\nAn example React render tree.", + "title": "Describing the UI \u2013 React", + "url": "https://react.dev/learn/describing-the-ui" + }, + { + "content": "An example React render tree.\nComponents 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.\nModelling the relationship between JavaScript modules is another useful way to understand your app. We refer to it as a module dependency tree.\nAn example module dependency tree.", + "title": "Describing the UI \u2013 React", + "url": "https://react.dev/learn/describing-the-ui" + }, + { + "content": "An example module dependency tree.\nA 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.\nReady to learn this topic?", + "title": "Describing the UI \u2013 React", + "url": "https://react.dev/learn/describing-the-ui" + }, + { + "content": "Ready to learn this topic?\nRead Your UI as a Tree to learn how to create a render and module dependency trees for a React app and how they\u2019re useful mental models for improving user experience and performance.\nWhat\u2019s next?\nHead over to Your First Component to start reading this chapter page by page!\nOr, if you\u2019re already familiar with these topics, why not read about Adding Interactivity?", + "title": "Describing the UI \u2013 React", + "url": "https://react.dev/learn/describing-the-ui" + }, + { + "content": "State: A Component's Memory\nComponents often need to change what\u2019s on the screen as a result of an interaction. Typing into the form should update the input field, clicking \u201cnext\u201d on an image carousel should change which image is displayed, clicking \u201cbuy\u201d should put a product in the shopping cart. Components need to \u201cremember\u201d things: the current input value, the current image, the shopping cart. In React, this kind of component-specific memory is called state.\nYou will learn", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "You will learn\nHow to add a state variable with the useState Hook\nuseState\nWhat pair of values the useState Hook returns\nuseState\nHow to add more than one state variable\nWhy state is called local\nWhen a regular variable isn\u2019t enough\nHere\u2019s a component that renders a sculpture image. Clicking the \u201cNext\u201d button should show the next sculpture by changing the index to 1, then 2, and so on. However, this won\u2019t work (you can try it!):\nindex\n1\n2\nimport { sculptureList } from './data.js';", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "export default function Gallery() {\n let index = 0;\n\n function handleClick() {\n index = index + 1;\n }", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "let sculpture = sculptureList[index];\n return (\n <>\n \n

          \n {sculpture.name} \n by {sculpture.artist}\n

          \n

          \n ({index + 1} of {sculptureList.length})\n

          \n {sculpture.alt}\n\n

          \n {sculpture.description}\n

          \n \n );\n}", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "/>\n

          \n {sculpture.description}\n

          \n \n );\n}\nThe handleClick event handler is updating a local variable, index. But two things prevent that change from being visible:\nhandleClick\nindex\nLocal variables don\u2019t persist between renders. When React renders this component a second time, it renders it from scratch\u2014it doesn\u2019t consider any changes to the local variables.", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "Changes to local variables won\u2019t trigger renders. React doesn\u2019t realize it needs to render the component again with the new data.\nTo update a component with new data, two things need to happen:\nRetain the data between renders.\nTrigger React to render the component with new data (re-rendering).\nThe useState Hook provides those two things:\nuseState\nA state variable to retain the data between renders.\nA state setter function to update the variable and trigger React to render the component again.", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "A state setter function to update the variable and trigger React to render the component again.\nAdding a state variable\nTo add a state variable, import useState from React at the top of the file:\nuseState\nimport { useState } from 'react';\nimport { useState } from 'react';\nThen, replace this line:\nlet index = 0;\nlet index = 0;\nwith\nconst [index, setIndex] = useState(0);\nconst [index, setIndex] = useState(0);\nindex is a state variable and setIndex is the setter function.\nindex\nsetIndex", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "index is a state variable and setIndex is the setter function.\nindex\nsetIndex\nThe [ and ] syntax here is called array destructuring and it lets you read values from an array. The array returned by useState always has exactly two items.\n[\n]\nuseState\nThis is how they work together in handleClick:\nhandleClick\nfunction handleClick() { setIndex(index + 1);}\nfunction handleClick() { setIndex(index + 1);}\nNow clicking the \u201cNext\u201d button switches the current sculpture:", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "Now clicking the \u201cNext\u201d button switches the current sculpture:\nimport { useState } from 'react';\nimport { sculptureList } from './data.js';", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "export default function Gallery() {\n const [index, setIndex] = useState(0);\n\n function handleClick() {\n setIndex(index + 1);\n }", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "let sculpture = sculptureList[index];\n return (\n <>\n \n

          \n {sculpture.name} \n by {sculpture.artist}\n

          \n

          \n ({index + 1} of {sculptureList.length})\n

          \n {sculpture.alt}\n\n

          \n {sculpture.description}\n

          \n \n );\n}\nMeet your first Hook", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "/>\n

          \n {sculpture.description}\n

          \n \n );\n}\nMeet your first Hook\nIn React, useState, as well as any other function starting with \u201cuse\u201d, is called a Hook.\nuseState\nuse\nHooks are special functions that are only available while React is rendering (which we\u2019ll get into in more detail on the next page). They let you \u201chook into\u201d different React features.\nState is just one of those features, but you will meet the other Hooks later.\nPitfall", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "State is just one of those features, but you will meet the other Hooks later.\nPitfall\nHooks\u2014functions starting with use\u2014can only be called at the top level of your components or your own Hooks. You can\u2019t call Hooks inside conditions, loops, or other nested functions. Hooks are functions, but it\u2019s helpful to think of them as unconditional declarations about your component\u2019s needs. You \u201cuse\u201d React features at the top of your component similar to how you \u201cimport\u201d modules at the top of your file.", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "use\nAnatomy of useState\nuseState\nWhen you call useState, you are telling React that you want this component to remember something:\nuseState\nconst [index, setIndex] = useState(0);\nconst [index, setIndex] = useState(0);\nIn this case, you want React to remember index.\nindex\nNote\nThe convention is to name this pair like const [something, setSomething]. You could name it anything you like, but conventions make things easier to understand across projects.\nconst [something, setSomething]", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "const [something, setSomething]\nThe only argument to useState is the initial value of your state variable. In this example, the index\u2019s initial value is set to 0 with useState(0).\nuseState\nindex\n0\nuseState(0)\nEvery time your component renders, useState gives you an array containing two values:\nuseState\nThe state variable (index) with the value you stored.\nindex\nThe state setter function (setIndex) which can update the state variable and trigger React to render the component again.\nsetIndex", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "setIndex\nHere\u2019s how that happens in action:\nconst [index, setIndex] = useState(0);\nconst [index, setIndex] = useState(0);\nYour component renders the first time. Because you passed 0 to useState as the initial value for index, it will return [0, setIndex]. React remembers 0 is the latest state value.\n0\nuseState\nindex\n[0, setIndex]\n0", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "0\nuseState\nindex\n[0, setIndex]\n0\nYou update the state. When a user clicks the button, it calls setIndex(index + 1). index is 0, so it\u2019s setIndex(1). This tells React to remember index is 1 now and triggers another render.\nsetIndex(index + 1)\nindex\n0\nsetIndex(1)\nindex\n1\nYour component\u2019s second render. React still sees useState(0), but because React remembers that you set index to 1, it returns [1, setIndex] instead.\nuseState(0)\nindex\n1\n[1, setIndex]\nAnd so on!", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "useState(0)\nindex\n1\n[1, setIndex]\nAnd so on!\nGiving a component multiple state variables\nYou can have as many state variables of as many types as you like in one component. This component has two state variables, a number index and a boolean showMore that\u2019s toggled when you click \u201cShow details\u201d:\nindex\nshowMore\nimport { useState } from 'react';\nimport { sculptureList } from './data.js';", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "export 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 }", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "let sculpture = sculptureList[index];\n return (\n <>\n \n

          \n {sculpture.name} \n by {sculpture.artist}\n

          \n

          \n ({index + 1} of {sculptureList.length})\n

          \n \n {showMore &&

          {sculpture.description}

          }\n {sculpture.description}

          }\n {sculpture.alt}\n\n \n );\n}", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "alt={sculpture.alt}\n />\n \n );\n}\nIt is a good idea to have multiple state variables if their state is unrelated, like index and showMore in this example. But if you find that you often change two state variables together, it might be easier to combine them into one. For example, if you have a form with many fields, it\u2019s more convenient to have a single state variable that holds an object than state variable per field. Read Choosing the State Structure for more tips.\nindex", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "index\nshowMore\nYou might have noticed that the useState call does not receive any information about which state variable it refers to. There is no \u201cidentifier\u201d that is passed to useState, so how does it know which of the state variables to return? Does it rely on some magic like parsing your functions? The answer is no.\nuseState\nuseState", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "useState\nuseState\nInstead, to enable their concise syntax, Hooks rely on a stable call order on every render of the same component. This works well in practice because if you follow the rule above (\u201conly call Hooks at the top level\u201d), Hooks will always be called in the same order. Additionally, a linter plugin catches most mistakes.", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "Internally, React holds an array of state pairs for every component. It also maintains the current pair index, which is set to 0 before rendering. Each time you call useState, React gives you the next state pair and increments the index. You can read more about this mechanism in React Hooks: Not Magic, Just Arrays.\n0\nuseState\nThis example doesn\u2019t use React but it gives you an idea of how useState works internally:\nuseState\nlet componentHooks = [];\nlet currentHookIndex = 0;", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "// 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];", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "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);", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "function handleNextClick() {\n setIndex(index + 1);\n }\n\n function handleMoreClick() {\n setShowMore(!showMore);\n }", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "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}", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "function updateDOM() {\n // Reset the current Hook index\n // before rendering the component.\n currentHookIndex = 0;\n let output = Gallery();", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "// 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}", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "let 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\u00eda',\n artist: 'Marta Colvin Andrade',", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "let sculptureList = [{\n name: 'Homenaje a la Neurocirug\u00eda',\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://i.imgur.com/Mx7dA2Y.jpg',\n alt: 'A bronze statue of two crossed hands delicately holding a human brain in their fingertips.' \n}, {\n name: 'Floralis Gen\u00e9rica',", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "}, {\n name: 'Floralis Gen\u00e9rica',\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://i.imgur.com/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',", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "}, {\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://i.imgur.com/aTtVpES.jpg',", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "url: 'https://i.imgur.com/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://i.imgur.com/RCwLEoQm.jpg',", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "url: 'https://i.imgur.com/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://i.imgur.com/Sd1AgUOm.jpg',", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "url: 'https://i.imgur.com/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.',", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "url: 'https://i.imgur.com/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://i.imgur.com/wIdGuZwm.png',\n alt: 'An intricate wood sculpture of a warrior with a focused face on a horse adorned with patterns.'\n}, {", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "}, {\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://i.imgur.com/AlHTAdDm.jpg',\n alt: 'The sculpture reminds a cascade of folds, quite different from bellies in classical sculptures.'\n}, {", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "}, {\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://i.imgur.com/HMFmH6m.jpg',\n alt: '12 terracotta sculptures of solemn warriors, each with a unique facial expression and armor.'\n}, {\n name: 'Lunar Landscape',", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "}, {\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\u2019s geometric abstraction of space and form.',\n url: 'https://i.imgur.com/rN7hY6om.jpg',", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "url: 'https://i.imgur.com/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.\"',", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "url: 'https://i.imgur.com/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://i.imgur.com/6o5Vuyu.jpg',\n alt: 'A group of bronze hippo sculptures emerging from the sett sidewalk as if they were swimming.'\n}];", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "// Make UI match the initial state.\nupdateDOM();\nYou don\u2019t have to understand it to use React, but you might find this a helpful mental model.\nState is isolated and private\nState is local to a component instance on the screen. In other words, if you render the same component twice, each copy will have completely isolated state! Changing one of them will not affect the other.", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "In this example, the Gallery component from earlier is rendered twice with no changes to its logic. Try clicking the buttons inside each of the galleries. Notice that their state is independent:\nGallery\nimport Gallery from './Gallery.js';", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "export default function Page() {\n return (\n
          \n \n \n
          \n );\n}\nThis is what makes state different from regular variables that you might declare at the top of your module. State is not tied to a particular function call or a place in the code, but it\u2019s \u201clocal\u201d to the specific place on the screen. You rendered two components, so their state is stored separately.\n", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "\nAlso notice how the Page component doesn\u2019t \u201cknow\u201d anything about the Gallery state or even whether it has any. Unlike props, state is fully private to the component declaring it. The parent component can\u2019t change it. This lets you add state to any component or remove it without impacting the rest of the components.\nPage\nGallery", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "Page\nGallery\nWhat if you wanted both galleries to keep their states in sync? The right way to do it in React is to remove state from child components and add it to their closest shared parent. The next few pages will focus on organizing state of a single component, but we will return to this topic in Sharing State Between Components.\nRecap\nUse a state variable when a component needs to \u201cremember\u201d some information between renders.\nState variables are declared by calling the useState Hook.", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "State variables are declared by calling the useState Hook.\nuseState\nHooks are special functions that start with use. They let you \u201chook into\u201d React features like state.\nuse\nHooks might remind you of imports: they need to be called unconditionally. Calling Hooks, including useState, is only valid at the top level of a component or another Hook.\nuseState\nThe useState Hook returns a pair of values: the current state and the function to update it.\nuseState", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "useState\nYou can have more than one state variable. Internally, React matches them up by their order.\nState is private to the component. If you render it in two places, each copy gets its own state.\nTry out some challenges\nWhen you press \u201cNext\u201d on the last sculpture, the code crashes. Fix the logic to prevent the crash. You may do this by adding extra logic to event handler or by disabling the button when the action is not possible.", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "After fixing the crash, add a \u201cPrevious\u201d button that shows the previous sculpture. It shouldn\u2019t crash on the first sculpture.\nimport { useState } from 'react';\nimport { sculptureList } from './data.js';", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "export 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 }", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "let sculpture = sculptureList[index];\n return (\n <>\n \n

          \n {sculpture.name} \n by {sculpture.artist}\n

          \n

          \n ({index + 1} of {sculptureList.length})\n

          \n \n {showMore &&

          {sculpture.description}

          }\n {sculpture.description}

          }\n {sculpture.alt}\n\n \n );\n}", + "title": "State: A Component's Memory \u2013 React", + "url": "https://react.dev/learn/state-a-components-memory" + }, + { + "content": "Managing State\nAs 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\u2019ll learn how to structure your state well, how to keep your state update logic maintainable, and how to share state between distant components.\nIn this chapter\nHow to think about UI changes as state changes\nHow to structure state well", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "In this chapter\nHow to think about UI changes as state changes\nHow to structure state well\nHow to \u201clift state up\u201d to share it between components\nHow to control whether the state gets preserved or reset\nHow to consolidate complex state logic in a function\nHow to pass information without \u201cprop drilling\u201d\nHow to scale state management as your app grows\nReacting to input with state", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "Reacting to input with state\nWith React, you won\u2019t modify the UI from code directly. For example, you won\u2019t write commands like \u201cdisable the button\u201d, \u201cenable the button\u201d, \u201cshow the success message\u201d, etc. Instead, you will describe the UI you want to see for the different visual states of your component (\u201cinitial state\u201d, \u201ctyping state\u201d, \u201csuccess state\u201d), and then trigger the state changes in response to user input. This is similar to how designers think about UI.", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "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.\nstatus\nimport { useState } from 'react';", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "export 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

          That's right!

          \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 }", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "function handleTextareaChange(e) {\n setAnswer(e.target.value);\n }", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "return (\n <>\n

          City quiz

          \n

          \n In which city is there a billboard that turns air into drinkable water?\n

          \n
          \n \n
          \n ", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "status === 'submitting'\n }>\n Submit\n \n {error !== null &&\n

          \n {error.message}\n

          \n }\n \n \n );\n}", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "function 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}\nReady to learn this topic?\nRead Reacting to Input with State to learn how to approach interactions with a state-driven mindset.", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "Choosing the state structure\nStructuring 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\u2019t contain redundant or duplicated information. If there\u2019s unnecessary state, it\u2019s easy to forget to update it, and introduce bugs!\nFor example, this form has a redundant fullName state variable:\nfullName\nimport { useState } from 'react';", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "export 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 }", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "return (\n <>\n

          Let\u2019s check you in

          \n \n \n

          \n Your ticket will be issued to: {fullName}\n

          \n \n );\n}", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "

          \n Your ticket will be issued to: {fullName}\n

          \n \n );\n}\nYou can remove it and simplify the code by calculating fullName while the component is rendering:\nfullName\nimport { useState } from 'react';", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "export 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 }", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "return (\n <>\n

          Let\u2019s check you in

          \n \n \n

          \n Your ticket will be issued to: {fullName}\n

          \n \n );\n}", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "

          \n Your ticket will be issued to: {fullName}\n

          \n \n );\n}\nThis might seem like a small change, but many bugs in React apps are fixed this way.\nReady to learn this topic?\nRead Choosing the State Structure to learn how to design the state shape to avoid bugs.\nSharing state between components", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "Sharing state between components\nSometimes, 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 \u201clifting state up\u201d, and it\u2019s one of the most common things you will do writing React code.", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "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.\nimport { useState } from 'react';", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "export default function Accordion() {\n const [activeIndex, setActiveIndex] = useState(0);\n return (\n <>\n

          Almaty, Kazakhstan

          \n 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 \n \n setActiveIndex(1)}\n >\n The name comes from \u0430\u043b\u043c\u0430, 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 Malus sieversii is considered a likely candidate for the ancestor of the modern domestic apple.", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "\n \n );\n}", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "function Panel({\n title,\n children,\n isActive,\n onShow\n}) {\n return (\n
          \n

          {title}

          \n {isActive ? (\n

          {children}

          \n ) : (\n \n )}\n
          \n );\n}\nReady to learn this topic?\nRead Sharing State Between Components to learn how to lift state up and keep components in sync.\nPreserving and resetting state", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "Preserving and resetting state\nWhen 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\u2019s automatic behavior works well enough. By default, React preserves the parts of the tree that \u201cmatch up\u201d with the previously rendered component tree.", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "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 person:\nimport { useState } from 'react';\nimport Chat from './Chat.js';\nimport ContactList from './ContactList.js';", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "export default function Messenger() {\n const [to, setTo] = useState(contacts[0]);\n return (\n
          \n setTo(contact)}\n />\n \n
          \n )\n}", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "const contacts = [\n { name: 'Taylor', email: 'taylor@mail.com' },\n { name: 'Alice', email: 'alice@mail.com' },\n { name: 'Bob', email: 'bob@mail.com' }\n];", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "{ name: 'Bob', email: 'bob@mail.com' }\n];\nReact lets you override the default behavior, and force a component to reset its state by passing it a different key, like . 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\u2014even though you render the same component.\nkey", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "key\n\nChat\nimport { useState } from 'react';\nimport Chat from './Chat.js';\nimport ContactList from './ContactList.js';", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "export default function Messenger() {\n const [to, setTo] = useState(contacts[0]);\n return (\n
          \n setTo(contact)}\n />\n \n
          \n )\n}", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "const contacts = [\n { name: 'Taylor', email: 'taylor@mail.com' },\n { name: 'Alice', email: 'alice@mail.com' },\n { name: 'Bob', email: 'bob@mail.com' }\n];\nReady to learn this topic?\nRead Preserving and Resetting State to learn the lifetime of state and how to control it.\nExtracting state logic into a reducer", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "Extracting state logic into a reducer\nComponents 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 \u201creducer\u201d. Your event handlers become concise because they only specify the user \u201cactions\u201d. At the bottom of the file, the reducer function specifies how the state should update in response to each action!\nimport { useReducer } from 'react';", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "import { useReducer } from 'react';\nimport AddTask from './AddTask.js';\nimport TaskList from './TaskList.js';", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "export 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 }", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "return (\n <>\n

          Prague itinerary

          \n \n \n \n );\n}", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "function 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: {", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "case 'deleted': {\n return tasks.filter(t => t.id !== action.id);\n }\n default: {\n throw Error('Unknown action: ' + action.type);\n }\n }\n}", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "let 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];\nReady to learn this topic?\nRead Extracting State Logic into a Reducer to learn how to consolidate logic in the reducer function.\nPassing data deeply with context", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "Passing data deeply with context\nUsually, 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\u2014no matter how deep it is\u2014without passing it explicitly through props.", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "Here, the Heading component determines its heading level by \u201casking\u201d 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\u2014it does that through context.\nHeading\nSection\nSection\nSection\nSection\nimport Heading from './Heading.js';\nimport Section from './Section.js';", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "export default function Page() {\n return (\n
          \n Title\n
          \n Heading\n Heading\n Heading\n
          \n Sub-heading\n Sub-heading\n Sub-heading\n
          \n Sub-sub-heading\n Sub-sub-heading", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "Sub-sub-heading\n Sub-sub-heading\n Sub-sub-heading\n
          \n
          \n
          \n
          \n );\n}\nReady to learn this topic?\nRead Passing Data Deeply with Context to learn about using context as an alternative to passing props.\nScaling up with reducer and context", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "Scaling up with reducer and context\nReducers let you consolidate a component\u2019s 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.\nWith 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.\nimport AddTask from './AddTask.js';", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "import AddTask from './AddTask.js';\nimport TaskList from './TaskList.js';\nimport { TasksProvider } from './TasksContext.js';", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "export default function TaskApp() {\n return (\n \n

          Day off in Kyoto

          \n \n \n
          \n );\n}\nReady to learn this topic?\nRead Scaling Up with Reducer and Context to learn how state management scales in a growing app.\nWhat\u2019s next?\nHead over to Reacting to Input with State to start reading this chapter page by page!\nOr, if you\u2019re already familiar with these topics, why not read about Escape Hatches?", + "title": "Managing State \u2013 React", + "url": "https://react.dev/learn/managing-state" + }, + { + "content": "Installation\nReact 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.\nTry React\nYou don\u2019t need to install anything to play with React. Try editing this sandbox!\nfunction Greeting({ name }) {\n return

          Hello, {name}

          ;\n}", + "title": "Installation \u2013 React", + "url": "https://react.dev/learn/installation" + }, + { + "content": "export default function App() {\n return \n}\nYou can edit it directly or open it in a new tab by pressing the \u201cFork\u201d button in the upper right corner.\nMost pages in the React documentation contain sandboxes like this. Outside of the React documentation, there are many online sandboxes that support React: for example, CodeSandbox, StackBlitz, or CodePen.\nTo try React locally on your computer, download this HTML page. Open it in your editor and in your browser!", + "title": "Installation \u2013 React", + "url": "https://react.dev/learn/installation" + }, + { + "content": "Creating a React App\nIf you want to start a new React app, you can create a React app using a recommended framework.\nBuild a React App from Scratch\nIf 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.\nAdd React to an existing project\nIf want to try using React in your existing app or a website, you can add React to an existing project.\nNote", + "title": "Installation \u2013 React", + "url": "https://react.dev/learn/installation" + }, + { + "content": "Note\nNo. Create React App has been deprecated. For more information, see Sunsetting Create React App.\nNext steps\nHead to the Quick Start guide for a tour of the most important React concepts you will encounter every day.", + "title": "Installation \u2013 React", + "url": "https://react.dev/learn/installation" + }, + { + "content": "Rendering Lists\nYou 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\u2019ll use filter() and map() with React to filter and transform your array of data into an array of components.\nfilter()\nmap()\nYou will learn\nHow to render components from an array using JavaScript\u2019s map()\nmap()\nHow to render only specific components using JavaScript\u2019s filter()\nfilter()", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "map()\nHow to render only specific components using JavaScript\u2019s filter()\nfilter()\nWhen and why to use React keys\nRendering data from arrays\nSay that you have a list of content.\n
          • Creola Katherine Johnson: mathematician
          • Mario Jos\u00e9 Molina-Pasquel Henr\u00edquez: chemist
          • Mohammad Abdus Salam: physicist
          • Percy Lavon Julian: chemist
          • Subrahmanyan Chandrasekhar: astrophysicist
          ", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "
          • Creola Katherine Johnson: mathematician
          • Mario Jos\u00e9 Molina-Pasquel Henr\u00edquez: chemist
          • Mohammad Abdus Salam: physicist
          • Percy Lavon Julian: chemist
          • Subrahmanyan Chandrasekhar: astrophysicist
          ", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "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 interfaces: from 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.\nmap()\nfilter()\nHere\u2019s a short example of how to generate a list of items from an array:", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "map()\nfilter()\nHere\u2019s a short example of how to generate a list of items from an array:\nMove the data into an array:\nconst people = [ 'Creola Katherine Johnson: mathematician', 'Mario Jos\u00e9 Molina-Pasquel Henr\u00edquez: chemist', 'Mohammad Abdus Salam: physicist', 'Percy Lavon Julian: chemist', 'Subrahmanyan Chandrasekhar: astrophysicist'];", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "const people = [ 'Creola Katherine Johnson: mathematician', 'Mario Jos\u00e9 Molina-Pasquel Henr\u00edquez: chemist', 'Mohammad Abdus Salam: physicist', 'Percy Lavon Julian: chemist', 'Subrahmanyan Chandrasekhar: astrophysicist'];\nMap the people members into a new array of JSX nodes, listItems:\npeople\nlistItems\nconst listItems = people.map(person =>
        12. {person}
        13. );\nconst listItems = people.map(person =>
        14. {person}
        15. );\nReturn listItems from your component wrapped in a
            :\nlistItems\n
              ", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "Return listItems from your component wrapped in a
                :\nlistItems\n
                  \nreturn
                    {listItems}
                  ;\nreturn
                    {listItems}
                  ;\nHere is the result:\nconst people = [\n 'Creola Katherine Johnson: mathematician',\n 'Mario Jos\u00e9 Molina-Pasquel Henr\u00edquez: chemist',\n 'Mohammad Abdus Salam: physicist',\n 'Percy Lavon Julian: chemist',\n 'Subrahmanyan Chandrasekhar: astrophysicist'\n];", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "export default function List() {\n const listItems = people.map(person =>\n
                • {person}
                • \n );\n return
                    {listItems}
                  ;\n}\nNotice the sandbox above displays a console error:\nYou\u2019ll learn how to fix this error later on this page. Before we get to that, let\u2019s add some structure to your data.\nFiltering arrays of items\nThis data can be structured even more.", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "Filtering arrays of items\nThis data can be structured even more.\nconst people = [{ id: 0, name: 'Creola Katherine Johnson', profession: 'mathematician',}, { id: 1, name: 'Mario Jos\u00e9 Molina-Pasquel Henr\u00edquez', 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',}];", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "const people = [{ id: 0, name: 'Creola Katherine Johnson', profession: 'mathematician',}, { id: 1, name: 'Mario Jos\u00e9 Molina-Pasquel Henr\u00edquez', 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',}];", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "Let\u2019s say you want a way to only show people whose profession is 'chemist'. You can use JavaScript\u2019s filter() method to return just those people. This method takes an array of items, passes them through a \u201ctest\u201d (a function that returns true or false), and returns a new array of only those items that passed the test (returned true).\n'chemist'\nfilter()\ntrue\nfalse\ntrue", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "'chemist'\nfilter()\ntrue\nfalse\ntrue\nYou only want the items where profession is 'chemist'. The \u201ctest\u201d function for this looks like (person) => person.profession === 'chemist'. Here\u2019s how to put it together:\nprofession\n'chemist'\n(person) => person.profession === 'chemist'\nCreate a new array of just \u201cchemist\u201d people, chemists, by calling filter() on the people filtering by person.profession === 'chemist':\nchemists\nfilter()\npeople\nperson.profession === 'chemist'", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "chemists\nfilter()\npeople\nperson.profession === 'chemist'\nconst chemists = people.filter(person => person.profession === 'chemist');\nconst chemists = people.filter(person => person.profession === 'chemist');\nNow map over chemists:\nchemists\nconst listItems = chemists.map(person =>
                • {person.name}

                  {person.name}: {' ' + person.profession + ' '} known for {person.accomplishment}

                • );", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "const listItems = chemists.map(person =>
                • {person.name}

                  {person.name}: {' ' + person.profession + ' '} known for {person.accomplishment}

                • );\nLastly, return the listItems from your component:\nlistItems\nreturn
                    {listItems}
                  ;\nreturn
                    {listItems}
                  ;\nimport { people } from './data.js';\nimport { getImageUrl } from './utils.js';", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "export default function List() {\n const chemists = people.filter(person =>\n person.profession === 'chemist'\n );\n const listItems = chemists.map(person =>\n
                • \n \n

                  \n {person.name}:\n {' ' + person.profession + ' '}\n known for {person.accomplishment}\n

                  \n
                • \n );\n return
                    {listItems}
                  ;\n}\nPitfall", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "

                  \n \n );\n return
                    {listItems}
                  ;\n}\nPitfall\nArrow functions implicitly return the expression right after =>, so you didn\u2019t need a return statement:\n=>\nreturn\nconst listItems = chemists.map(person =>
                • ...
                • // Implicit return!);\nconst listItems = chemists.map(person =>
                • ...
                • // Implicit return!);\nHowever, you must write return explicitly if your => is followed by a { curly brace!\nreturn\n=>\n{", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "However, you must write return explicitly if your => is followed by a { curly brace!\nreturn\n=>\n{\nconst listItems = chemists.map(person => { // Curly brace return
                • ...
                • ;});\nconst listItems = chemists.map(person => { // Curly brace return
                • ...
                • ;});\nArrow functions containing => { are said to have a \u201cblock body\u201d. 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!\n=> {\nreturn", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "=> {\nreturn\nKeeping list items in order with key\nkey\nNotice that all the sandboxes above show an error in the console:\nYou need to give each array item a key \u2014 a string or a number that uniquely identifies it among other items in that array:\nkey\n
                • ...
                • \n
                • ...
                • \nNote\nJSX elements directly inside a map() call always need keys!\nmap()", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "
                • ...
                • \nNote\nJSX elements directly inside a map() call always need keys!\nmap()\nKeys 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.\nkey\nRather than generating keys on the fly, you should include them in your data:", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "key\nRather than generating keys on the fly, you should include them in your data:\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\u00e9 Molina-Pasquel Henr\u00edquez',\n profession: 'chemist',\n accomplishment: 'discovery of Arctic ozone hole',\n imageId: 'mynHUSa'\n}, {\n id: 2, // Used in JSX as a key", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "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',", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "name: 'Subrahmanyan Chandrasekhar',\n profession: 'astrophysicist',\n accomplishment: 'white dwarf star mass calculations',\n imageId: 'lrWQx8l'\n}];\nWhat do you do when each item needs to render not one, but several DOM nodes?\nThe short <>... Fragment syntax won\u2019t let you pass a key, so you need to either group them into a single
                  , or use the slightly longer and more explicit syntax:\n<>...\n
                  \n", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "<>...\n
                  \n\nimport { Fragment } from 'react';// ...const listItems = people.map(person =>

                  {person.name}

                  {person.bio}

                  );\nimport { Fragment } from 'react';// ...const listItems = people.map(person =>

                  {person.name}

                  {person.bio}

                  );\nFragments disappear from the DOM, so this will produce a flat list of

                  ,

                  ,

                  ,

                  , and so on.\n

                  \n

                  \n

                  \n

                  ", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "

                  \n

                  \n

                  \n

                  \nWhere to get your key\nkey\nDifferent sources of data provide different sources of keys:\nData from a database: If your data is coming from a database, you can use the database keys/IDs, which are unique by nature.\nLocally generated data: If 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.\ncrypto.randomUUID()\nuuid\nRules of keys", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "crypto.randomUUID()\nuuid\nRules of keys\nKeys must be unique among siblings. However, it\u2019s okay to use the same keys for JSX nodes in different arrays.\nKeys must not change or that defeats their purpose! Don\u2019t generate them while rendering.\nWhy does React need keys?", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "Why does React need keys?\nImagine that files on your desktop didn\u2019t have names. Instead, you\u2019d refer to them by their order \u2014 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.", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "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.\nkey\nPitfall", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "key\nPitfall\nYou might be tempted to use an item\u2019s index in the array as its key. In fact, that\u2019s what React will use if you don\u2019t 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.\nkey", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "key\nSimilarly, 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.\nkey={Math.random()}", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "key={Math.random()}\nNote that your components won\u2019t receive key as a prop. It\u2019s only used as a hint by React itself. If your component needs an ID, you have to pass it as a separate prop: .\nkey\n\nRecap\nOn this page you learned:\nHow to move data out of components and into data structures like arrays and objects.\nHow to generate sets of similar components with JavaScript\u2019s map().\nmap()", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "How to generate sets of similar components with JavaScript\u2019s map().\nmap()\nHow to create arrays of filtered items with JavaScript\u2019s filter().\nfilter()\nWhy 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.\nkey\nTry out some challenges\nThis example shows a list of all people.", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "key\nTry out some challenges\nThis example shows a list of all people.\nChange it to show two separate lists one after another: Chemists and Everyone Else. Like previously, you can determine whether a person is a chemist by checking if person.profession === 'chemist'.\nperson.profession === 'chemist'\nimport { people } from './data.js';\nimport { getImageUrl } from './utils.js';", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "export default function List() {\n const listItems = people.map(person =>\n

                • \n \n

                  \n {person.name}:\n {' ' + person.profession + ' '}\n known for {person.accomplishment}\n

                  \n
                • \n );\n return (\n
                  \n

                  Scientists

                  \n
                    {listItems}
                  \n
                  \n );\n}", + "title": "Rendering Lists \u2013 React", + "url": "https://react.dev/learn/rendering-lists" + }, + { + "content": "Passing Props to a Component\nReact 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.\nYou will learn\nHow to pass props to a component\nHow to read props from a component\nHow to specify default values for props\nHow to pass some JSX to a component", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "How to specify default values for props\nHow to pass some JSX to a component\nHow props change over time\nFamiliar props\nProps 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 :\nclassName\nsrc\nalt\nwidth\nheight\n\nfunction Avatar() {\n return (\n \n );\n}", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "export default function Profile() {\n return (\n \n );\n}\nThe props you can pass to an tag are predefined (ReactDOM conforms to the HTML standard). But you can pass any props to your own components, such as , to customize them. Here\u2019s how!\n\n\nPassing props to a component\nIn this code, the Profile component isn\u2019t passing any props to its child component, Avatar:\nProfile\nAvatar\nexport default function Profile() { return ( );}", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "Profile\nAvatar\nexport default function Profile() { return ( );}\nexport default function Profile() { return ( );}\nYou can give Avatar some props in two steps.\nAvatar\nStep 1: Pass props to the child component\nFirst, pass some props to Avatar. For example, let\u2019s pass two props: person (an object), and size (a number):\nAvatar\nperson\nsize", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "Avatar\nperson\nsize\nexport default function Profile() { return ( );}\nexport default function Profile() { return ( );}\nNote\nIf double curly braces after person= confuse you, recall they\u2019re merely an object inside the JSX curlies.\nperson=\nNow you can read these props inside the Avatar component.\nAvatar", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "person=\nNow you can read these props inside the Avatar component.\nAvatar\nStep 2: Read props inside the child component\nYou 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.\nperson, size\n({\n})\nfunction Avatar\nAvatar\nfunction Avatar({ person, size }) { // person and size are available here}", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "function Avatar\nAvatar\nfunction Avatar({ person, size }) { // person and size are available here}\nfunction Avatar({ person, size }) { // person and size are available here}\nAdd some logic to Avatar that uses the person and size props for rendering, and you\u2019re done.\nAvatar\nperson\nsize\nNow you can configure Avatar to render in many different ways with different props. Try tweaking the values!\nAvatar\nimport { getImageUrl } from './utils.js';", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "function Avatar({ person, size }) {\n return (\n \n );\n}", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "export default function Profile() {\n return (\n
                  \n \n \n \n
                  \n );\n}", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "name: 'Lin Lanying',\n imageId: '1bX5QH6'\n }}\n />\n

                  \n );\n}\nProps 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.\nperson\nsize\nProfile\nAvatar\nAvatar\nProfile", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "person\nsize\nProfile\nAvatar\nAvatar\nProfile\nYou can think of props like \u201cknobs\u201d that you can adjust. They serve the same role as arguments serve for functions\u2014in fact, props are the only argument to your component! React component functions accept a single argument, a props object:\nprops\nfunction Avatar(props) { let person = props.person; let size = props.size; // ...}\nfunction Avatar(props) { let person = props.person; let size = props.size; // ...}", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "function Avatar(props) { let person = props.person; let size = props.size; // ...}\nUsually you don\u2019t need the whole props object itself, so you destructure it into individual props.\nprops\nPitfall\nDon\u2019t miss the pair of { and } curlies inside of ( and ) when declaring props:\n{\n}\n(\n)\nfunction Avatar({ person, size }) { // ...}\nfunction Avatar({ person, size }) { // ...}\nThis syntax is called \u201cdestructuring\u201d and is equivalent to reading properties from a function parameter:", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "function Avatar(props) { let person = props.person; let size = props.size; // ...}\nfunction Avatar(props) { let person = props.person; let size = props.size; // ...}\nSpecifying a default value for a prop\nIf 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 parameter:\n=\nfunction Avatar({ person, size = 100 }) { // ...}\nfunction Avatar({ person, size = 100 }) { // ...}", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "function Avatar({ person, size = 100 }) { // ...}\nNow, if is rendered with no size prop, the size will be set to 100.\n\nsize\nsize\n100\nThe 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.\nsize\nsize={undefined}\nsize={null}\nsize={0}\nForwarding props with the JSX spread syntax\nSometimes, passing props gets very repetitive:", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "size={0}\nForwarding props with the JSX spread syntax\nSometimes, passing props gets very repetitive:\nfunction Profile({ person, size, isSepia, thickBorder }) { return (
                  );}", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "function Profile({ person, size, isSepia, thickBorder }) { return (
                  );}", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "There\u2019s nothing wrong with repetitive code\u2014it 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\u2019t use any of their props directly, it can make sense to use a more concise \u201cspread\u201d syntax:\nProfile\nAvatar\nfunction Profile(props) { return (
                  );}", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "function Profile(props) { return (
                  );}\nThis forwards all of Profile\u2019s props to the Avatar without listing each of their names.\nProfile\nAvatar\nUse spread syntax with restraint. If you\u2019re 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!\nPassing JSX as children\nIt is common to nest built-in browser tags:\n
                  ", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "Passing JSX as children\nIt is common to nest built-in browser tags:\n
                  \n
                  \nSometimes you\u2019ll want to nest your own components the same way:\n \n \nWhen 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 and render it in a wrapper div:\nchildren\nCard\nchildren\n", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "children\nCard\nchildren\n\nimport Avatar from './Avatar.js';", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "function Card({ children }) {\n return (\n
                  \n {children}\n
                  \n );\n}", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "export default function Profile() {\n return (\n \n \n \n );\n}\nTry replacing the inside with some text to see how the Card component can wrap any nested content. It doesn\u2019t need to \u201cknow\u201d what\u2019s being rendered inside of it. You will see this flexible pattern in many places.\n\n\nCard", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "\n\nCard\nYou can think of a component with a children prop as having a \u201chole\u201d that can be \u201cfilled in\u201d by its parent components with arbitrary JSX. You will often use the children prop for visual wrappers: panels, grids, etc.\nchildren\nchildren\nIllustrated by Rachel Lee Nabors\nHow props change over time", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "children\nchildren\nIllustrated by Rachel Lee Nabors\nHow props change over time\nThe Clock component below receives two props from its parent component: color and time. (The parent component\u2019s code is omitted because it uses state, which we won\u2019t dive into just yet.)\nClock\ncolor\ntime\nTry changing the color in the select box below:\nexport default function Clock({ color, time }) {\n return (\n

                  \n {time}\n

                  \n );\n}", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "return (\n

                  \n {time}\n

                  \n );\n}\nThis 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\u2019s data at any point in time, rather than only in the beginning.\ntime\ncolor", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "time\ncolor\nHowever, props are immutable\u2014a term from computer science meaning \u201cunchangeable\u201d. When a component needs to change its props (for example, in response to a user interaction or new data), it will have to \u201cask\u201d its parent component to pass it different props\u2014a new object! Its old props will then be cast aside, and eventually the JavaScript engine will reclaim the memory taken by them.", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "Don\u2019t try to \u201cchange props\u201d. When you need to respond to the user input (like changing the selected color), you will need to \u201cset state\u201d, which you can learn about in State: A Component\u2019s Memory.\nRecap\nTo pass props, add them to the JSX, just like you would with HTML attributes.\nTo read props, use the function Avatar({ person, size }) destructuring syntax.\nfunction Avatar({ person, size })\nYou can specify a default value like size = 100, which is used for missing and undefined props.\nsize = 100", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "size = 100\nundefined\nYou can forward all props with JSX spread syntax, but don\u2019t overuse it!\n\nNested JSX like will appear as Card component\u2019s children prop.\n\nCard\nchildren\nProps are read-only snapshots in time: every render receives a new version of props.\nYou can\u2019t change props. When you need interactivity, you\u2019ll need to set state.\nTry out some challenges\nchildren", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "Try out some challenges\nchildren\nThis Gallery component contains some very similar markup for two profiles. Extract a Profile component out of it to reduce the duplication. You\u2019ll need to choose what props to pass to it.\nGallery\nProfile\nimport { getImageUrl } from './utils.js';", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "export default function Gallery() {\n return (\n
                  \n

                  Notable Scientists

                  \n
                  \n

                  Maria Sk\u0142odowska-Curie

                  \n \n
                    \n
                  • \n Profession: \n physicist and chemist\n
                  • \n
                  • \n Awards: 4 ", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "physicist and chemist\n
                  • \n
                  • \n Awards: 4 \n (Nobel Prize in Physics, Nobel Prize in Chemistry, Davy Medal, Matteucci Medal)\n
                  • \n
                  • \n Discovered: \n polonium (chemical element)\n
                  • \n
                  \n
                  \n
                  \n

                  Katsuko Saruhashi

                  \n \n
                    \n
                  • \n Profession: \n geochemist\n
                  • \n
                  • \n Awards: 2 \n (Miyake Prize for geochemistry, Tanaka Prize)\n
                  • \n
                  • \n Discovered: \n a method for measuring carbon dioxide in seawater", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "Discovered: \n a method for measuring carbon dioxide in seawater\n
                  • \n
                  \n
                  \n
                  \n );\n}", + "title": "Passing Props to a Component \u2013 React", + "url": "https://react.dev/learn/passing-props-to-a-component" + }, + { + "content": "Setup\nReact integrates with tools like editors, TypeScript, browser extensions, and compilers. This section will help you get your environment set up.\nEditor Setup\nSee our recommended editors and learn how to set them up to work with React.\nUsing TypeScript\nTypeScript is a popular way to add type definitions to JavaScript codebases. Learn how to integrate TypeScript into your React projects.\nReact Developer Tools", + "title": "Setup \u2013 React", + "url": "https://react.dev/learn/setup" + }, + { + "content": "React Developer Tools\nReact 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.\nReact Compiler\nReact Compiler is a tool that automatically optimizes your React app. Learn more.\nNext steps\nHead to the Quick Start guide for a tour of the most important React concepts you will encounter every day.", + "title": "Setup \u2013 React", + "url": "https://react.dev/learn/setup" + }, + { + "content": "React Developer Tools\nUse React Developer Tools to inspect React components, edit props and state, and identify performance problems.\nYou will learn\nHow to install React Developer Tools\nBrowser extension\nThe easiest way to debug websites built with React is to install the React Developer Tools browser extension. It is available for several popular browsers:\nInstall for Chrome\nInstall for Firefox\nInstall for Edge", + "title": "React Developer Tools \u2013 React", + "url": "https://react.dev/learn/react-developer-tools" + }, + { + "content": "Install for Chrome\nInstall for Firefox\nInstall for Edge\nNow, if you visit a website built with React, you will see the Components and Profiler panels.\nSafari and other browsers\nFor other browsers (for example, Safari), install the react-devtools npm package:\nreact-devtools\n# Yarnyarn global add react-devtools# Npmnpm install -g react-devtools\n# Yarnyarn global add react-devtools# Npmnpm install -g react-devtools\nNext open the developer tools from the terminal:\nreact-devtools\nreact-devtools", + "title": "React Developer Tools \u2013 React", + "url": "https://react.dev/learn/react-developer-tools" + }, + { + "content": "Next open the developer tools from the terminal:\nreact-devtools\nreact-devtools\nThen connect your website by adding the following \n \nReload your website in the browser now to view it in developer tools.\nMobile (React Native)", + "title": "React Developer Tools \u2013 React", + "url": "https://react.dev/learn/react-developer-tools" + }, + { + "content": "Reload your website in the browser now to view it in developer tools.\nMobile (React Native)\nTo 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.\nLearn more about debugging in React Native.", + "title": "React Developer Tools \u2013 React", + "url": "https://react.dev/learn/react-developer-tools" + }, + { + "content": "Learn more about debugging in React Native.\nFor 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.", + "title": "React Developer Tools \u2013 React", + "url": "https://react.dev/learn/react-developer-tools" + }, + { + "content": "Understanding Your UI as a Tree\nYour React app is taking shape with many components being nested within each other. How does React keep track of your app\u2019s component structure?\nReact, 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.\nYou will learn\nHow React \u201csees\u201d component structures", + "title": "Understanding Your UI as a Tree \u2013 React", + "url": "https://react.dev/learn/understanding-your-ui-as-a-tree" + }, + { + "content": "You will learn\nHow React \u201csees\u201d component structures\nWhat a render tree is and what it is useful for\nWhat a module dependency tree is and what it is useful for\nYour UI as a tree\nTrees are a relationship model between items and 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.", + "title": "Understanding Your UI as a Tree \u2013 React", + "url": "https://react.dev/learn/understanding-your-ui-as-a-tree" + }, + { + "content": "React creates a UI tree from your components. In this example, the UI tree is then used to render to the DOM.\nLike 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.\nThe Render Tree", + "title": "Understanding Your UI as a Tree \u2013 React", + "url": "https://react.dev/learn/understanding-your-ui-as-a-tree" + }, + { + "content": "The Render Tree\nA 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.\nWhen we render a React app, we can model this relationship in a tree, known as the render tree.\nHere is a React app that renders inspirational quotes.\nimport FancyText from './FancyText';\nimport InspirationGenerator from './InspirationGenerator';", + "title": "Understanding Your UI as a Tree \u2013 React", + "url": "https://react.dev/learn/understanding-your-ui-as-a-tree" + }, + { + "content": "import FancyText from './FancyText';\nimport InspirationGenerator from './InspirationGenerator';\nimport Copyright from './Copyright';", + "title": "Understanding Your UI as a Tree \u2013 React", + "url": "https://react.dev/learn/understanding-your-ui-as-a-tree" + }, + { + "content": "export default function App() {\n return (\n <>\n \n \n \n \n \n );\n}\nReact creates a render tree, a UI tree, composed of the rendered components.\nFrom the example app, we can construct the above render tree.\nThe tree is composed of nodes, each of which represents a component. App, FancyText, Copyright, to name a few, are all nodes in our tree.\nApp\nFancyText", + "title": "Understanding Your UI as a Tree \u2013 React", + "url": "https://react.dev/learn/understanding-your-ui-as-a-tree" + }, + { + "content": "App\nFancyText\nCopyright\nThe 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.\nApp\nYou\u2019ll 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.", + "title": "Understanding Your UI as a Tree \u2013 React", + "url": "https://react.dev/learn/understanding-your-ui-as-a-tree" + }, + { + "content": "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.\nThese 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.", + "title": "Understanding Your UI as a Tree \u2013 React", + "url": "https://react.dev/learn/understanding-your-ui-as-a-tree" + }, + { + "content": "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.\nWe can update the app to conditionally render either an inspirational quote or color.\nimport FancyText from './FancyText';\nimport InspirationGenerator from './InspirationGenerator';\nimport Copyright from './Copyright';", + "title": "Understanding Your UI as a Tree \u2013 React", + "url": "https://react.dev/learn/understanding-your-ui-as-a-tree" + }, + { + "content": "export default function App() {\n return (\n <>\n \n \n \n \n \n );\n}\nWith conditional rendering, across different renders, the render tree may render different components.\nIn this example, depending on what inspiration.type is, we may render or . The render tree may be different for each render pass.\ninspiration.type\n\n", + "title": "Understanding Your UI as a Tree \u2013 React", + "url": "https://react.dev/learn/understanding-your-ui-as-a-tree" + }, + { + "content": "inspiration.type\n\n\nAlthough 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.", + "title": "Understanding Your UI as a Tree \u2013 React", + "url": "https://react.dev/learn/understanding-your-ui-as-a-tree" + }, + { + "content": "Identifying these categories of components are useful for understanding data flow and performance of your app.\nThe Module Dependency Tree\nAnother relationship in a React app that can be modeled with a tree are an app\u2019s 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.\nEach node in a module dependency tree is a module and each branch represents an import statement in that module.\nimport", + "title": "Understanding Your UI as a Tree \u2013 React", + "url": "https://react.dev/learn/understanding-your-ui-as-a-tree" + }, + { + "content": "import\nIf we take the previous Inspirations app, we can build a module dependency tree, or dependency tree for short.\nThe module dependency tree for the Inspirations app.\nThe 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.\nComparing to the render tree of the same app, there are similar structures but some notable differences:\nThe nodes that make-up the tree represent modules, not components.", + "title": "Understanding Your UI as a Tree \u2013 React", + "url": "https://react.dev/learn/understanding-your-ui-as-a-tree" + }, + { + "content": "The nodes that make-up the tree represent modules, not components.\nNon-component modules, like inspirations.js, are also represented in this tree. The render tree only encapsulates components.\ninspirations.js\nCopyright.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.\nCopyright.js", + "title": "Understanding Your UI as a Tree \u2013 React", + "url": "https://react.dev/learn/understanding-your-ui-as-a-tree" + }, + { + "content": "Copyright.js\nApp.js\nCopyright\nInspirationGenerator\nInspirationGenerator\nCopyright\nDependency 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.", + "title": "Understanding Your UI as a Tree \u2013 React", + "url": "https://react.dev/learn/understanding-your-ui-as-a-tree" + }, + { + "content": "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\u2019s dependency tree may help with debugging these issues.\nRecap\nTrees are a common way to represent the relationship between entities. They are often used to model UI.\nRender trees represent the nested relationship between React components across a single render.", + "title": "Understanding Your UI as a Tree \u2013 React", + "url": "https://react.dev/learn/understanding-your-ui-as-a-tree" + }, + { + "content": "Render trees represent the nested relationship between React components across a single render.\nWith conditional rendering, the render tree may change across different renders. With different prop values, components may render different children components.", + "title": "Understanding Your UI as a Tree \u2013 React", + "url": "https://react.dev/learn/understanding-your-ui-as-a-tree" + }, + { + "content": "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.\nDependency trees represent the module dependencies in a React app.\nDependency trees are used by build tools to bundle the necessary code to ship an app.", + "title": "Understanding Your UI as a Tree \u2013 React", + "url": "https://react.dev/learn/understanding-your-ui-as-a-tree" + }, + { + "content": "Dependency trees are used by build tools to bundle the necessary code to ship an app.\nDependency trees are useful for debugging large bundle sizes that slow time to paint and expose opportunities for optimizing what code is bundled.", + "title": "Understanding Your UI as a Tree \u2013 React", + "url": "https://react.dev/learn/understanding-your-ui-as-a-tree" + }, + { + "content": "Updating Arrays in State\nArrays are mutable in JavaScript, but you should treat them as immutable when you store them in state. 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 array.\nYou will learn\nHow to add, remove, or change items in an array in React state\nHow to update an object inside of an array\nHow to make array copying less repetitive with Immer", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "How to update an object inside of an array\nHow to make array copying less repetitive with Immer\nUpdating arrays without mutation\nIn JavaScript, arrays are just another kind of object. Like with objects, you should treat arrays in React state as read-only. This means that you shouldn\u2019t reassign items inside an array like arr[0] = 'bird', and you also shouldn\u2019t use methods that mutate the array, such as push() and pop().\narr[0] = 'bird'\npush()\npop()", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "arr[0] = 'bird'\npush()\npop()\nInstead, every time you want to update an array, you\u2019ll want to pass a new array to your state setting function. To do that, you can create a new array from the original array in your state by calling its non-mutating methods like filter() and map(). Then you can set your state to the resulting new array.\nfilter()\nmap()", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "filter()\nmap()\nHere is a reference table of common array operations. When dealing with arrays inside React state, you will need to avoid the methods in the left column, and instead prefer the methods in the right column:\npush\nunshift\nconcat\n[...arr]\npop\nshift\nsplice\nfilter\nslice\nsplice\narr[i] = ...\nmap\nreverse\nsort\nAlternatively, you can use Immer which lets you use methods from both columns.\nPitfall\nUnfortunately, slice and splice are named similarly but are very different:\nslice\nsplice", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "Pitfall\nUnfortunately, slice and splice are named similarly but are very different:\nslice\nsplice\nslice lets you copy an array or a part of it.\nslice\nsplice mutates the array (to insert or delete items).\nsplice\nIn React, you will be using slice (no p!) a lot more often because you don\u2019t want to mutate objects or arrays in state. Updating Objects explains what mutation is and why it\u2019s not recommended for state.\nslice\np\nAdding to an array\npush() will mutate an array, which you don\u2019t want:\npush()", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "slice\np\nAdding to an array\npush() will mutate an array, which you don\u2019t want:\npush()\nimport { useState } from 'react';", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "let nextId = 0;\n\nexport default function List() {\n const [name, setName] = useState('');\n const [artists, setArtists] = useState([]);", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "return (\n <>\n

                  Inspiring sculptors:

                  \n setName(e.target.value)}\n />\n \n
                    \n {artists.map(artist => (\n
                  • {artist.name}
                  • \n ))}\n
                  \n \n );\n}", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "
                • {artist.name}
                • \n ))}\n
                \n \n );\n}\nInstead, create a new array which contains the existing items and a new item at the end. There are multiple ways to do this, but the easiest one is to use the ... array spread syntax:\n...\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 ]);", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "setArtists( // 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 ]);\nNow it works correctly:\nimport { useState } from 'react';", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "let nextId = 0;\n\nexport default function List() {\n const [name, setName] = useState('');\n const [artists, setArtists] = useState([]);", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "return (\n <>\n

                Inspiring sculptors:

                \n setName(e.target.value)}\n />\n \n
                  \n {artists.map(artist => (\n
                • {artist.name}
                • \n ))}\n
                \n \n );\n}", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "
              • {artist.name}
              • \n ))}\n
              \n \n );\n}\nThe array spread syntax also lets you prepend an item by placing it before the original ...artists:\n...artists\nsetArtists([ { id: nextId++, name: name }, ...artists // Put old items at the end]);\nsetArtists([ { id: nextId++, name: name }, ...artists // Put old items at the end]);", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "setArtists([ { id: nextId++, name: name }, ...artists // Put old items at the end]);\nIn this way, spread can do the job of both push() by adding to the end of an array and unshift() by adding to the beginning of an array. Try it in the sandbox above!\npush()\nunshift()\nRemoving from an array\nThe easiest way to remove an item from an array is to filter it out. In other words, you will produce a new array that will not contain that item. To do this, use the filter method, for example:\nfilter", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "filter\nimport { useState } from 'react';", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "let 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 );", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "return (\n <>\n

              Inspiring sculptors:

              \n
                \n {artists.map(artist => (\n
              • \n {artist.name}{' '}\n \n
              • \n ))}\n
              \n \n );\n}", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "Delete\n \n \n ))}\n
            \n \n );\n}\nClick the \u201cDelete\u201d button a few times, and look at its click handler.\nsetArtists( artists.filter(a => a.id !== artist.id));\nsetArtists( artists.filter(a => a.id !== artist.id));", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "setArtists( artists.filter(a => a.id !== artist.id));\nHere, artists.filter(a => a.id !== artist.id) means \u201ccreate an array that consists of those artists whose IDs are different from artist.id\u201d. In other words, each artist\u2019s \u201cDelete\u201d button will filter that artist out of the array, and then request a re-render with the resulting array. Note that filter does not modify the original array.\nartists.filter(a => a.id !== artist.id)\nartists\nartist.id\nfilter\nTransforming an array", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "artists.filter(a => a.id !== artist.id)\nartists\nartist.id\nfilter\nTransforming an array\nIf you want to change some or all items of the array, you can use map() to create a new array. The function you will pass to map can decide what to do with each item, based on its data or its index (or both).\nmap()\nmap", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "map()\nmap\nIn this example, an array holds coordinates of two circles and a square. When you press the button, it moves only the circles down by 50 pixels. It does this by producing a new array of data using map():\nmap()\nimport { useState } from 'react';", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "let 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 );", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "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 }", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "return (\n <>\n \n {shapes.map(shape => (\n \n ))}\n \n );\n}\nReplacing items in an array", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "height: 20,\n }} />\n ))}\n \n );\n}\nReplacing items in an array\nIt is particularly common to want to replace one or more items in an array. Assignments like arr[0] = 'bird' are mutating the original array, so instead you\u2019ll want to use map for this as well.\narr[0] = 'bird'\nmap", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "arr[0] = 'bird'\nmap\nTo replace an item, create a new array with map. Inside your map call, you will receive the item index as the second argument. Use it to decide whether to return the original item (the first argument) or something else:\nmap\nmap\nimport { useState } from 'react';", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "let 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 }", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "return (\n
              \n {counters.map((counter, i) => (\n
            • \n {counter}\n \n
            • \n ))}\n
            \n );\n}\nInserting into an array", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "\n ))}\n
          \n );\n}\nInserting into an array\nSometimes, you may want to insert an item at a particular position that\u2019s neither at the beginning nor at the end. To do this, you can use the ... array spread syntax together with the slice() method. The slice() method lets you cut a \u201cslice\u201d of the array. To insert an item, you will create an array that spreads the slice before the insertion point, then the new item, and then the rest of the original array.\n...\nslice()\nslice()", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "...\nslice()\nslice()\nIn this example, the Insert button always inserts at the index 1:\n1\nimport { useState } from 'react';", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "let 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 );", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "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 }", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "return (\n <>\n

          Inspiring sculptors:

          \n setName(e.target.value)}\n />\n \n
            \n {artists.map(artist => (\n
          • {artist.name}
          • \n ))}\n
          \n \n );\n}\nMaking other changes to an array", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "))}\n \n \n );\n}\nMaking other changes to an array\nThere are some things you can\u2019t do with the spread syntax and non-mutating methods like map() and filter() alone. For example, you may want to reverse or sort an array. The JavaScript reverse() and sort() methods are mutating the original array, so you can\u2019t use them directly.\nmap()\nfilter()\nreverse()\nsort()\nHowever, you can copy the array first, and then make changes to it.\nFor example:\nimport { useState } from 'react';", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "const 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 }", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "return (\n <>\n \n
            \n {list.map(artwork => (\n
          • {artwork.title}
          • \n ))}\n
          \n \n );\n}\nHere, you use the [...list] spread syntax to create a copy of the original array first. Now that you have a copy, you can use mutating methods like nextList.reverse() or nextList.sort(), or even assign individual items with nextList[0] = \"something\".\n[...list]", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "[...list]\nnextList.reverse()\nnextList.sort()\nnextList[0] = \"something\"\nHowever, even if you copy an array, you can\u2019t mutate existing items inside of it directly. This is because copying is shallow\u2014the new array will contain the same items as the original one. So if you modify an object inside the copied array, you are mutating the existing state. For example, code like this is a problem.\nconst nextList = [...list];nextList[0].seen = true; // Problem: mutates list[0]setList(nextList);", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "const nextList = [...list];nextList[0].seen = true; // Problem: mutates list[0]setList(nextList);\nconst nextList = [...list];nextList[0].seen = true; // Problem: mutates list[0]setList(nextList);", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "const nextList = [...list];nextList[0].seen = true; // Problem: mutates list[0]setList(nextList);\nAlthough nextList and list are two different arrays, nextList[0] and list[0] point to the same object. So by changing nextList[0].seen, you are also changing list[0].seen. This is a state mutation, which you should avoid! You can solve this issue in a similar way to updating nested JavaScript objects\u2014by copying individual items you want to change instead of mutating them. Here\u2019s how.\nnextList\nlist", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "nextList\nlist\nnextList[0]\nlist[0]\nnextList[0].seen\nlist[0].seen\nUpdating objects inside arrays\nObjects are not really located \u201cinside\u201d arrays. They might appear to be \u201cinside\u201d in code, but each object in an array is a separate value, to which the array \u201cpoints\u201d. This is why you need to be careful when changing nested fields like list[0]. Another person\u2019s artwork list may point to the same element of the array!\nlist[0]", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "list[0]\nWhen updating nested state, you need to create copies from the point where you want to update, and all the way up to the top level. Let\u2019s see how this works.\nIn this example, two separate artwork lists have the same initial state. They are supposed to be isolated, but because of a mutation, their state is accidentally shared, and checking a box in one list affects the other list:\nimport { useState } from 'react';", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "let 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 );", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "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 }", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "return (\n <>\n

          Art Bucket List

          \n

          My list of art to see:

          \n \n

          Your list of art to see:

          \n \n \n );\n}", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "function ItemList({ artworks, onToggle }) {\n return (\n
            \n {artworks.map(artwork => (\n
          • \n \n
          • \n ))}\n
          \n );\n}", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "{artwork.title}\n \n \n ))}\n \n );\n}\nThe problem is in code like this:\nconst myNextList = [...myList];const artwork = myNextList.find(a => a.id === artworkId);artwork.seen = nextSeen; // Problem: mutates an existing itemsetMyList(myNextList);\nconst myNextList = [...myList];const artwork = myNextList.find(a => a.id === artworkId);artwork.seen = nextSeen; // Problem: mutates an existing itemsetMyList(myNextList);", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "Although the myNextList array itself is new, the items themselves are the same as in the original myList array. So changing artwork.seen changes the original artwork item. That artwork item is also in yourList, which causes the bug. Bugs like this can be difficult to think about, but thankfully they disappear if you avoid mutating state.\nmyNextList\nmyList\nartwork.seen\nyourList\nYou can use map to substitute an old item with its updated version without mutation.\nmap", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "yourList\nYou can use map to substitute an old item with its updated version without mutation.\nmap\nsetMyList(myList.map(artwork => { if (artwork.id === artworkId) { // Create a *new* object with changes return { ...artwork, seen: nextSeen }; } else { // No changes return artwork; }}));", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "setMyList(myList.map(artwork => { if (artwork.id === artworkId) { // Create a *new* object with changes return { ...artwork, seen: nextSeen }; } else { // No changes return artwork; }}));\nHere, ... is the object spread syntax used to create a copy of an object.\n...\nWith this approach, none of the existing state items are being mutated, and the bug is fixed:\nimport { useState } from 'react';", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "let 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 );", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "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 }", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "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 }", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "return (\n <>\n

          Art Bucket List

          \n

          My list of art to see:

          \n \n

          Your list of art to see:

          \n \n \n );\n}", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "function ItemList({ artworks, onToggle }) {\n return (\n
            \n {artworks.map(artwork => (\n
          • \n \n
          • \n ))}\n
          \n );\n}", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "{artwork.title}\n \n \n ))}\n \n );\n}\nIn general, you should only mutate objects that you have just created. If you were inserting a new artwork, you could mutate it, but if you\u2019re dealing with something that\u2019s already in state, you need to make a copy.\nWrite concise update logic with Immer\nUpdating nested arrays without mutation can get a little bit repetitive. Just as with objects:", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "Updating nested arrays without mutation can get a little bit repetitive. Just as with objects:\nGenerally, you shouldn\u2019t need to update state more than a couple of levels deep. If your state objects are very deep, you might want to restructure them differently so that they are flat.\nIf you don\u2019t want to change your state structure, you might prefer to use Immer, which lets you write using the convenient but mutating syntax and takes care of producing the copies for you.", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "Here is the Art Bucket List example rewritten with Immer:\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}\nNote how with Immer, mutation like artwork.seen = nextSeen is now okay:", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "\"devDependencies\": {}\n}\nNote how with Immer, mutation like artwork.seen = nextSeen is now okay:\nartwork.seen = nextSeen\nupdateMyTodos(draft => { const artwork = draft.find(a => a.id === artworkId); artwork.seen = nextSeen;});\nupdateMyTodos(draft => { const artwork = draft.find(a => a.id === artworkId); artwork.seen = nextSeen;});", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "This is because you\u2019re not mutating the original state, but you\u2019re mutating a special draft object provided by Immer. Similarly, you can apply mutating methods like push() and pop() to the content of the draft.\ndraft\npush()\npop()\ndraft\nBehind the scenes, Immer always constructs the next state from scratch according to the changes that you\u2019ve done to the draft. This keeps your event handlers very concise without ever mutating state.\ndraft\nRecap", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "draft\nRecap\nYou can put arrays into state, but you can\u2019t change them.\nInstead of mutating an array, create a new version of it, and update the state to it.\nYou can use the [...arr, newItem] array spread syntax to create arrays with new items.\n[...arr, newItem]\nYou can use filter() and map() to create new arrays with filtered or transformed items.\nfilter()\nmap()\nYou can use Immer to keep your code concise.\nTry out some challenges", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "filter()\nmap()\nYou can use Immer to keep your code concise.\nTry out some challenges\nFill in the handleIncreaseClick logic so that pressing \u201d+\u201d increases the corresponding number:\nhandleIncreaseClick\nimport { useState } from 'react';", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "const 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 }", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "function handleIncreaseClick(productId) {\n\n }\n\n return (\n
            \n {products.map(product => (\n
          • \n {product.name}\n {' '}\n ({product.count})\n \n
          • \n ))}\n
          \n );\n}", + "title": "Updating Arrays in State \u2013 React", + "url": "https://react.dev/learn/updating-arrays-in-state" + }, + { + "content": "Preserving and Resetting State\nState 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.\nYou will learn\nWhen React chooses to preserve or reset the state\nHow to force React to reset component\u2019s state\nHow keys and types affect whether the state is preserved\nState is tied to a position in the render tree", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "State is tied to a position in the render tree\nReact builds render trees for the component structure in your UI.\nWhen you give a component state, you might think the state \u201clives\u201d inside the component. But the state is actually held inside React. React associates each piece of state it\u2019s holding with the correct component by where that component sits in the render tree.\nHere, there is only one JSX tag, but it\u2019s rendered at two different positions:\n", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "\nimport { useState } from 'react';", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "export default function App() {\n const counter = ;\n return (\n
          \n {counter}\n {counter}\n
          \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 }", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "return (\n setHover(true)}\n onPointerLeave={() => setHover(false)}\n >\n

          {score}

          \n \n \n );\n}\nHere\u2019s how these look as a tree:\nReact tree", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "Add one\n \n \n );\n}\nHere\u2019s how these look as a tree:\nReact tree\nThese are two separate counters because each is rendered at its own position in the tree. You don\u2019t usually have to think about these positions to use React, but it can be useful to understand how it works.\nIn 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.", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "Counter\nscore\nhover\nTry clicking both counters and notice they don\u2019t affect each other:\nimport { useState } from 'react';", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "export default function App() {\n return (\n
          \n \n \n
          \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 }", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "return (\n setHover(true)}\n onPointerLeave={() => setHover(false)}\n >\n

          {score}

          \n \n \n );\n}\nAs you can see, when one counter is updated, only the state for that component is updated:\nUpdating state", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "Updating state\nReact 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 \u201cRender the second counter\u201d checkbox, and then add it back by ticking it again:\nimport { useState } from 'react';", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "export default function App() {\n const [showB, setShowB] = useState(true);\n return (\n
          \n \n {showB && } \n \n
          \n );\n}\n\nfunction Counter() {\n const [score, setScore] = useState(0);\n const [hover, setHover] = useState(false);", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "let className = 'counter';\n if (hover) {\n className += ' hover';\n }", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "return (\n setHover(true)}\n onPointerLeave={() => setHover(false)}\n >\n

          {score}

          \n \n \n );\n}\nNotice how the moment you stop rendering the second counter, its state disappears completely. That\u2019s because when React removes a component, it destroys its state.\nDeleting a component", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "Deleting a component\nWhen you tick \u201cRender the second counter\u201d, a second Counter and its state are initialized from scratch (score = 0) and added to the DOM.\nCounter\nscore = 0\nAdding a component\nReact preserves a component\u2019s state for as long as it\u2019s 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.\nSame component at the same position preserves state", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "Same component at the same position preserves state\nIn this example, there are two different tags:\n\nimport { useState } from 'react';", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "export default function App() {\n const [isFancy, setIsFancy] = useState(false);\n return (\n
          \n {isFancy ? (\n \n ) : (\n \n )}\n \n
          \n );\n}", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "function 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 }", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "return (\n setHover(true)}\n onPointerLeave={() => setHover(false)}\n >\n

          {score}

          \n \n \n );\n}\nWhen you tick or clear the checkbox, the counter state does not get reset. Whether isFancy is true or false, you always have a as the first child of the div returned from the root App component:\nisFancy\ntrue\nfalse", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "isFancy\ntrue\nfalse\n\ndiv\nApp\nUpdating the App state does not reset the Counter because Counter stays in the same position\nApp\nCounter\nCounter\nIt\u2019s the same component at the same position, so from React\u2019s perspective, it\u2019s the same counter.\nPitfall\nRemember that it\u2019s the position in the UI tree\u2014not in the JSX markup\u2014that matters to React! This component has two return clauses with different JSX tags inside and outside the if:\nreturn\n\nif", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "return\n\nif\nimport { useState } from 'react';", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "export default function App() {\n const [isFancy, setIsFancy] = useState(false);\n if (isFancy) {\n return (\n
          \n \n \n
          \n );\n }\n return (\n
          \n \n
          \n );\n }\n return (\n
          \n \n \n
          \n );\n}", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "function 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 }", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "return (\n setHover(true)}\n onPointerLeave={() => setHover(false)}\n >\n

          {score}

          \n \n \n );\n}", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "Add one\n \n \n );\n}\nYou might expect the state to reset when you tick checkbox, but it doesn\u2019t! This is because both of these tags are rendered at the same position. React doesn\u2019t know where you place the conditions in your function. All it \u201csees\u201d is the tree you return.\n", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "\nIn both cases, the App component returns a
          with as a first child. To React, these two counters have the same \u201caddress\u201d: 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.\nApp\n
          \n\nDifferent components at the same position reset state\nIn this example, ticking the checkbox will replace with a

          :\n\n

          ", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "In this example, ticking the checkbox will replace with a

          :\n\n

          \nimport { useState } from 'react';", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "export default function App() {\n const [isPaused, setIsPaused] = useState(false);\n return (\n

          \n {isPaused ? (\n

          See you later!

          \n ) : (\n \n )}\n \n
          \n );\n}", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "function 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 }", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "return (\n setHover(true)}\n onPointerLeave={() => setHover(false)}\n >\n

          {score}

          \n \n
          \n );\n}\nHere, you switch between different component types at the same position. Initially, the first child of the
          contained a Counter. But when you swapped in a p, React removed the Counter from the UI tree and destroyed its state.", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "
          \nCounter\np\nCounter\nWhen Counter changes to p, the Counter is deleted and the p is added\nCounter\np\nCounter\np\nWhen switching back, the p is deleted and the Counter is added\np\nCounter\nAlso, 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 checkbox:\nimport { useState } from 'react';", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "export default function App() {\n const [isFancy, setIsFancy] = useState(false);\n return (\n
          \n {isFancy ? (\n
          \n \n
          \n ) : (\n
          \n \n
          \n )}\n \n
          \n );\n}", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "function 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 }", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "return (\n setHover(true)}\n onPointerLeave={() => setHover(false)}\n >\n

          {score}

          \n \n
          \n );\n}", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "Add one\n \n
          \n );\n}\nThe 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.\nCounter\ndiv\nsection\ndiv\nsection\nCounter\nWhen section changes to div, the section is deleted and the new div is added\nsection\ndiv\nsection\ndiv", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "section\ndiv\nsection\ndiv\nWhen switching back, the div is deleted and the new section is added\ndiv\nsection\nAs a rule of thumb, if you want to preserve the state between re-renders, the structure of your tree needs to \u201cmatch up\u201d 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.\nPitfall\nThis is why you should not nest component function definitions.", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "Pitfall\nThis is why you should not nest component function definitions.\nHere, the MyTextField component function is defined inside MyComponent:\nMyTextField\nMyComponent\nimport { useState } from 'react';", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "export default function MyComponent() {\n const [counter, setCounter] = useState(0);\n\n function MyTextField() {\n const [text, setText] = useState('');\n\n return (\n setText(e.target.value)}\n />\n );\n }", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "return (\n <>\n \n \n \n );\n}", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "setCounter(counter + 1)\n }}>Clicked {counter} times\n \n );\n}\nEvery time you click the button, the input state disappears! This is because a different MyTextField function is created for every render of MyComponent. You\u2019re 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\u2019t nest their definitions.", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "MyTextField\nMyComponent\nResetting state at the same position\nBy 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\u2019s state. Consider this app that lets two players keep track of their scores during each turn:\nimport { useState } from 'react';", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "export default function Scoreboard() {\n const [isPlayerA, setIsPlayerA] = useState(true);\n return (\n
          \n {isPlayerA ? (\n \n ) : (\n \n )}\n \n
          \n );\n}\n\nfunction Counter({ person }) {\n const [score, setScore] = useState(0);\n const [hover, setHover] = useState(false);", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "let className = 'counter';\n if (hover) {\n className += ' hover';\n }", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "return (\n setHover(true)}\n onPointerLeave={() => setHover(false)}\n >\n

          {person}'s score: {score}

          \n \n
          \n );\n}\nCurrently, 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.\nCounter\nCounter\nperson", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "Counter\nCounter\nperson\nBut 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.\nThere are two ways to reset state when switching between them:\nRender components in different positions\nGive each component an explicit identity with key\nkey\nOption 1: Rendering a component in different positions", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "key\nOption 1: Rendering a component in different positions\nIf you want these two Counters to be independent, you can render them in two different positions:\nCounter\nimport { useState } from 'react';", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "export default function Scoreboard() {\n const [isPlayerA, setIsPlayerA] = useState(true);\n return (\n
          \n {isPlayerA &&\n \n }\n {!isPlayerA &&\n \n }\n \n
          \n );\n}\n\nfunction Counter({ person }) {\n const [score, setScore] = useState(0);\n const [hover, setHover] = useState(false);", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "let className = 'counter';\n if (hover) {\n className += ' hover';\n }", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "return (\n setHover(true)}\n onPointerLeave={() => setHover(false)}\n >\n

          {person}'s score: {score}

          \n \n \n );\n}\nInitially, isPlayerA is true. So the first position contains Counter state, and the second one is empty.\nisPlayerA\ntrue\nCounter", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "isPlayerA\ntrue\nCounter\nWhen you click the \u201cNext player\u201d button the first position clears but the second one now contains a Counter.\nCounter\nInitial state\nClicking \u201cnext\u201d\nClicking \u201cnext\u201d again\nEach Counter\u2019s state gets destroyed each time it\u2019s removed from the DOM. This is why they reset every time you click the button.\nCounter", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "Counter\nThis 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\u2019s not a hassle to render both separately in the JSX.\nOption 2: Resetting state with a key\nThere is also another, more generic, way to reset a component\u2019s state.", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "You might have seen keys when rendering lists. Keys aren\u2019t just for lists! You can use keys to make React distinguish between any components. By default, React uses order within the parent (\u201cfirst counter\u201d, \u201csecond counter\u201d) 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\u2014for example, Taylor\u2019s counter. This way, React will know Taylor\u2019s counter wherever it appears in the tree!\nkey", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "key\nIn this example, the two s don\u2019t share state even though they appear in the same place in JSX:\n\nimport { useState } from 'react';", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "export default function Scoreboard() {\n const [isPlayerA, setIsPlayerA] = useState(true);\n return (\n
          \n {isPlayerA ? (\n \n ) : (\n \n )}\n \n
          \n );\n}\n\nfunction Counter({ person }) {\n const [score, setScore] = useState(0);\n const [hover, setHover] = useState(false);", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "let className = 'counter';\n if (hover) {\n className += ' hover';\n }", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "return (\n setHover(true)}\n onPointerLeave={() => setHover(false)}\n >\n

          {person}'s score: {score}

          \n \n \n );\n}\nSwitching between Taylor and Sarah does not preserve the state. This is because you gave them different keys:\nkey", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "key\n{isPlayerA ? ( ) : ( )}\n{isPlayerA ? ( ) : ( )}", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "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.\nkey\nkey\nNote", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "key\nkey\nNote\nRemember that keys are not globally unique. They only specify the position within the parent.\nResetting a form with a key\nResetting state with a key is particularly useful when dealing with forms.\nIn this chat app, the component contains the text input state:\n\nimport { useState } from 'react';\nimport Chat from './Chat.js';\nimport ContactList from './ContactList.js';", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "export default function Messenger() {\n const [to, setTo] = useState(contacts[0]);\n return (\n
          \n setTo(contact)}\n />\n \n
          \n )\n}", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "const 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];\nTry entering something into the input, and then press \u201cAlice\u201d or \u201cBob\u201d to choose a different recipient. You will notice that the input state is preserved because the is rendered at the same position in the tree.\n", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "\nIn many apps, this may be the desired behavior, but not in a chat app! You don\u2019t 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:\nkey\n\n", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "key\n\n\nThis 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.\nChat\nNow switching the recipient always clears the text field:\nimport { useState } from 'react';\nimport Chat from './Chat.js';\nimport ContactList from './ContactList.js';", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "export default function Messenger() {\n const [to, setTo] = useState(contacts[0]);\n return (\n
          \n setTo(contact)}\n />\n \n
          \n )\n}", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "const 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];\nIn a real chat app, you\u2019d probably want to recover the input state when the user selects the previous recipient again. There are a few ways to keep the state \u201calive\u201d for a component that\u2019s no longer visible:", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "You 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.", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "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\u2019t matter, because it\u2019s the parent that keeps the important information. This is the most common solution.", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "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.\nChat\nlocalStorage", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "Chat\nlocalStorage\nNo 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 tree based on the current recipient.\nkey\n\nRecap\nReact keeps state for as long as the same component is rendered at the same position.\nState is not kept in JSX tags. It\u2019s associated with the tree position in which you put that JSX.\nYou can force a subtree to reset its state by giving it a different key.", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "You can force a subtree to reset its state by giving it a different key.\nDon\u2019t nest component definitions, or you\u2019ll reset state by accident.\nTry out some challenges\nThis 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.\nimport { useState } from 'react';", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "export default function App() {\n const [showHint, setShowHint] = useState(false);\n if (showHint) {\n return (\n
          \n

          Hint: Your favorite city?

          \n
          \n \n
          \n );\n }\n return (\n
          \n \n \n
          \n );\n}", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "function Form() {\n const [text, setText] = useState('');\n return (\n setText(e.target.value)}\n />\n );\n}", + "title": "Preserving and Resetting State \u2013 React", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "content": "Render and Commit\nBefore 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.\nYou will learn\nWhat rendering means in React\nWhen and why React renders a component\nThe steps involved in displaying a component on screen\nWhy rendering does not always produce a DOM update", + "title": "Render and Commit \u2013 React", + "url": "https://react.dev/learn/render-and-commit" + }, + { + "content": "Why rendering does not always produce a DOM update\nImagine 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 steps:\nTriggering a render (delivering the guest\u2019s order to the kitchen)\nRendering the component (preparing the order in the kitchen)\nCommitting to the DOM (placing the order on the table)", + "title": "Render and Commit \u2013 React", + "url": "https://react.dev/learn/render-and-commit" + }, + { + "content": "Committing to the DOM (placing the order on the table)\nTrigger\nRender\nCommit\nIllustrated by Rachel Lee Nabors\nStep 1: Trigger a render\nThere are two reasons for a component to render:\nIt\u2019s the component\u2019s initial render.\nThe component\u2019s (or one of its ancestors\u2019) state has been updated.\nInitial render", + "title": "Render and Commit \u2013 React", + "url": "https://react.dev/learn/render-and-commit" + }, + { + "content": "The component\u2019s (or one of its ancestors\u2019) state has been updated.\nInitial render\nWhen your app starts, you need to trigger the initial render. Frameworks and sandboxes sometimes hide this code, but it\u2019s done by calling createRoot with the target DOM node, and then calling its render method with your component:\ncreateRoot\nrender\nimport Image from './Image.js';\nimport { createRoot } from 'react-dom/client';", + "title": "Render and Commit \u2013 React", + "url": "https://react.dev/learn/render-and-commit" + }, + { + "content": "const root = createRoot(document.getElementById('root'))\nroot.render();\nTry commenting out the root.render() call and see the component disappear!\nroot.render()\nRe-renders when state updates", + "title": "Render and Commit \u2013 React", + "url": "https://react.dev/learn/render-and-commit" + }, + { + "content": "root.render()\nRe-renders when state updates\nOnce the component has been initially rendered, you can trigger further renders by updating its state with the set function. Updating your component\u2019s 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.)\nset\nState update...\n...triggers...\n...render!\nIllustrated by Rachel Lee Nabors", + "title": "Render and Commit \u2013 React", + "url": "https://react.dev/learn/render-and-commit" + }, + { + "content": "set\nState update...\n...triggers...\n...render!\nIllustrated by Rachel Lee Nabors\nStep 2: React renders your components\nAfter you trigger a render, React calls your components to figure out what to display on screen. \u201cRendering\u201d is React calling your components.\nOn initial render, React will call the root component.\nFor subsequent renders, React will call the function component whose state update triggered the render.", + "title": "Render and Commit \u2013 React", + "url": "https://react.dev/learn/render-and-commit" + }, + { + "content": "This process is recursive: if 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.\nIn the following example, React will call Gallery() and Image() several times:\nGallery()\nImage()\nexport default function Gallery() {\n return (\n
          ", + "title": "Render and Commit \u2013 React", + "url": "https://react.dev/learn/render-and-commit" + }, + { + "content": "Gallery()\nImage()\nexport default function Gallery() {\n return (\n
          \n

          Inspiring Sculptures

          \n \n \n \n
          \n );\n}", + "title": "Render and Commit \u2013 React", + "url": "https://react.dev/learn/render-and-commit" + }, + { + "content": "function Image() {\n return (\n \n );\n}\nDuring the initial render, React will create the DOM nodes for
          ,

          , and three tags.\n
          \n

          \n", + "title": "Render and Commit \u2013 React", + "url": "https://react.dev/learn/render-and-commit" + }, + { + "content": "
          \n

          \n\nDuring a re-render, React will calculate which of their properties, if any, have changed since the previous render. It won\u2019t do anything with that information until the next step, the commit phase.\nPitfall\nRendering must always be a pure calculation:\nSame 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!)", + "title": "Render and Commit \u2013 React", + "url": "https://react.dev/learn/render-and-commit" + }, + { + "content": "It minds its own business. It should not change any objects or variables that existed before rendering. (One order should not change anyone else\u2019s order.)\nOtherwise, you can encounter confusing bugs and unpredictable behavior as your codebase grows in complexity. When developing in \u201cStrict Mode\u201d, React calls each component\u2019s function twice, which can help surface mistakes caused by impure functions.", + "title": "Render and Commit \u2013 React", + "url": "https://react.dev/learn/render-and-commit" + }, + { + "content": "The 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\u2019t optimize prematurely!\nStep 3: React commits changes to the DOM\nAfter rendering (calling) your components, React will modify the DOM.", + "title": "Render and Commit \u2013 React", + "url": "https://react.dev/learn/render-and-commit" + }, + { + "content": "After rendering (calling) your components, React will modify the DOM.\nFor the initial render, React will use the appendChild() DOM API to put all the DOM nodes it has created on screen.\nappendChild()\nFor re-renders, React will apply the minimal necessary operations (calculated while rendering!) to make the DOM match the latest rendering output.", + "title": "Render and Commit \u2013 React", + "url": "https://react.dev/learn/render-and-commit" + }, + { + "content": "React only changes the DOM nodes if there\u2019s 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 , updating its value, but the text doesn\u2019t disappear when the component re-renders:\n\nvalue\nexport default function Clock({ time }) {\n return (\n <>\n

          {time}

          \n \n \n );\n}", + "title": "Render and Commit \u2013 React", + "url": "https://react.dev/learn/render-and-commit" + }, + { + "content": "return (\n <>\n

          {time}

          \n \n \n );\n}\nThis works because during this last step, React only updates the content of

          with the new time. It sees that the appears in the JSX in the same place as last time, so React doesn\u2019t touch the \u2014or its value!\n

          \ntime\n\n\nvalue\nEpilogue: Browser paint", + "title": "Render and Commit \u2013 React", + "url": "https://react.dev/learn/render-and-commit" + }, + { + "content": "

          \ntime\n\n\nvalue\nEpilogue: Browser paint\nAfter rendering is done and React updated the DOM, the browser will repaint the screen. Although this process is known as \u201cbrowser rendering\u201d, we\u2019ll refer to it as \u201cpainting\u201d to avoid confusion throughout the docs.\nIllustrated by Rachel Lee Nabors\nRecap\nAny screen update in a React app happens in three steps:", + "title": "Render and Commit \u2013 React", + "url": "https://react.dev/learn/render-and-commit" + }, + { + "content": "Trigger\nRender\nCommit\nTrigger\nRender\nCommit\nYou can use Strict Mode to find mistakes in your components\nReact does not touch the DOM if the rendering result is the same as last time", + "title": "Render and Commit \u2013 React", + "url": "https://react.dev/learn/render-and-commit" + }, + { + "content": "Build a React app from Scratch\nIf 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.", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "Starting 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.", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "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.", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "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.", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "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\u2019re confident that you will never need these features.\nFor a list of recommended frameworks, check out Creating a React App.\nStep 1: Install a build tool", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "For a list of recommended frameworks, check out Creating a React App.\nStep 1: Install a build tool\nThe 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.\nvite\nparcel\nrsbuild\nVite\nVite is a build tool that aims to provide a faster and leaner development experience for modern web projects.", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "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\u2019s React plugin or React SWC plugin and React SSR example project to get started.\nVite is already being used as a build tool in one of our recommended frameworks: React Router.\nParcel", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "Parcel\nParcel 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.\nParcel supports fast refresh, JSX, TypeScript, Flow, and styling out of the box. See Parcel\u2019s React recipe to get started.\nRsbuild", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "Rsbuild\nRsbuild 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.\nRsbuild includes built-in support for React features like fast refresh, JSX, TypeScript, and styling. See Rsbuild\u2019s React guide to get started.\nNote", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "Note\nIf you\u2019re starting from scratch with React Native you\u2019ll 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.\nStep 2: Build Common Application Patterns", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "Step 2: Build Common Application Patterns\nThe build tools listed above start off with a client-only, single-page app (SPA), but don\u2019t include any further solutions for common functionality like routing, data fetching, or styling.\nThe React ecosystem includes many tools for these problems. We\u2019ve listed a few that are widely used as a starting point, but feel free to choose other tools if those work better for you.\nRouting", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "Routing\nRouting 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\u2019ll 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.", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "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).\nWe suggest using:\nReact Router\nTanstack Router\nData Fetching", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "We suggest using:\nReact Router\nTanstack Router\nData Fetching\nFetching 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.", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "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.", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "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\u2019s data to be fetched all at once as the page is being displayed.\nIf you\u2019re fetching data from most backends or REST-style APIs, we suggest using:\nReact Query\nSWR\nRTK Query\nIf you\u2019re fetching data from a GraphQL API, we suggest using:\nApollo\nRelay\nCode-splitting", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "Code-splitting\nCode-splitting is the process of breaking your app into smaller bundles that can be loaded on demand. An app\u2019s 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.", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "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 waterfall: rather", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "data after it has been initially rendered you are now waiting twice. This is a waterfall: rather 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.", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "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).\nFor code-splitting instructions, see your build tool docs:\nVite build optimizations\nParcel code splitting\nRsbuild code splitting\nImproving Application Performance", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "Parcel code splitting\nRsbuild code splitting\nImproving Application Performance\nSince the build tool you select only support single page apps (SPAs) you\u2019ll 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\u2019t need these features at first, in the future there may be some routes that would benefit SSR, SSG or RSC.", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "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.", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "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.", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "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\u2019s SSR guide.", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "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\u2019s SSR guide.", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "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\u2019s SSG guide.\nStatic 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\u2019s SSG guide.", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "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\u2019s RSC examples.\nReact 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\u2019s RSC examples.", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "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.", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "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).\nAnd more\u2026", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "And more\u2026\nThese are just a few examples of the features a new app will need to consider when building from scratch. Many limitations you\u2019ll 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.\nIf you don\u2019t want to solve these problems on your own, you can get started with a framework that provides these features out of the box.", + "title": "Build a React app from Scratch \u2013 React", + "url": "https://react.dev/learn/build-a-react-app-from-scratch" + }, + { + "content": "State as a Snapshot\nState variables might look like regular JavaScript variables that you can read and write to. However, state behaves more like a snapshot. Setting it does not change the state variable you already have, but instead triggers a re-render.\nYou will learn\nHow setting state triggers re-renders\nWhen and how state updates\nWhy state does not update immediately after you set it\nHow event handlers access a \u201csnapshot\u201d of the state\nSetting state triggers renders", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "How event handlers access a \u201csnapshot\u201d of the state\nSetting state triggers renders\nYou might think of your user interface as changing directly in response to the user event like a click. In React, it works a little differently from this mental model. On the previous page, you saw that setting state requests a re-render from React. This means that for an interface to react to the event, you need to update the state.", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "In this example, when you press \u201csend\u201d, setIsSent(true) tells React to re-render the UI:\nsetIsSent(true)\nimport { useState } from 'react';", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "export default function Form() {\n const [isSent, setIsSent] = useState(false);\n const [message, setMessage] = useState('Hi!');\n if (isSent) {\n return

          Your message is on its way!

          \n }\n return (\n {\n e.preventDefault();\n setIsSent(true);\n sendMessage(message);\n }}>\n setMessage(e.target.value)}\n />\n ", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "/>\n \n \n );\n}", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "function sendMessage(message) {\n // ...\n}\nHere\u2019s what happens when you click the button:\nThe onSubmit event handler executes.\nonSubmit\nsetIsSent(true) sets isSent to true and queues a new render.\nsetIsSent(true)\nisSent\ntrue\nReact re-renders the component according to the new isSent value.\nisSent\nLet\u2019s take a closer look at the relationship between state and rendering.\nRendering takes a snapshot in time", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "Rendering takes a snapshot in time\n\u201cRendering\u201d means that React is calling your component, which is a function. The JSX you return from that function is like a snapshot of the UI in time. Its props, event handlers, and local variables were all calculated using its state at the time of the render.", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "Unlike a photograph or a movie frame, the UI \u201csnapshot\u201d you return is interactive. It includes logic like event handlers that specify what happens in response to inputs. React updates the screen to match this snapshot and connects the event handlers. As a result, pressing a button will trigger the click handler from your JSX.\nWhen React re-renders a component:\nReact calls your function again.\nYour function returns a new JSX snapshot.", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "React calls your function again.\nYour function returns a new JSX snapshot.\nReact then updates the screen to match the snapshot your function returned.\nReact executing the function\nCalculating the snapshot\nUpdating the DOM tree\nIllustrated by Rachel Lee Nabors", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "Updating the DOM tree\nIllustrated by Rachel Lee Nabors\nAs a component\u2019s memory, state is not like a regular variable that disappears after your function returns. State actually \u201clives\u201d in React itself\u2014as if on a shelf!\u2014outside of your function. When React calls your component, it gives you a snapshot of the state for that particular render. Your component returns a snapshot of the UI with a fresh set of props and event handlers in its JSX, all calculated using the state values from that render!", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "You tell React to update the state\nReact updates the state value\nReact passes a snapshot of the state value into the component\nIllustrated by Rachel Lee Nabors\nHere\u2019s a little experiment to show you how this works. In this example, you might expect that clicking the \u201c+3\u201d button would increment the counter three times because it calls setNumber(number + 1) three times.\nsetNumber(number + 1)\nSee what happens when you click the \u201c+3\u201d button:\nimport { useState } from 'react';", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "export default function Counter() {\n const [number, setNumber] = useState(0);", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "return (\n <>\n

          {number}

          \n \n \n )\n}\nNotice that number only increments once per click!\nnumber\nSetting state only changes it for the next render. During the first render, number was 0. This is why, in that render\u2019s onClick handler, the value of number is still 0 even after setNumber(number + 1) was called:\nnumber\n0\nonClick\nnumber\n0", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "number\n0\nonClick\nnumber\n0\nsetNumber(number + 1)\n\n\nHere is what this button\u2019s click handler tells React to do:\nsetNumber(number + 1): number is 0 so setNumber(0 + 1).", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "React prepares to change number to 1 on the next render.\nsetNumber(number + 1)\nnumber\n0\nsetNumber(0 + 1)\nReact prepares to change number to 1 on the next render.\nnumber\n1\nsetNumber(number + 1): number is 0 so setNumber(0 + 1).\n\nReact prepares to change number to 1 on the next render.\nsetNumber(number + 1)\nnumber\n0\nsetNumber(0 + 1)\nReact prepares to change number to 1 on the next render.\nnumber\n1\nsetNumber(number + 1): number is 0 so setNumber(0 + 1).", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "React prepares to change number to 1 on the next render.\nsetNumber(number + 1)\nnumber\n0\nsetNumber(0 + 1)\nReact prepares to change number to 1 on the next render.\nnumber\n1\nEven though you called setNumber(number + 1) three times, in this render\u2019s event handler number is always 0, so you set the state to 1 three times. This is why, after your event handler finishes, React re-renders the component with number equal to 1 rather than 3.\nsetNumber(number + 1)\nnumber\n0\n1\nnumber\n1\n3", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "setNumber(number + 1)\nnumber\n0\n1\nnumber\n1\n3\nYou can also visualize this by mentally substituting state variables with their values in your code. Since the number state variable is 0 for this render, its event handler looks like this:\nnumber\n0\n\n", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "\nFor the next render, number is 1, so that render\u2019s click handler looks like this:\nnumber\n1\n\n\nThis is why clicking the button again will set the counter to 2, then to 3 on the next click, and so on.\n2\n3", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "2\n3\nState over time\nWell, that was fun. Try to guess what clicking this button will alert:\nimport { useState } from 'react';", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "export default function Counter() {\n const [number, setNumber] = useState(0);", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "return (\n <>\n

          {number}

          \n \n \n )\n}\nIf you use the substitution method from before, you can guess that the alert shows \u201c0\u201d:\nsetNumber(0 + 5);alert(0);\nsetNumber(0 + 5);alert(0);\nBut what if you put a timer on the alert, so it only fires after the component re-rendered? Would it say \u201c0\u201d or \u201c5\u201d? Have a guess!\nimport { useState } from 'react';", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "export default function Counter() {\n const [number, setNumber] = useState(0);", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "return (\n <>\n

          {number}

          \n \n \n )\n}\nSurprised? If you use the substitution method, you can see the \u201csnapshot\u201d of the state passed to the alert.\nsetNumber(0 + 5);setTimeout(() => { alert(0);}, 3000);\nsetNumber(0 + 5);setTimeout(() => { alert(0);}, 3000);", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "setNumber(0 + 5);setTimeout(() => { alert(0);}, 3000);\nThe state stored in React may have changed by the time the alert runs, but it was scheduled using a snapshot of the state at the time the user interacted with it!", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "A state variable\u2019s value never changes within a render, even if its event handler\u2019s code is asynchronous. Inside that render\u2019s onClick, the value of number continues to be 0 even after setNumber(number + 5) was called. Its value was \u201cfixed\u201d when React \u201ctook the snapshot\u201d of the UI by calling your component.\nonClick\nnumber\n0\nsetNumber(number + 5)", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "onClick\nnumber\n0\nsetNumber(number + 5)\nHere is an example of how that makes your event handlers less prone to timing mistakes. Below is a form that sends a message with a five-second delay. Imagine this scenario:\nYou press the \u201cSend\u201d button, sending \u201cHello\u201d to Alice.\nBefore the five-second delay ends, you change the value of the \u201cTo\u201d field to \u201cBob\u201d.", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "Before the five-second delay ends, you change the value of the \u201cTo\u201d field to \u201cBob\u201d.\nWhat do you expect the alert to display? Would it display, \u201cYou said Hello to Alice\u201d? Or would it display, \u201cYou said Hello to Bob\u201d? Make a guess based on what you know, and then try it:\nalert\nimport { useState } from 'react';", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "export 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 }", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "return (\n
          \n \n setMessage(e.target.value)}\n />\n \n \n );\n}", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "/>\n \n \n );\n}\nReact keeps the state values \u201cfixed\u201d within one render\u2019s event handlers. You don\u2019t need to worry whether the state has changed while the code is running.\nBut what if you wanted to read the latest state before a re-render? You\u2019ll want to use a state updater function, covered on the next page!\nRecap\nSetting state requests a new render.\nReact stores state outside of your component, as if on a shelf.", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "React stores state outside of your component, as if on a shelf.\nWhen you call useState, React gives you a snapshot of the state for that render.\nuseState\nVariables and event handlers don\u2019t \u201csurvive\u201d re-renders. Every render has its own event handlers.\nEvery render (and functions inside it) will always \u201csee\u201d the snapshot of the state that React gave to that render.\nYou can mentally substitute state in event handlers, similarly to how you think about the rendered JSX.", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "Event handlers created in the past have the state values from the render in which they were created.\nTry out some challenges\nHere is a crosswalk light component that toggles when the button is pressed:\nimport { useState } from 'react';", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "export default function TrafficLight() {\n const [walk, setWalk] = useState(true);\n\n function handleClick() {\n setWalk(!walk);\n }", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "return (\n <>\n \n

          \n {walk ? 'Walk' : 'Stop'}\n

          \n \n );\n}\nAdd an alert to the click handler. When the light is green and says \u201cWalk\u201d, clicking the button should say \u201cStop is next\u201d. When the light is red and says \u201cStop\u201d, clicking the button should say \u201cWalk is next\u201d.\nalert", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "alert\nDoes it make a difference whether you put the alert before or after the setWalk call?\nalert\nsetWalk", + "title": "State as a Snapshot \u2013 React", + "url": "https://react.dev/learn/state-as-a-snapshot" + }, + { + "content": "Sharing State Between Components\nSometimes, 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\u2019s one of the most common things you will do writing React code.\nYou will learn\nHow to share state between components by lifting it up\nWhat are controlled and uncontrolled components\nLifting state up by example", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "What are controlled and uncontrolled components\nLifting state up by example\nIn this example, a parent Accordion component renders two separate Panels:\nAccordion\nPanel\nAccordion", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "Panel\nPanel\nAccordion\nPanel\nPanel\nPanel\nPanel\nEach Panel component has a boolean isActive state that determines whether its content is visible.\nPanel\nisActive\nPress the Show button for both panels:\nimport { useState } from 'react';", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "function Panel({ title, children }) {\n const [isActive, setIsActive] = useState(false);\n return (\n
          \n

          {title}

          \n {isActive ? (\n

          {children}

          \n ) : (\n \n )}\n
          \n );\n}", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "export default function Accordion() {\n return (\n <>\n

          Almaty, Kazakhstan

          \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 \n ", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "\n \n The name comes from \u0430\u043b\u043c\u0430, 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 Malus sieversii is considered a likely candidate for the ancestor of the modern domestic apple.\n \n \n );\n}", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "\n \n );\n}\nNotice how pressing one panel\u2019s button does not affect the other panel\u2014they are independent.\nInitially, each Panel\u2019s isActive state is false, so they both appear collapsed\nPanel\nisActive\nfalse\nClicking either Panel\u2019s button will only update that Panel\u2019s isActive state alone\nPanel\nPanel\nisActive", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "Panel\nPanel\nisActive\nBut now let\u2019s 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?\nTo coordinate these two panels, you need to \u201clift their state up\u201d to a parent component in three steps:\nRemove state from the child components.\nPass hardcoded data from the common parent.\nAdd state to the common parent and pass it down together with the event handlers.", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "Add state to the common parent and pass it down together with the event handlers.\nThis will allow the Accordion component to coordinate both Panels and only expand one at a time.\nAccordion\nPanel\nStep 1: Remove state from the child components\nYou will give control of the Panel\u2019s 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 component:\nPanel\nisActive\nisActive\nPanel\nPanel", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "Panel\nisActive\nisActive\nPanel\nPanel\nconst [isActive, setIsActive] = useState(false);\nconst [isActive, setIsActive] = useState(false);\nAnd instead, add isActive to the Panel\u2019s list of props:\nisActive\nPanel\nfunction Panel({ title, children, isActive }) {\nfunction Panel({ title, children, isActive }) {\nNow the Panel\u2019s 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\u2014it\u2019s now up to the parent component!", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "Panel\nisActive\nPanel\nisActive\nStep 2: Pass hardcoded data from the common parent\nTo lift state up, you must locate the closest common parent component of both of the child components that you want to coordinate:\nAccordion (closest common parent)", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "Panel\nPanel\nAccordion\nPanel\nPanel\nPanel\nPanel\nIn this example, it\u2019s the Accordion component. Since it\u2019s above both panels and can control their props, it will become the \u201csource of truth\u201d for which panel is currently active. Make the Accordion component pass a hardcoded value of isActive (for example, true) to both panels:\nAccordion\nAccordion\nisActive\ntrue\nimport { useState } from 'react';", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "export default function Accordion() {\n return (\n <>\n

          Almaty, Kazakhstan

          \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 \n ", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "\n \n The name comes from \u0430\u043b\u043c\u0430, 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 Malus sieversii is considered a likely candidate for the ancestor of the modern domestic apple.\n \n \n );\n}", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "function Panel({ title, children, isActive }) {\n return (\n
          \n

          {title}

          \n {isActive ? (\n

          {children}

          \n ) : (\n \n )}\n
          \n );\n}\nTry editing the hardcoded isActive values in the Accordion component and see the result on the screen.\nisActive\nAccordion\nStep 3: Add state to the common parent", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "isActive\nAccordion\nStep 3: Add state to the common parent\nLifting state up often changes the nature of what you\u2019re storing as state.\nIn 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 variable:\nAccordion\nboolean\nPanel\nconst [activeIndex, setActiveIndex] = useState(0);", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "Accordion\nboolean\nPanel\nconst [activeIndex, setActiveIndex] = useState(0);\nconst [activeIndex, setActiveIndex] = useState(0);\nWhen the activeIndex is 0, the first panel is active, and when it\u2019s 1, it\u2019s the second one.\nactiveIndex\n0\n1", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "activeIndex\n0\n1\nClicking the \u201cShow\u201d button in either Panel needs to change the active index in Accordion. A Panel can\u2019t set the activeIndex state directly because it\u2019s 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:\nPanel\nAccordion\nPanel\nactiveIndex\nAccordion\nAccordion\nPanel", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "Panel\nAccordion\nPanel\nactiveIndex\nAccordion\nAccordion\nPanel\n<> setActiveIndex(0)} > ... setActiveIndex(1)} > ... \n<> setActiveIndex(0)} > ... setActiveIndex(1)} > ... ", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "The \n )}\n
          \n );\n}", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "\n )}\n

          \n );\n}\nThis 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 \u201cis shown\u201d 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\u2019s state.", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "Initially, Accordion\u2019s activeIndex is 0, so the first Panel receives isActive = true\nAccordion\nactiveIndex\n0\nPanel\nisActive = true\nWhen Accordion\u2019s activeIndex state changes to 1, the second Panel receives isActive = true instead\nAccordion\nactiveIndex\n1\nPanel\nisActive = true", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "Accordion\nactiveIndex\n1\nPanel\nisActive = true\nIt is common to call a component with some local state \u201cuncontrolled\u201d. 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.\nPanel\nisActive", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "Panel\nisActive\nIn contrast, you might say a component is \u201ccontrolled\u201d 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.\nPanel\nisActive\nAccordion", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "Panel\nisActive\nAccordion\nUncontrolled components are easier to use within their parents because they require less configuration. But they\u2019re 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.", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "In practice, \u201ccontrolled\u201d and \u201cuncontrolled\u201d aren\u2019t strict technical terms\u2014each 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.\nWhen 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.\nA single source of truth for each state", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "A single source of truth for each state\nIn a React application, many components will have their own state. Some state may \u201clive\u201d close to the leaf components (components at the bottom of the tree) like inputs. Other state may \u201clive\u201d 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!", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "For each unique piece of state, you will choose the component that \u201cowns\u201d it. This principle is also known as having a \u201csingle source of truth\u201d. It doesn\u2019t mean that all state lives in one place\u2014but 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.", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "Your app will change as you work on it. It is common that you will move state down or back up while you\u2019re still figuring out where each piece of the state \u201clives\u201d. This is all part of the process!\nTo see what this feels like in practice with a few more components, read Thinking in React.\nRecap\nWhen you want to coordinate two components, move their state to their common parent.\nThen pass the information down through props from their common parent.", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "Then pass the information down through props from their common parent.\nFinally, pass the event handlers down so that the children can change the parent\u2019s state.\nIt\u2019s useful to consider components as \u201ccontrolled\u201d (driven by props) or \u201cuncontrolled\u201d (driven by state).\nTry out some challenges\nThese two inputs are independent. Make them stay in sync: editing one input should update the other input with the same text, and vice versa.\nimport { useState } from 'react';", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "export default function SyncedInputs() {\n return (\n <>\n \n \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 \n );\n}", + "title": "Sharing State Between Components \u2013 React", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "content": "Manipulating the DOM with Refs\nReact automatically updates the DOM to match your render output, so your components won\u2019t often need to manipulate it. However, sometimes you might need access to the DOM elements managed by React\u2014for 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.\nYou will learn\nHow to access a DOM node managed by React with the ref attribute\nref", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "You will learn\nHow to access a DOM node managed by React with the ref attribute\nref\nHow the ref JSX attribute relates to the useRef Hook\nref\nuseRef\nHow to access another component\u2019s DOM node\nIn which cases it\u2019s safe to modify the DOM managed by React\nGetting a ref to the node\nTo access a DOM node managed by React, first, import the useRef Hook:\nuseRef\nimport { useRef } from 'react';\nimport { useRef } from 'react';\nThen, use it to declare a ref inside your component:\nconst myRef = useRef(null);", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "Then, use it to declare a ref inside your component:\nconst myRef = useRef(null);\nconst myRef = useRef(null);\nFinally, pass your ref as the ref attribute to the JSX tag for which you want to get the DOM node:\nref\n
          \n
          ", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "ref\n
          \n
          \nThe useRef Hook returns an object with a single property called current. Initially, myRef.current will be null. When React creates a DOM node for this
          , React will put a reference to this node into myRef.current. You can then access this DOM node from your event handlers and use the built-in browser APIs defined on it.\nuseRef\ncurrent\nmyRef.current\nnull\n
          \nmyRef.current\n// You can use any browser APIs, for example:myRef.current.scrollIntoView();", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "
          \nmyRef.current\n// You can use any browser APIs, for example:myRef.current.scrollIntoView();\n// You can use any browser APIs, for example:myRef.current.scrollIntoView();\nExample: Focusing a text input\nIn this example, clicking the button will focus the input:\nimport { useRef } from 'react';", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "export default function Form() {\n const inputRef = useRef(null);\n\n function handleClick() {\n inputRef.current.focus();\n }", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "return (\n <>\n \n \n \n );\n}\nTo implement this:\nDeclare inputRef with the useRef Hook.\ninputRef\nuseRef\nPass it as . This tells React to put this \u2019s DOM node into inputRef.current.\n\n\ninputRef.current\nIn the handleClick function, read the input DOM node from inputRef.current and call focus() on it with inputRef.current.focus().", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "handleClick\ninputRef.current\nfocus()\ninputRef.current.focus()\nPass the handleClick event handler to \n \n \n \n
          \n
            \n
          • \n \n
          • ", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "alt=\"Neo\"\n ref={firstCatRef}\n />\n \n
          • \n \n
          • \n
          • \n \n
          • \n
          \n
          \n \n );\n}", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "/>\n \n \n
          \n \n );\n}\nIn the above examples, there is a predefined number of refs. However, sometimes you might need a ref to each item in the list, and you don\u2019t know how many you will have. Something like this wouldn\u2019t work:\n
            {items.map((item) => { // Doesn't work! const ref = useRef(null); return
          • ; })}
          ", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "
            {items.map((item) => { // Doesn't work! const ref = useRef(null); return
          • ; })}
          \nThis is because Hooks must only be called at the top-level of your component. You can\u2019t call useRef in a loop, in a condition, or inside a map() call.\nuseRef\nmap()", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "useRef\nmap()\nOne possible way around this is to get a single ref to their parent element, and then use DOM manipulation methods like querySelectorAll to \u201cfind\u201d the individual child nodes from it. However, this is brittle and can break if your DOM structure changes.\nquerySelectorAll", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "querySelectorAll\nAnother solution is to pass a function to the ref attribute. This is called a ref callback. React will call your ref callback with the DOM node when it\u2019s time to set the ref, and with null when it\u2019s time to clear it. This lets you maintain your own array or a Map, and access any ref by its index or some kind of ID.\nref\nref\nnull\nThis example shows how you can use this approach to scroll to an arbitrary node in a long list:\nimport { useRef, useState } from \"react\";", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "export 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 }", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "return (\n <>\n \n
          \n
            \n {catList.map((cat) => (\n {\n const map = getMap();\n map.set(cat, node);", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "return () => {\n map.delete(cat);\n };\n }}\n >\n \n \n ))}\n
          \n
          \n \n );\n}\n\nfunction setupCatList() {\n const catList = [];\n for (let i = 0; i < 10; i++) {\n catList.push(\"https://loremflickr.com/320/240/cat?lock=\" + i);\n }", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "return catList;\n}\nIn this example, itemsRef doesn\u2019t hold a single DOM node. Instead, it holds a Map from item ID to a DOM node. (Refs can hold any values!) The ref callback on every list item takes care to update the Map:\nitemsRef\nref\n
        16. { const map = getMap(); // Add to the Map map.set(cat, node); return () => { // Remove from the Map map.delete(cat); }; }}>", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "
        17. { const map = getMap(); // Add to the Map map.set(cat, node); return () => { // Remove from the Map map.delete(cat); }; }}>\nThis lets you read individual DOM nodes from the Map later.\nNote\nWhen Strict Mode is enabled, ref callbacks will run twice in development.\nRead more about how this helps find bugs in callback refs.\nAccessing another component\u2019s DOM nodes\nPitfall", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "Accessing another component\u2019s DOM nodes\nPitfall\nRefs are an escape hatch. Manually manipulating another component\u2019s DOM nodes can make your code fragile.\nYou can pass refs from parent component to child components just like any other prop.\nimport { useRef } from 'react';function MyInput({ ref }) { return ;}function MyForm() { const inputRef = useRef(null); return }", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "import { useRef } from 'react';function MyInput({ ref }) { return ;}function MyForm() { const inputRef = useRef(null); return }\nIn the above example, a ref is created in the parent component, MyForm, and is passed to the child component, MyInput. MyInput then passes the ref to . Because is a built-in component React sets the .current property of the ref to the DOM element.\nMyForm\nMyInput\nMyInput\n\n\n.current", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "MyForm\nMyInput\nMyInput\n\n\n.current\n\nThe inputRef created in MyForm now points to the DOM element returned by MyInput. A click handler created in MyForm can access inputRef and call focus() to set the focus on .\ninputRef\nMyForm\n\nMyInput\nMyForm\ninputRef\nfocus()\n\nimport { useRef } from 'react';", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "function MyInput({ ref }) {\n return ;\n}\n\nexport default function MyForm() {\n const inputRef = useRef(null);\n\n function handleClick() {\n inputRef.current.focus();\n }", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "return (\n <>\n \n \n \n );\n}", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "\n \n );\n}\nIn the above example, the ref passed to MyInput is passed on to the original DOM input element. This lets the parent component call focus() on it. However, this also lets the parent component do something else\u2014for example, change its CSS styles. In uncommon cases, you may want to restrict the exposed functionality. You can do that with useImperativeHandle:\nMyInput\nfocus()\nuseImperativeHandle", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "MyInput\nfocus()\nuseImperativeHandle\nimport { useRef, useImperativeHandle } from \"react\";", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "function 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 ;\n};\n\nexport default function Form() {\n const inputRef = useRef(null);\n\n function handleClick() {\n inputRef.current.focus();\n }", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "return (\n <>\n \n \n \n );\n}", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "\n \n );\n}\nHere, realInputRef inside MyInput holds the actual input DOM node. However, useImperativeHandle instructs React to provide your own special object as the value of a ref to the parent component. So inputRef.current inside the Form component will only have the focus method. In this case, the ref \u201chandle\u201d is not the DOM node, but the custom object you create inside useImperativeHandle call.\nrealInputRef\nMyInput", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "realInputRef\nMyInput\nuseImperativeHandle\ninputRef.current\nForm\nfocus\nuseImperativeHandle\nWhen React attaches the refs\nIn React, every update is split in two phases:\nDuring render, React calls your components to figure out what should be on the screen.\nDuring commit, React applies changes to the DOM.", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "During commit, React applies changes to the DOM.\nIn general, you don\u2019t want to access refs during rendering. That goes for refs holding DOM nodes as well. During the first render, the DOM nodes have not yet been created, so ref.current will be null. And during the rendering of updates, the DOM nodes haven\u2019t been updated yet. So it\u2019s too early to read them.\nref.current\nnull", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "ref.current\nnull\nReact sets ref.current during the commit. Before updating the DOM, React sets the affected ref.current values to null. After updating the DOM, React immediately sets them to the corresponding DOM nodes.\nref.current\nref.current\nnull\nUsually, you will access refs from event handlers. If you want to do something with a ref, but there is no particular event to do it in, you might need an Effect. We will discuss Effects on the next pages.", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "Consider code like this, which adds a new todo and scrolls the screen down to the last child of the list. Notice how, for some reason, it always scrolls to the todo that was just before the last added one:\nimport { useState, useRef } from 'react';", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "export 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 }", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "return (\n <>\n \n setText(e.target.value)}\n />\n
            \n {todos.map(todo => (\n
          • {todo.text}
          • \n ))}\n
          \n \n );\n}", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "let nextId = 0;\nlet initialTodos = [];\nfor (let i = 0; i < 20; i++) {\n initialTodos.push({\n id: nextId++,\n text: 'Todo #' + (i + 1)\n });\n}\nThe issue is with these two lines:\nsetTodos([ ...todos, newTodo]);listRef.current.lastChild.scrollIntoView();\nsetTodos([ ...todos, newTodo]);listRef.current.lastChild.scrollIntoView();", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "setTodos([ ...todos, newTodo]);listRef.current.lastChild.scrollIntoView();\nIn React, state updates are queued. Usually, this is what you want. However, here it causes a problem because setTodos does not immediately update the DOM. So the time you scroll the list to its last element, the todo has not yet been added. This is why scrolling always \u201clags behind\u201d by one item.\nsetTodos", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "setTodos\nTo fix this issue, you can force React to update (\u201cflush\u201d) the DOM synchronously. To do this, import flushSync from react-dom and wrap the state update into a flushSync call:\nflushSync\nreact-dom\nflushSync\nflushSync(() => { setTodos([ ...todos, newTodo]);});listRef.current.lastChild.scrollIntoView();\nflushSync(() => { setTodos([ ...todos, newTodo]);});listRef.current.lastChild.scrollIntoView();", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "flushSync(() => { setTodos([ ...todos, newTodo]);});listRef.current.lastChild.scrollIntoView();\nThis will instruct React to update the DOM synchronously right after the code wrapped in flushSync executes. As a result, the last todo will already be in the DOM by the time you try to scroll to it:\nflushSync\nimport { useState, useRef } from 'react';\nimport { flushSync } from 'react-dom';", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "export 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 }", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "return (\n <>\n \n setText(e.target.value)}\n />\n
            \n {todos.map(todo => (\n
          • {todo.text}
          • \n ))}\n
          \n \n );\n}", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "let nextId = 0;\nlet initialTodos = [];\nfor (let i = 0; i < 20; i++) {\n initialTodos.push({\n id: nextId++,\n text: 'Todo #' + (i + 1)\n });\n}\nBest practices for DOM manipulation with refs\nRefs are an escape hatch. You should only use them when you have to \u201cstep outside React\u201d. Common examples of this include managing focus, scroll position, or calling browser APIs that React does not expose.", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "If you stick to non-destructive actions like focusing and scrolling, you shouldn\u2019t encounter any problems. However, if you try to modify the DOM manually, you can risk conflicting with the changes React is making.", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "To illustrate this problem, this example includes a welcome message and two buttons. The first button toggles its presence using conditional rendering and state, as you would usually do in React. The second button uses the remove() DOM API to forcefully remove it from the DOM outside of React\u2019s control.\nremove()", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "remove()\nTry pressing \u201cToggle with setState\u201d a few times. The message should disappear and appear again. Then press \u201cRemove from the DOM\u201d. This will forcefully remove it. Finally, press \u201cToggle with setState\u201d:\nimport { useState, useRef } from 'react';", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "export default function Counter() {\n const [show, setShow] = useState(true);\n const ref = useRef(null);", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "return (\n
          \n {\n setShow(!show);\n }}>\n Toggle with setState\n \n {\n ref.current.remove();\n }}>\n Remove from the DOM\n \n {show &&

          Hello world

          }\n
          \n );\n}", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "\n {show &&

          Hello world

          }\n
        18. \n );\n}\nAfter you\u2019ve manually removed the DOM element, trying to use setState to show it again will lead to a crash. This is because you\u2019ve changed the DOM, and React doesn\u2019t know how to continue managing it correctly.\nsetState\nAvoid changing DOM nodes managed by React. Modifying, adding children to, or removing children from elements that are managed by React can lead to inconsistent visual results or crashes like above.", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "However, this doesn\u2019t mean that you can\u2019t do it at all. It requires caution. You can safely modify parts of the DOM that React has no reason to update. For example, if some
          is always empty in the JSX, React won\u2019t have a reason to touch its children list. Therefore, it is safe to manually add or remove elements there.\n
          \nRecap\nRefs are a generic concept, but most often you\u2019ll use them to hold DOM elements.", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "
          \nRecap\nRefs are a generic concept, but most often you\u2019ll use them to hold DOM elements.\nYou instruct React to put a DOM node into myRef.current by passing
          .\nmyRef.current\n
          \nUsually, you will use refs for non-destructive actions like focusing, scrolling, or measuring DOM elements.\nA component doesn\u2019t expose its DOM nodes by default. You can opt into exposing a DOM node by using the ref prop.\nref\nAvoid changing DOM nodes managed by React.", + "title": "Manipulating the DOM with Refs \u2013 React", + "url": "https://react.dev/learn/manipulating-the-dom-with-refs" + }, + { + "content": "ref\nAvoid changing DOM nodes managed by React.\nIf you do modify DOM nodes managed by React, modify parts that React has no reason to update.\nTry out some challenges\nIn this example, the button toggles a state variable to switch between a playing and a paused state. However, in order to actually play or pause the video, toggling state is not enough. You also need to call play() and pause() on the DOM element for the
          \n );\n}\nIf you click on either button, its onClick will run first, followed by the parent
          \u2019s onClick. So two messages will appear. If you click the toolbar itself, only the parent
          \u2019s onClick will run.\nonClick\n
          \nonClick\n
          \nonClick\nPitfall\nAll events propagate in React except onScroll, which only works on the JSX tag you attach it to.\nonScroll\nStopping propagation", + "title": "Responding to Events \u2013 React", + "url": "https://react.dev/learn/responding-to-events" + }, + { + "content": "onScroll\nStopping propagation\nEvent handlers receive an event object as their only argument. By convention, it\u2019s usually called e, which stands for \u201cevent\u201d. You can use this object to read information about the event.\ne\nThat event object also lets you stop the propagation. If you want to prevent an event from reaching parent components, you need to call e.stopPropagation() like this Button component does:\ne.stopPropagation()\nButton\nfunction Button({ onClick, children }) {\n return (", + "title": "Responding to Events \u2013 React", + "url": "https://react.dev/learn/responding-to-events" + }, + { + "content": "e.stopPropagation()\nButton\nfunction Button({ onClick, children }) {\n return (\n \n );\n}", + "title": "Responding to Events \u2013 React", + "url": "https://react.dev/learn/responding-to-events" + }, + { + "content": "export default function Toolbar() {\n return (\n
          {\n alert('You clicked on the toolbar!');\n }}>\n \n \n
          \n );\n}\nWhen you click on a button:\nReact calls the onClick handler passed to
          ", + "title": "Responding to Events \u2013 React", + "url": "https://react.dev/learn/responding-to-events" + }, + { + "content": "
          { /* this runs first */ }}>
          \nEach event propagates in three phases:\nIt travels down, calling all onClickCapture handlers.\nonClickCapture\nIt runs the clicked element\u2019s onClick handler.\nonClick\nIt travels upwards, calling all onClick handlers.\nonClick\nCapture events are useful for code like routers or analytics, but you probably won\u2019t use them in app code.", + "title": "Responding to Events \u2013 React", + "url": "https://react.dev/learn/responding-to-events" + }, + { + "content": "Passing handlers as alternative to propagation\nNotice how this click handler runs a line of code and then calls the onClick prop passed by the parent:\nonClick\nfunction Button({ onClick, children }) { return ( );}\nfunction Button({ onClick, children }) { return ( );}", + "title": "Responding to Events \u2013 React", + "url": "https://react.dev/learn/responding-to-events" + }, + { + "content": "You could add more code to this handler before calling the parent onClick event handler, too. This pattern provides an alternative to propagation. It lets the child component handle the event, while also letting the parent component specify some additional behavior. Unlike propagation, it\u2019s not automatic. But the benefit of this pattern is that you can clearly follow the whole chain of code that executes as a result of some event.\nonClick", + "title": "Responding to Events \u2013 React", + "url": "https://react.dev/learn/responding-to-events" + }, + { + "content": "onClick\nIf you rely on propagation and it\u2019s difficult to trace which handlers execute and why, try this approach instead.\nPreventing default behavior\nSome browser events have default behavior associated with them. For example, a
          submit event, which happens when a button inside of it is clicked, will reload the whole page by default:\n\nexport default function Signup() {\n return (\n alert('Submitting!')}>\n \n \n
          ", + "title": "Responding to Events \u2013 React", + "url": "https://react.dev/learn/responding-to-events" + }, + { + "content": "\n \n \n );\n}\nYou can call e.preventDefault() on the event object to stop this from happening:\ne.preventDefault()\nexport default function Signup() {\n return (\n
          {\n e.preventDefault();\n alert('Submitting!');\n }}>\n \n \n
          \n );\n}\nDon\u2019t confuse e.stopPropagation() and e.preventDefault(). They are both useful, but are unrelated:\ne.stopPropagation()\ne.preventDefault()", + "title": "Responding to Events \u2013 React", + "url": "https://react.dev/learn/responding-to-events" + }, + { + "content": "e.stopPropagation()\ne.preventDefault()\ne.stopPropagation() stops the event handlers attached to the tags above from firing.\ne.stopPropagation()\ne.preventDefault() prevents the default browser behavior for the few events that have it.\ne.preventDefault()\nCan event handlers have side effects?\nAbsolutely! Event handlers are the best place for side effects.", + "title": "Responding to Events \u2013 React", + "url": "https://react.dev/learn/responding-to-events" + }, + { + "content": "Absolutely! Event handlers are the best place for side effects.\nUnlike rendering functions, event handlers don\u2019t need to be pure, so it\u2019s a great place to change something\u2014for example, change an input\u2019s value in response to typing, or change a list in response to a button press. However, in order to change some information, you first need some way to store it. In React, this is done by using state, a component\u2019s memory. You will learn all about it on the next page.\nRecap", + "title": "Responding to Events \u2013 React", + "url": "https://react.dev/learn/responding-to-events" + }, + { + "content": "Recap\nYou can handle events by passing a function as a prop to an element like \n );\n}", + "title": "Responding to Events \u2013 React", + "url": "https://react.dev/learn/responding-to-events" + }, + { + "content": "Referencing Values with Refs\nWhen you want a component to \u201cremember\u201d some information, but you don\u2019t want that information to trigger new renders, you can use a ref.\nYou will learn\nHow to add a ref to your component\nHow to update a ref\u2019s value\nHow refs are different from state\nHow to use refs safely\nAdding a ref to your component\nYou can add a ref to your component by importing the useRef Hook from React:\nuseRef\nimport { useRef } from 'react';\nimport { useRef } from 'react';", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "useRef\nimport { useRef } from 'react';\nimport { useRef } from 'react';\nInside your component, call the useRef Hook and pass the initial value that you want to reference as the only argument. For example, here is a ref to the value 0:\nuseRef\n0\nconst ref = useRef(0);\nconst ref = useRef(0);\nuseRef returns an object like this:\nuseRef\n{ current: 0 // The value you passed to useRef}\n{ current: 0 // The value you passed to useRef}\nIllustrated by Rachel Lee Nabors", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "{ current: 0 // The value you passed to useRef}\nIllustrated by Rachel Lee Nabors\nYou can access the current value of that ref through the ref.current property. This value is intentionally mutable, meaning you can both read and write to it. It\u2019s like a secret pocket of your component that React doesn\u2019t track. (This is what makes it an \u201cescape hatch\u201d from React\u2019s one-way data flow\u2014more on that below!)\nref.current\nHere, a button will increment ref.current on every click:\nref.current", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "ref.current\nHere, a button will increment ref.current on every click:\nref.current\nimport { useRef } from 'react';", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "export 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 }", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "return (\n \n );\n}\nThe ref points to a number, but, like state, you could point to anything: a string, an object, or even a function. Unlike state, ref is a plain JavaScript object with the current property that you can read and modify.\ncurrent", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "current\nNote that the component doesn\u2019t re-render with every increment. Like state, refs are retained by React between re-renders. However, setting state re-renders a component. Changing a ref does not!\nExample: building a stopwatch", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "Example: building a stopwatch\nYou can combine refs and state in a single component. For example, let\u2019s make a stopwatch that the user can start or stop by pressing a button. In order to display how much time has passed since the user pressed \u201cStart\u201d, you will need to keep track of when the Start button was pressed and what the current time is. This information is used for rendering, so you\u2019ll keep it in state:", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "const [startTime, setStartTime] = useState(null);const [now, setNow] = useState(null);\nconst [startTime, setStartTime] = useState(null);const [now, setNow] = useState(null);\nWhen the user presses \u201cStart\u201d, you\u2019ll use setInterval in order to update the time every 10 milliseconds:\nsetInterval\nimport { useState } from 'react';", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "export 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 }", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "return (\n <>\n

          Time passed: {secondsPassed.toFixed(3)}

          \n \n \n );\n}", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "\n \n );\n}\nWhen the \u201cStop\u201d button is pressed, you need to cancel the existing interval so that it stops updating the now state variable. You can do this by calling clearInterval, but you need to give it the interval ID that was previously returned by the setInterval call when the user pressed Start. You need to keep the interval ID somewhere. Since the interval ID is not used for rendering, you can keep it in a ref:\nnow", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "now\nclearInterval\nsetInterval\nimport { useState, useRef } from 'react';", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "export 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 }", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "function handleStop() {\n clearInterval(intervalRef.current);\n }\n\n let secondsPassed = 0;\n if (startTime != null && now != null) {\n secondsPassed = (now - startTime) / 1000;\n }", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "return (\n <>\n

          Time passed: {secondsPassed.toFixed(3)}

          \n \n \n \n );\n}\nWhen a piece of information is used for rendering, keep it in state. When a piece of information is only needed by event handlers and changing it doesn\u2019t require a re-render, using a ref may be more efficient.\nDifferences between refs and state", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "Differences between refs and state\nPerhaps you\u2019re thinking refs seem less \u201cstrict\u201d than state\u2014you can mutate them instead of always having to use a state setting function, for instance. But in most cases, you\u2019ll want to use state. Refs are an \u201cescape hatch\u201d you won\u2019t need often. Here\u2019s how state and refs compare:\nuseRef(initialValue)\n{ current: initialValue }\nuseState(initialValue)\n[value, setValue]\ncurrent\ncurrent\nHere is a counter button that\u2019s implemented with state:", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "[value, setValue]\ncurrent\ncurrent\nHere is a counter button that\u2019s implemented with state:\nimport { useState } from 'react';", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "export default function Counter() {\n const [count, setCount] = useState(0);\n\n function handleClick() {\n setCount(count + 1);\n }", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "return (\n \n );\n}\nBecause the count value is displayed, it makes sense to use a state value for it. When the counter\u2019s value is set with setCount(), React re-renders the component and the screen updates to reflect the new count.\ncount\nsetCount()", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "count\nsetCount()\nIf you tried to implement this with a ref, React would never re-render the component, so you\u2019d never see the count change! See how clicking this button does not update its text:\nimport { useRef } from 'react';", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "export 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 }", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "return (\n \n );\n}\nThis is why reading ref.current during render leads to unreliable code. If you need that, use state instead.\nref.current\nAlthough both useState and useRef are provided by React, in principle useRef could be implemented on top of useState. You can imagine that inside of React, useRef is implemented like this:\nuseState\nuseRef\nuseRef\nuseState\nuseRef", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "useState\nuseRef\nuseRef\nuseState\nuseRef\n// Inside of Reactfunction useRef(initialValue) { const [ref, unused] = useState({ current: initialValue }); return ref;}\n// Inside of Reactfunction useRef(initialValue) { const [ref, unused] = useState({ current: initialValue }); return ref;}", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "During the first render, useRef returns { current: initialValue }. This object is stored by React, so during the next render the same object will be returned. Note how the state setter is unused in this example. It is unnecessary because useRef always needs to return the same object!\nuseRef\n{ current: initialValue }\nuseRef", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "useRef\n{ current: initialValue }\nuseRef\nReact provides a built-in version of useRef because it is common enough in practice. But you can think of it as a regular state variable without a setter. If you\u2019re familiar with object-oriented programming, refs might remind you of instance fields\u2014but instead of this.something you write somethingRef.current.\nuseRef\nthis.something\nsomethingRef.current\nWhen to use refs", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "useRef\nthis.something\nsomethingRef.current\nWhen to use refs\nTypically, you will use a ref when your component needs to \u201cstep outside\u201d React and communicate with external APIs\u2014often a browser API that won\u2019t impact the appearance of the component. Here are a few of these rare situations:\nStoring timeout IDs\nStoring and manipulating DOM elements, which we cover on the next page\nStoring other objects that aren\u2019t necessary to calculate the JSX.", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "Storing other objects that aren\u2019t necessary to calculate the JSX.\nIf your component needs to store some value, but it doesn\u2019t impact the rendering logic, choose refs.\nBest practices for refs\nFollowing these principles will make your components more predictable:\nTreat refs as an escape hatch. Refs are useful when you work with external systems or browser APIs. If much of your application logic and data flow relies on refs, you might want to rethink your approach.", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "Don\u2019t read or write ref.current during rendering. If some information is needed during rendering, use state instead. Since React doesn\u2019t know when ref.current changes, even reading it while rendering makes your component\u2019s behavior difficult to predict. (The only exception to this is code like if (!ref.current) ref.current = new Thing() which only sets the ref once during the first render.)\nref.current\nref.current\nif (!ref.current) ref.current = new Thing()", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "ref.current\nref.current\nif (!ref.current) ref.current = new Thing()\nLimitations of React state don\u2019t apply to refs. For example, state acts like a snapshot for every render and doesn\u2019t update synchronously. But when you mutate the current value of a ref, it changes immediately:\nref.current = 5;console.log(ref.current); // 5\nref.current = 5;console.log(ref.current); // 5\nThis is because the ref itself is a regular JavaScript object, and so it behaves like one.", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "This is because the ref itself is a regular JavaScript object, and so it behaves like one.\nYou also don\u2019t need to worry about avoiding mutation when you work with a ref. As long as the object you\u2019re mutating isn\u2019t used for rendering, React doesn\u2019t care what you do with the ref or its contents.\nRefs and the DOM", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "Refs and the DOM\nYou can point a ref to any value. However, the most common use case for a ref is to access a DOM element. For example, this is handy if you want to focus an input programmatically. When you pass a ref to a ref attribute in JSX, like
          , React will put the corresponding DOM element into myRef.current. Once the element is removed from the DOM, React will update myRef.current to be null. You can read more about this in Manipulating the DOM with Refs.\nref", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "ref\n
          \nmyRef.current\nmyRef.current\nnull\nRecap\nRefs are an escape hatch to hold onto values that aren\u2019t used for rendering. You won\u2019t need them often.\nA ref is a plain JavaScript object with a single property called current, which you can read or set.\ncurrent\nYou can ask React to give you a ref by calling the useRef Hook.\nuseRef\nLike state, refs let you retain information between re-renders of a component.\nUnlike state, setting the ref\u2019s current value does not trigger a re-render.", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "Unlike state, setting the ref\u2019s current value does not trigger a re-render.\ncurrent\nDon\u2019t read or write ref.current during rendering. This makes your component hard to predict.\nref.current\nTry out some challenges", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "ref.current\nTry out some challenges\nType a message and click \u201cSend\u201d. You will notice there is a three second delay before you see the \u201cSent!\u201d alert. During this delay, you can see an \u201cUndo\u201d button. Click it. This \u201cUndo\u201d button is supposed to stop the \u201cSent!\u201d message from appearing. It does this by calling clearTimeout for the timeout ID saved during handleSend. However, even after \u201cUndo\u201d is clicked, the \u201cSent!\u201d message still appears. Find why it doesn\u2019t work, and fix it.\nclearTimeout\nhandleSend", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "clearTimeout\nhandleSend\nimport { useState } from 'react';", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "export 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 }", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "function handleUndo() {\n setIsSending(false);\n clearTimeout(timeoutID);\n }\n\n return (\n <>\n setText(e.target.value)}\n />\n \n {isSending ? 'Sending...' : 'Send'}\n \n {isSending &&\n \n }\n \n );\n}", + "title": "Referencing Values with Refs \u2013 React", + "url": "https://react.dev/learn/referencing-values-with-refs" + }, + { + "content": "Queueing a Series of State Updates\nSetting 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.\nYou will learn\nWhat \u201cbatching\u201d is and how React uses it to process multiple state updates\nHow to apply several updates to the same state variable in a row\nReact batches state updates", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "How to apply several updates to the same state variable in a row\nReact batches state updates\nYou might expect that clicking the \u201c+3\u201d button will increment the counter three times because it calls setNumber(number + 1) three times:\nsetNumber(number + 1)\nimport { useState } from 'react';", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "export default function Counter() {\n const [number, setNumber] = useState(0);", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "return (\n <>\n

          {number}

          \n \n \n )\n}\nHowever, as you might recall from the previous section, each render\u2019s state values are fixed, so the value of number inside the first render\u2019s event handler is always 0, no matter how many times you call setNumber(1):\nnumber\n0\nsetNumber(1)\nsetNumber(0 + 1);setNumber(0 + 1);setNumber(0 + 1);", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "number\n0\nsetNumber(1)\nsetNumber(0 + 1);setNumber(0 + 1);setNumber(0 + 1);\nsetNumber(0 + 1);setNumber(0 + 1);setNumber(0 + 1);\nBut 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.\nsetNumber()", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "setNumber()\nThis might remind you of a waiter taking an order at the restaurant. A waiter doesn\u2019t 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.\nIllustrated by Rachel Lee Nabors", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "Illustrated by Rachel Lee Nabors\nThis lets you update multiple state variables\u2014even from multiple components\u2014without triggering too many re-renders. But this also means that the UI won\u2019t 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 \u201chalf-finished\u201d renders where only some of the variables have been updated.", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "React does not batch across multiple intentional events like clicks\u2014each click is handled separately. Rest assured that React only does batching when it\u2019s 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.\nUpdating the same state multiple times before the next render", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "Updating the same state multiple times before the next render\nIt 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 \u201cdo something with the state value\u201d instead of just replacing it.\nsetNumber(number + 1)", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "setNumber(number + 1)\nsetNumber(n => n + 1)\nTry incrementing the counter now:\nimport { useState } from 'react';", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "export default function Counter() {\n const [number, setNumber] = useState(0);", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "return (\n <>\n

          {number}

          \n \n \n )\n}\nHere, n => n + 1 is called an updater function. When you pass it to a state setter:\nn => n + 1\nReact queues this function to be processed after all the other code in the event handler has run.\nDuring the next render, React goes through the queue and gives you the final updated state.", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "During the next render, React goes through the queue and gives you the final updated state.\nsetNumber(n => n + 1);setNumber(n => n + 1);setNumber(n => n + 1);\nsetNumber(n => n + 1);setNumber(n => n + 1);setNumber(n => n + 1);\nHere\u2019s how React works through these lines of code while executing the event handler:\nsetNumber(n => n + 1): n => n + 1 is a function. React adds it to a queue.\nsetNumber(n => n + 1)\nn => n + 1\nsetNumber(n => n + 1): n => n + 1 is a function. React adds it to a queue.", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "n => n + 1\nsetNumber(n => n + 1): n => n + 1 is a function. React adds it to a queue.\nsetNumber(n => n + 1)\nn => n + 1\nsetNumber(n => n + 1): n => n + 1 is a function. React adds it to a queue.\nsetNumber(n => n + 1)\nn => n + 1", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "setNumber(n => n + 1)\nn => n + 1\nWhen you call useState during the next render, React goes through the queue. The previous number state was 0, so that\u2019s 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 on:\nuseState\nnumber\n0\nn\nn\nn\nn => n + 1\n0\n0 + 1 = 1\nn => n + 1\n1\n1 + 1 = 2\nn => n + 1\n2\n2 + 1 = 3\nReact stores 3 as the final result and returns it from useState.\n3", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "1 + 1 = 2\nn => n + 1\n2\n2 + 1 = 3\nReact stores 3 as the final result and returns it from useState.\n3\nuseState\nThis is why clicking \u201c+3\u201d in the above example correctly increments the value by 3.\nWhat happens if you update state after replacing it\nWhat about this event handler? What do you think number will be in the next render?\nnumber\n\n \n )\n}\nHere\u2019s what this event handler tells React to do:\nsetNumber(number + 5): number is 0, so setNumber(0 + 5). React adds \u201creplace with 5\u201d to its queue.\nsetNumber(number + 5)\nnumber\n0\nsetNumber(0 + 5)\n5\nsetNumber(n => n + 1): n => n + 1 is an updater function. React adds that function to its queue.", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "5\nsetNumber(n => n + 1): n => n + 1 is an updater function. React adds that function to its queue.\nsetNumber(n => n + 1)\nn => n + 1\nDuring the next render, React goes through the state queue:\nn\n5\n0\n5\nn => n + 1\n5\n5 + 1 = 6\nReact stores 6 as the final result and returns it from useState.\n6\nuseState\nNote\nYou may have noticed that setState(5) actually works like setState(n => 5), but n is unused!\nsetState(5)\nsetState(n => 5)\nn\nWhat happens if you replace state after updating it", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "setState(5)\nsetState(n => 5)\nn\nWhat happens if you replace state after updating it\nLet\u2019s try one more example. What do you think number will be in the next render?\nnumber\n\n \n )\n}\nHere\u2019s how React works through these lines of code while executing this event handler:\nsetNumber(number + 5): number is 0, so setNumber(0 + 5). React adds \u201creplace with 5\u201d to its queue.\nsetNumber(number + 5)\nnumber\n0\nsetNumber(0 + 5)\n5", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "setNumber(number + 5)\nnumber\n0\nsetNumber(0 + 5)\n5\nsetNumber(n => n + 1): n => n + 1 is an updater function. React adds that function to its queue.\nsetNumber(n => n + 1)\nn => n + 1\nsetNumber(42): React adds \u201creplace with 42\u201d to its queue.\nsetNumber(42)\n42\nDuring the next render, React goes through the state queue:\nn\n5\n0\n5\nn => n + 1\n5\n5 + 1 = 6\n42\n6\n42\nThen React stores 42 as the final result and returns it from useState.\n42\nuseState", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "42\n6\n42\nThen React stores 42 as the final result and returns it from useState.\n42\nuseState\nTo summarize, here\u2019s how you can think of what you\u2019re passing to the setNumber state setter:\nsetNumber\nAn updater function (e.g. n => n + 1) gets added to the queue.\nn => n + 1\nAny other value (e.g. number 5) adds \u201creplace with 5\u201d to the queue, ignoring what\u2019s already queued.\n5\n5", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "5\n5\nAfter 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\u2019t 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.\nNaming conventions", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "Naming conventions\nIt\u2019s common to name the updater function argument by the first letters of the corresponding state variable:\nsetEnabled(e => !e);setLastName(ln => ln.reverse());setFriendCount(fc => fc * 2);\nsetEnabled(e => !e);setLastName(ln => ln.reverse());setFriendCount(fc => fc * 2);\nIf 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).", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "setEnabled(enabled => !enabled)\nsetEnabled(prevEnabled => !prevEnabled)\nRecap\nSetting state does not change the variable in the existing render, but it requests a new render.\nReact processes state updates after event handlers have finished running. This is called batching.\nTo update some state multiple times in one event, you can use setNumber(n => n + 1) updater function.\nsetNumber(n => n + 1)\nTry out some challenges", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "setNumber(n => n + 1)\nTry out some challenges\nYou\u2019re 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 \u201cBuy\u201d button, the \u201cPending\u201d counter should increase by one. After three seconds, the \u201cPending\u201d counter should decrease, and the \u201cCompleted\u201d counter should increase.", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "However, the \u201cPending\u201d counter does not behave as intended. When you press \u201cBuy\u201d, it decreases to -1 (which should not be possible!). And if you click fast twice, both counters seem to behave unpredictably.\n-1\nWhy does this happen? Fix both counters.\nimport { useState } from 'react';", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "export 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

          \n Pending: {pending}\n

          \n

          \n Completed: {completed}\n

          \n \n \n );\n}", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "function delay(ms) {\n return new Promise(resolve => {\n setTimeout(resolve, ms);\n });\n}", + "title": "Queueing a Series of State Updates \u2013 React", + "url": "https://react.dev/learn/queueing-a-series-of-state-updates" + }, + { + "content": "Separating Events from Effects\nEvent 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 behaviors: an Effect that re-runs in response to some values but not others. This page will teach you how to do that.\nYou will learn\nHow to choose between an event handler and an Effect", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "You will learn\nHow to choose between an event handler and an Effect\nWhy Effects are reactive, and event handlers are not\nWhat to do when you want a part of your Effect\u2019s code to not be reactive\nWhat Effect Events are, and how to extract them from your Effects\nHow to read the latest props and state from Effects using Effect Events\nChoosing between event handlers and Effects\nFirst, let\u2019s recap the difference between event handlers and Effects.", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "First, let\u2019s recap the difference between event handlers and Effects.\nImagine you\u2019re implementing a chat room component. Your requirements look like this:\nYour component should automatically connect to the selected chat room.\nWhen you click the \u201cSend\u201d button, it should send a message to the chat.", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "When you click the \u201cSend\u201d button, it should send a message to the chat.\nLet\u2019s say you\u2019ve already implemented the code for them, but you\u2019re 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.\nEvent handlers run in response to specific interactions", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "Event handlers run in response to specific interactions\nFrom the user\u2019s perspective, sending a message should happen because the particular \u201cSend\u201d 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 interactions:", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "function ChatRoom({ roomId }) { const [message, setMessage] = useState(''); // ... function handleSendClick() { sendMessage(message); } // ... return ( <> setMessage(e.target.value)} /> );}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "function ChatRoom({ roomId }) { const [message, setMessage] = useState(''); // ... function handleSendClick() { sendMessage(message); } // ... return ( <> setMessage(e.target.value)} /> );}\nWith an event handler, you can be sure that sendMessage(message) will only run if the user presses the button.\nsendMessage(message)\nEffects run whenever synchronization is needed", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "sendMessage(message)\nEffects run whenever synchronization is needed\nRecall that you also need to keep the component connected to the chat room. Where does that code go?", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "The reason to run this code is not some particular interaction. It doesn\u2019t matter why or how the user navigated to the chat room screen. Now that they\u2019re 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\u2019s an Effect:", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "function ChatRoom({ roomId }) { // ... useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; }, [roomId]); // ...}\nfunction ChatRoom({ roomId }) { // ... useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; }, [roomId]); // ...}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "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\u2019s necessary.\nimport { useState, useEffect } from 'react';", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "import { useState, useEffect } from 'react';\nimport { createConnection, sendMessage } from './chat.js';", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "const 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 }", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "function handleSendClick() {\n sendMessage(message);\n }\n\n return (\n <>\n

          Welcome to the {roomId} room!

          \n setMessage(e.target.value)} />\n \n \n );\n}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "export default function App() {\n const [roomId, setRoomId] = useState('general');\n const [show, setShow] = useState(false);\n return (\n <>\n ", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "\n \n \n \n {show &&
          }\n {show && }\n \n );\n}\nReactive values and reactive logic", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "{show && }\n \n );\n}\nReactive values and reactive logic\nIntuitively, you could say that event handlers are always triggered \u201cmanually\u201d, for example by clicking a button. Effects, on the other hand, are \u201cautomatic\u201d: they run and re-run as often as it\u2019s needed to stay synchronized.\nThere is a more precise way to think about this.", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "There is a more precise way to think about this.\nProps, state, and variables declared inside your component\u2019s 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 flow:\nserverUrl\nroomId\nmessage\nconst serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) { const [message, setMessage] = useState(''); // ...}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "const serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) { const [message, setMessage] = useState(''); // ...}\nReactive 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 differently:\nmessage\nroomId", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "message\nroomId\nLogic 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 \u201creacting\u201d to their changes.\nLogic 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\u2019s logic with the new value.", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "Let\u2019s revisit the previous example to illustrate this difference.\nLogic inside event handlers is not reactive\nTake a look at this line of code. Should this logic be reactive or not?\n// ... sendMessage(message); // ...\n// ... sendMessage(message); // ...", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "// ... sendMessage(message); // ...\n// ... sendMessage(message); // ...\nFrom the user\u2019s 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\u2019s why it belongs in the event handler:\nmessage\nfunction handleSendClick() { sendMessage(message); }", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "message\nfunction handleSendClick() { sendMessage(message); }\nfunction handleSendClick() { sendMessage(message); }\nEvent handlers aren\u2019t reactive, so sendMessage(message) will only run when the user clicks the Send button.\nsendMessage(message)\nLogic inside Effects is reactive\nNow let\u2019s return to these lines:\n// ... const connection = createConnection(serverUrl, roomId); connection.connect(); // ...", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "// ... const connection = createConnection(serverUrl, roomId); connection.connect(); // ...\nFrom the user\u2019s 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 \u201ckeep up\u201d with the reactive value, and to run again if that value is different. That\u2019s why it belongs in an Effect:\nroomId", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "roomId\nuseEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect() }; }, [roomId]);\nuseEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect() }; }, [roomId]);", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "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.\ncreateConnection(serverUrl, roomId)\nconnection.connect()\nroomId\nExtracting non-reactive logic out of Effects\nThings get more tricky when you want to mix reactive logic with non-reactive logic.", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "Things get more tricky when you want to mix reactive logic with non-reactive logic.\nFor 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 color:", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "function ChatRoom({ roomId, theme }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.on('connected', () => { showNotification('Connected!', theme); }); connection.connect(); // ...\nfunction ChatRoom({ roomId, theme }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.on('connected', () => { showNotification('Connected!', theme); }); connection.connect(); // ...", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "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 Effect:\ntheme\ntheme", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "theme\ntheme\nfunction ChatRoom({ roomId, theme }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.on('connected', () => { showNotification('Connected!', theme); }); connection.connect(); return () => { connection.disconnect() }; }, [roomId, theme]); // \u2705 All dependencies declared // ...", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "function ChatRoom({ roomId, theme }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.on('connected', () => { showNotification('Connected!', theme); }); connection.connect(); return () => { connection.disconnect() }; }, [roomId, theme]); // \u2705 All dependencies declared // ...\nPlay with this example and see if you can spot the problem with this user experience:\nimport { useState, useEffect } from 'react';", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "import { useState, useEffect } from 'react';\nimport { createConnection, sendMessage } from './chat.js';\nimport { showNotification } from './notifications.js';", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "const 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

          Welcome to the {roomId} room!

          \n}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "export default function App() {\n const [roomId, setRoomId] = useState('general');\n const [isDark, setIsDark] = useState(false);\n return (\n <>\n \n \n \n
          \n \n \n );\n}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "roomId={roomId}\n theme={isDark ? 'dark' : 'light'}\n />\n \n );\n}\nWhen 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\u2019s not great!\nroomId\ntheme\nIn other words, you don\u2019t want this line to be reactive, even though it is inside an Effect (which is reactive):\n// ... showNotification('Connected!', theme); // ...", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "// ... showNotification('Connected!', theme); // ...\n// ... showNotification('Connected!', theme); // ...\nYou need a way to separate this non-reactive logic from the reactive Effect around it.\nDeclaring an Effect Event\nUnder Construction\nThis section describes an experimental API that has not yet been released in a stable version of React.\nUse a special Hook called useEffectEvent to extract this non-reactive logic out of your Effect:\nuseEffectEvent", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "useEffectEvent\nimport { useEffect, useEffectEvent } from 'react';function ChatRoom({ roomId, theme }) { const onConnected = useEffectEvent(() => { showNotification('Connected!', theme); }); // ...\nimport { useEffect, useEffectEvent } from 'react';function ChatRoom({ roomId, theme }) { const onConnected = useEffectEvent(() => { showNotification('Connected!', theme); }); // ...", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "Here, onConnected is called an Effect Event. It\u2019s 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 \u201csees\u201d the latest values of your props and state.\nonConnected\nNow you can call the onConnected Effect Event from inside your Effect:\nonConnected", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "onConnected\nNow you can call the onConnected Effect Event from inside your Effect:\nonConnected\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]); // \u2705 All dependencies declared // ...", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "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]); // \u2705 All dependencies declared // ...", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "This solves the problem. Note that you had to remove theme from the list of your Effect\u2019s dependencies, because it\u2019s no longer used in the Effect. You also don\u2019t need to add onConnected to it, because Effect Events are not reactive and must be omitted from dependencies.\ntheme\nonConnected\nVerify that the new behavior works as you would expect:\nimport { useState, useEffect } from 'react';\nimport { experimental_useEffectEvent as useEffectEvent } from 'react';", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "import { experimental_useEffectEvent as useEffectEvent } from 'react';\nimport { createConnection, sendMessage } from './chat.js';\nimport { showNotification } from './notifications.js';", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "const 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

          Welcome to the {roomId} room!

          \n}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "export default function App() {\n const [roomId, setRoomId] = useState('general');\n const [isDark, setIsDark] = useState(false);\n return (\n <>\n \n \n \n
          \n \n \n );\n}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "roomId={roomId}\n theme={isDark ? 'dark' : 'light'}\n />\n \n );\n}\nYou can think of Effect Events as being very similar to event handlers. The main difference is that event handlers run in response to a user interactions, whereas Effect Events are triggered by you from Effects. Effect Events let you \u201cbreak the chain\u201d between the reactivity of Effects and code that should not be reactive.\nReading latest props and state with Effect Events\nUnder Construction", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "Reading latest props and state with Effect Events\nUnder Construction\nThis section describes an experimental API that has not yet been released in a stable version of React.\nEffect Events let you fix many patterns where you might be tempted to suppress the dependency linter.\nFor example, say you have an Effect to log the page visits:\nfunction Page() { useEffect(() => { logVisit(); }, []); // ...}\nfunction Page() { useEffect(() => { logVisit(); }, []); // ...}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "function Page() { useEffect(() => { logVisit(); }, []); // ...}\nLater, 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 complains:\nPage\nurl\nurl\nlogVisit\nfunction Page({ url }) { useEffect(() => { logVisit(url); }, []); // \ud83d\udd34 React Hook useEffect has a missing dependency: 'url' // ...}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "function Page({ url }) { useEffect(() => { logVisit(url); }, []); // \ud83d\udd34 React Hook useEffect has a missing dependency: 'url' // ...}\nThink 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 dependency:\nlogVisit\nurl\nurl", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "logVisit\nurl\nurl\nfunction Page({ url }) { useEffect(() => { logVisit(url); }, [url]); // \u2705 All dependencies declared // ...}\nfunction Page({ url }) { useEffect(() => { logVisit(url); }, [url]); // \u2705 All dependencies declared // ...}\nNow let\u2019s say you want to include the number of items in the shopping cart together with every page visit:", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "function Page({ url }) { const { items } = useContext(ShoppingCartContext); const numberOfItems = items.length; useEffect(() => { logVisit(url, numberOfItems); }, [url]); // \ud83d\udd34 React Hook useEffect has a missing dependency: 'numberOfItems' // ...}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "function Page({ url }) { const { items } = useContext(ShoppingCartContext); const numberOfItems = items.length; useEffect(() => { logVisit(url, numberOfItems); }, [url]); // \ud83d\udd34 React Hook useEffect has a missing dependency: 'numberOfItems' // ...}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "You used numberOfItems inside the Effect, so the linter asks you to add it as a dependency. However, you don\u2019t 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 \u201cevent\u201d. It happens at a precise moment in time.\nnumberOfItems\nlogVisit\nnumberOfItems\nnumberOfItems", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "numberOfItems\nlogVisit\nnumberOfItems\nnumberOfItems\nSplit the code in two parts:\nfunction Page({ url }) { const { items } = useContext(ShoppingCartContext); const numberOfItems = items.length; const onVisit = useEffectEvent(visitedUrl => { logVisit(visitedUrl, numberOfItems); }); useEffect(() => { onVisit(url); }, [url]); // \u2705 All dependencies declared // ...}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "function Page({ url }) { const { items } = useContext(ShoppingCartContext); const numberOfItems = items.length; const onVisit = useEffectEvent(visitedUrl => { logVisit(visitedUrl, numberOfItems); }); useEffect(() => { onVisit(url); }, [url]); // \u2705 All dependencies declared // ...}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "Here, onVisit is an Effect Event. The code inside it isn\u2019t 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.\nonVisit\nnumberOfItems\nOn 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.\nurl\nurl\nonVisit", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "url\nurl\nonVisit\nAs 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.\nlogVisit\nurl\nnumberOfItems\nnumberOfItems\nNote\nYou might be wondering if you could call onVisit() with no arguments, and read the url inside it:\nonVisit()\nurl\nconst onVisit = useEffectEvent(() => { logVisit(url, numberOfItems); }); useEffect(() => { onVisit(); }, [url]);", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "const onVisit = useEffectEvent(() => { logVisit(url, numberOfItems); }); useEffect(() => { onVisit(); }, [url]);\nThis would work, but it\u2019s 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 \u201cevent\u201d from the user\u2019s perspective. The visitedUrl is a part of the \u201cevent\u201d that happened:\nurl\nurl\nurl\nvisitedUrl", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "url\nurl\nurl\nvisitedUrl\nconst onVisit = useEffectEvent(visitedUrl => { logVisit(visitedUrl, numberOfItems); }); useEffect(() => { onVisit(url); }, [url]);\nconst onVisit = useEffectEvent(visitedUrl => { logVisit(visitedUrl, numberOfItems); }); useEffect(() => { onVisit(url); }, [url]);", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "Since your Effect Event explicitly \u201casks\u201d for the visitedUrl, now you can\u2019t accidentally remove url from the Effect\u2019s 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\u2019t be reactive), you pass it from your Effect.\nvisitedUrl\nurl\nurl\nonVisit\nurl\nurl", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "visitedUrl\nurl\nurl\nonVisit\nurl\nurl\nThis becomes especially important if there is some asynchronous logic inside the Effect:\nconst onVisit = useEffectEvent(visitedUrl => { logVisit(visitedUrl, numberOfItems); }); useEffect(() => { setTimeout(() => { onVisit(url); }, 5000); // Delay logging visits }, [url]);", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "const onVisit = useEffectEvent(visitedUrl => { logVisit(visitedUrl, numberOfItems); }); useEffect(() => { setTimeout(() => { onVisit(url); }, 5000); // Delay logging visits }, [url]);\nHere, 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.\nurl\nonVisit\nurl\nvisitedUrl\nurl\nonVisit", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "url\nonVisit\nurl\nvisitedUrl\nurl\nonVisit\nIn the existing codebases, you may sometimes see the lint rule suppressed like this:\nfunction Page({ url }) { const { items } = useContext(ShoppingCartContext); const numberOfItems = items.length; useEffect(() => { logVisit(url, numberOfItems); // \ud83d\udd34 Avoid suppressing the linter like this: // eslint-disable-next-line react-hooks/exhaustive-deps }, [url]); // ...}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "function Page({ url }) { const { items } = useContext(ShoppingCartContext); const numberOfItems = items.length; useEffect(() => { logVisit(url, numberOfItems); // \ud83d\udd34 Avoid suppressing the linter like this: // eslint-disable-next-line react-hooks/exhaustive-deps }, [url]); // ...}\nAfter useEffectEvent becomes a stable part of React, we recommend never suppressing the linter.\nuseEffectEvent", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "useEffectEvent\nThe first downside of suppressing the rule is that React will no longer warn you when your Effect needs to \u201creact\u201d to a new reactive dependency you\u2019ve 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.\nurl", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "url\nHere 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.\nhandleMove\ncanMove\ncanMove\ntrue\nhandleMove\nCan you see why?\nimport { useState, useEffect } from 'react';", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "export 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 }, []);", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "return (\n <>\n \n
          \n
          \n \n );\n}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "top: -20,\n width: 40,\n height: 40,\n }} />\n \n );\n}\nThe problem with this code is in suppressing the dependency linter. If you remove the suppression, you\u2019ll see that this Effect should depend on the handleMove function. This makes sense: handleMove 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!\nhandleMove\nhandleMove", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "The author of the original code has \u201clied\u201d 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.", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "[]\ncanMove\nhandleMove\nhandleMove\nhandleMove\ncanMove\ntrue\nhandleMove\nIf you never suppress the linter, you will never see problems with stale values.\nWith useEffectEvent, there is no need to \u201clie\u201d to the linter, and the code works as you would expect:\nuseEffectEvent\nimport { useState, useEffect } from 'react';\nimport { experimental_useEffectEvent as useEffectEvent } from 'react';", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "export 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 }, []);", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "return (\n <>\n \n
          \n
          \n \n );\n}\nThis doesn\u2019t mean that useEffectEvent is always the correct solution. You should only apply it to the lines of code that you don\u2019t want to be reactive. In the above sandbox, you didn\u2019t want the Effect\u2019s code to be reactive with regards to canMove. That\u2019s why it made sense to extract an Effect Event.\nuseEffectEvent\ncanMove", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "useEffectEvent\ncanMove\nRead Removing Effect Dependencies for other correct alternatives to suppressing the linter.\nLimitations of Effect Events\nUnder Construction\nThis section describes an experimental API that has not yet been released in a stable version of React.\nEffect Events are very limited in how you can use them:\nOnly call them from inside Effects.\nNever pass them to other components or Hooks.\nFor example, don\u2019t declare and pass an Effect Event like this:", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "function Timer() { const [count, setCount] = useState(0); const onTick = useEffectEvent(() => { setCount(count + 1); }); useTimer(onTick, 1000); // \ud83d\udd34 Avoid: Passing Effect Events return

          {count}

          }function useTimer(callback, delay) { useEffect(() => { const id = setInterval(() => { callback(); }, delay); return () => { clearInterval(id); }; }, [delay, callback]); // Need to specify \"callback\" in dependencies}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "function Timer() { const [count, setCount] = useState(0); const onTick = useEffectEvent(() => { setCount(count + 1); }); useTimer(onTick, 1000); // \ud83d\udd34 Avoid: Passing Effect Events return

          {count}

          }function useTimer(callback, delay) { useEffect(() => { const id = setInterval(() => { callback(); }, delay); return () => { clearInterval(id); }; }, [delay, callback]); // Need to specify \"callback\" in dependencies}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "Instead, always declare Effect Events directly next to the Effects that use them:", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "function Timer() { const [count, setCount] = useState(0); useTimer(() => { setCount(count + 1); }, 1000); return

          {count}

          }function useTimer(callback, delay) { const onTick = useEffectEvent(() => { callback(); }); useEffect(() => { const id = setInterval(() => { onTick(); // \u2705 Good: Only called locally inside an Effect }, delay); return () => { clearInterval(id); }; }, [delay]); // No need to specify \"onTick\" (an Effect Event) as a dependency}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "function Timer() { const [count, setCount] = useState(0); useTimer(() => { setCount(count + 1); }, 1000); return

          {count}

          }function useTimer(callback, delay) { const onTick = useEffectEvent(() => { callback(); }); useEffect(() => { const id = setInterval(() => { onTick(); // \u2705 Good: Only called locally inside an Effect }, delay); return () => { clearInterval(id); }; }, [delay]); // No need to specify \"onTick\" (an Effect Event) as a dependency}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "Effect Events are non-reactive \u201cpieces\u201d of your Effect code. They should be next to the Effect using them.\nRecap\nEvent handlers run in response to specific interactions.\nEffects run whenever synchronization is needed.\nLogic inside event handlers is not reactive.\nLogic inside Effects is reactive.\nYou can move non-reactive logic from Effects into Effect Events.\nOnly call Effect Events from inside Effects.\nDon\u2019t pass Effect Events to other components or Hooks.\nTry out some challenges", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "Don\u2019t pass Effect Events to other components or Hooks.\nTry out some challenges\nThis Timer component keeps a count state variable which increases every second. The value by which it\u2019s increasing is stored in the increment state variable. You can control the increment variable with the plus and minus buttons.\nTimer\ncount\nincrement\nincrement", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "Timer\ncount\nincrement\nincrement\nHowever, no matter how many times you click the plus button, the counter is still incremented by one every second. What\u2019s wrong with this code? Why is increment always equal to 1 inside the Effect\u2019s code? Find the mistake and fix it.\nincrement\n1\nimport { useState, useEffect } from 'react';", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "export 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 }, []);", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "return (\n <>\n

          \n Counter: {count}\n \n

          \n
          \n

          \n Every second, increment by:\n \n {increment}\n \n

          \n \n );\n}", + "title": "Separating Events from Effects \u2013 React", + "url": "https://react.dev/learn/separating-events-from-effects" + }, + { + "content": "Removing Effect Dependencies\nWhen you write an Effect, the linter will verify that you\u2019ve included every reactive value (like props and state) that the Effect reads in the list of your Effect\u2019s 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.", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "You will learn\nHow to fix infinite Effect dependency loops\nWhat to do when you want to remove a dependency\nHow to read a value from your Effect without \u201creacting\u201d to it\nHow and why to avoid object and function dependencies\nWhy suppressing the dependency linter is dangerous, and what to do instead\nDependencies should match the code\nWhen you write an Effect, you first specify how to start and stop whatever you want your Effect to be doing:", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "const serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); \t// ...}\nconst serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); \t// ...}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "Then, if you leave the Effect dependencies empty ([]), the linter will suggest the correct dependencies:\n[]\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "const 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

          Welcome to the {roomId} room!

          ;\n}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "export default function App() {\n const [roomId, setRoomId] = useState('general');\n return (\n <>\n \n
          \n \n \n );\n}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "\n \n
          \n \n \n );\n}\nFill them in according to what the linter says:\nfunction ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); }, [roomId]); // \u2705 All dependencies declared // ...}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); }, [roomId]); // \u2705 All dependencies declared // ...}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "Effects \u201creact\u201d to reactive values. Since roomId is a reactive value (it can change due to a re-render), the linter verifies that you\u2019ve 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 \u201creacts\u201d to the dropdown:\nroomId\nroomId\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "const 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

          Welcome to the {roomId} room!

          ;\n}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "export default function App() {\n const [roomId, setRoomId] = useState('general');\n return (\n <>\n \n
          \n \n \n );\n}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "\n \n
          \n \n \n );\n}\nTo remove a dependency, prove that it\u2019s not a dependency\nNotice that you can\u2019t \u201cchoose\u201d the dependencies of your Effect. Every reactive value used by your Effect\u2019s code must be declared in your dependency list. The dependency list is determined by the surrounding code:", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "const 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]); // \u2705 So you must specify that reactive value as a dependency of your Effect // ...}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "const 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]); // \u2705 So you must specify that reactive value as a dependency of your Effect // ...}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "Reactive values include props and all variables and functions declared directly inside of your component. Since roomId is a reactive value, you can\u2019t remove it from the dependency list. The linter wouldn\u2019t allow it:\nroomId", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "roomId\nconst serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); }, []); // \ud83d\udd34 React Hook useEffect has a missing dependency: 'roomId' // ...}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "const serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); }, []); // \ud83d\udd34 React Hook useEffect has a missing dependency: 'roomId' // ...}\nAnd the linter would be right! Since roomId may change over time, this would introduce a bug in your code.\nroomId", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "roomId\nTo remove a dependency, \u201cprove\u201d to the linter that it doesn\u2019t need to be a dependency. For example, you can move roomId out of your component to prove that it\u2019s not reactive and won\u2019t change on re-renders:\nroomId", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "roomId\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(); }, []); // \u2705 All dependencies declared // ...}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "const serverUrl = 'https://localhost:1234';const roomId = 'music'; // Not a reactive value anymorefunction ChatRoom() { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); }, []); // \u2705 All dependencies declared // ...}\nNow that roomId is not a reactive value (and can\u2019t change on a re-render), it doesn\u2019t need to be a dependency:\nroomId\nimport { useState, useEffect } from 'react';", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "roomId\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "const serverUrl = 'https://localhost:1234';\nconst roomId = 'music';", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "export default function ChatRoom() {\n useEffect(() => {\n const connection = createConnection(serverUrl, roomId);\n connection.connect();\n return () => connection.disconnect();\n }, []);\n return

          Welcome to the {roomId} room!

          ;\n}\nThis is why you could now specify an empty ([]) dependency list. Your Effect really doesn\u2019t depend on any reactive value anymore, so it really doesn\u2019t need to re-run when any of the component\u2019s props or state change.\n[]", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "[]\nTo change the dependencies, change the code\nYou might have noticed a pattern in your workflow:\nFirst, you change the code of your Effect or how your reactive values are declared.\nThen, you follow the linter and adjust the dependencies to match the code you have changed.\nIf you\u2019re not happy with the list of dependencies, you go back to the first step (and change the code again).", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "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\u2019s code. You don\u2019t choose what to put on that list. The list describes your code. To change the dependency list, change the code.", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "This might feel like solving an equation. You might start with a goal (for example, to remove a dependency), and you need to \u201cfind\u201d 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.\nPitfall\nIf you have an existing codebase, you might have some Effects that suppress the linter like this:", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "If you have an existing codebase, you might have some Effects that suppress the linter like this:\nuseEffect(() => { // ... // \ud83d\udd34 Avoid suppressing the linter like this: // eslint-ignore-next-line react-hooks/exhaustive-deps}, []);\nuseEffect(() => { // ... // \ud83d\udd34 Avoid suppressing the linter like this: // eslint-ignore-next-line react-hooks/exhaustive-deps}, []);", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "When dependencies don\u2019t match the code, there is a very high risk of introducing bugs. By suppressing the linter, you \u201clie\u201d to React about the values your Effect depends on.\nInstead, use the techniques below.\nSuppressing the linter leads to very unintuitive bugs that are hard to find and fix. Here\u2019s one example:\nimport { useState, useEffect } from 'react';", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "export 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 }, []);", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "return (\n <>\n

          \n Counter: {count}\n \n

          \n
          \n

          \n Every second, increment by:\n \n {increment}\n \n

          \n \n );\n}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "setIncrement(i => i + 1);\n }}>+\n

          \n \n );\n}\nLet\u2019s say that you wanted to run the Effect \u201conly on mount\u201d. You\u2019ve read that empty ([]) dependencies do that, so you\u2019ve decided to ignore the linter, and forcefully specified [] as the dependencies.\n[]\n[]", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "[]\n[]\nThis counter was supposed to increment every second by the amount configurable with the two buttons. However, since you \u201clied\u201d to React that this Effect doesn\u2019t 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\u2019re spread across multiple components.\nonTick", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "onTick\ncount\n0\nincrement\n1\nonTick\nsetCount(0 + 1)\n1\nThere\u2019s 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.)\nonTick\nonTick\nWe recommend treating the dependency lint error as a compilation error. If you don\u2019t suppress it, you will never see bugs like this. The rest of this page documents the alternatives for this and other cases.", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "Removing unnecessary dependencies\nEvery time you adjust the Effect\u2019s 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 \u201cno\u201d:\nYou might want to re-execute different parts of your Effect under different conditions.\nYou might want to only read the latest value of some dependency instead of \u201creacting\u201d to its changes.", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "A dependency may change too often unintentionally because it\u2019s an object or a function.\nTo find the right solution, you\u2019ll need to answer a few questions about your Effect. Let\u2019s walk through them.\nShould this code move to an event handler?\nThe first thing you should think about is whether this code should be an Effect at all.", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "The first thing you should think about is whether this code should be an Effect at all.\nImagine a form. On submit, you set the submitted state variable to true. You need to send a POST request and show a notification. You\u2019ve put this logic inside an Effect that \u201creacts\u201d to submitted being true:\nsubmitted\ntrue\nsubmitted\ntrue", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "submitted\ntrue\nsubmitted\ntrue\nfunction Form() { const [submitted, setSubmitted] = useState(false); useEffect(() => { if (submitted) { // \ud83d\udd34 Avoid: Event-specific logic inside an Effect post('/api/register'); showNotification('Successfully registered!'); } }, [submitted]); function handleSubmit() { setSubmitted(true); } // ...}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function Form() { const [submitted, setSubmitted] = useState(false); useEffect(() => { if (submitted) { // \ud83d\udd34 Avoid: Event-specific logic inside an Effect post('/api/register'); showNotification('Successfully registered!'); } }, [submitted]); function handleSubmit() { setSubmitted(true); } // ...}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "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 dependency:\ntheme", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "theme\nfunction Form() { const [submitted, setSubmitted] = useState(false); const theme = useContext(ThemeContext); useEffect(() => { if (submitted) { // \ud83d\udd34 Avoid: Event-specific logic inside an Effect post('/api/register'); showNotification('Successfully registered!', theme); } }, [submitted, theme]); // \u2705 All dependencies declared function handleSubmit() { setSubmitted(true); } // ...}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function Form() { const [submitted, setSubmitted] = useState(false); const theme = useContext(ThemeContext); useEffect(() => { if (submitted) { // \ud83d\udd34 Avoid: Event-specific logic inside an Effect post('/api/register'); showNotification('Successfully registered!', theme); } }, [submitted, theme]); // \u2705 All dependencies declared function handleSubmit() { setSubmitted(true); } // ...}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "By doing this, you\u2019ve 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!\ntheme", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "theme\nThe problem here is that this shouldn\u2019t 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 handler:", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function Form() { const theme = useContext(ThemeContext); function handleSubmit() { // \u2705 Good: Event-specific logic is called from event handlers post('/api/register'); showNotification('Successfully registered!', theme); } // ...}\nfunction Form() { const theme = useContext(ThemeContext); function handleSubmit() { // \u2705 Good: Event-specific logic is called from event handlers post('/api/register'); showNotification('Successfully registered!', theme); } // ...}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "Now that the code is in an event handler, it\u2019s not reactive\u2014so 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.\nIs your Effect doing several unrelated things?\nThe next question you should ask yourself is whether your Effect is doing several unrelated things.", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "The next question you should ask yourself is whether your Effect is doing several unrelated things.\nImagine you\u2019re 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 dropdown:\ncities\ncountry", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "cities\ncountry\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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function 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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "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\u2019t 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).\ncities\ncountry\nShippingForm\ncountry", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "cities\ncountry\nShippingForm\ncountry\nNow let\u2019s say you\u2019re 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 Effect:\nareas\ncity\nfetch", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function 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); } }); // \ud83d\udd34 Avoid: A single Effect synchronizes two independent processes if (city) {", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "}); // \ud83d\udd34 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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function 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); } }); // \ud83d\udd34 Avoid: A single Effect synchronizes two independent processes if (city) {", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "}); // \ud83d\udd34 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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "However, since the Effect now uses the city state variable, you\u2019ve had to add city to the list of dependencies. That, in turn, introduced a problem: when 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.\ncity\ncity\nfetchCities(country)\nThe problem with this code is that you\u2019re synchronizing two different unrelated things:", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "The problem with this code is that you\u2019re synchronizing two different unrelated things:\nYou want to synchronize the cities state to the network based on the country prop.\ncities\ncountry\nYou want to synchronize the areas state to the network based on the city state.\nareas\ncity\nSplit the logic into two Effects, each of which reacts to the prop that it needs to synchronize with:", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function 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]); // \u2705 All dependencies declared const [city, setCity] = useState(null); const [areas, setAreas] = useState(null); useEffect(() => { if", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function 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]); // \u2705 All dependencies declared const [city, setCity] = useState(null); const [areas, setAreas] = useState(null); useEffect(() => { if", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "Now the first Effect only re-runs if the country changes, while the second Effect re-runs when the city changes. You\u2019ve separated them by purpose: two different things are synchronized by two separate Effects. Two separate Effects have two separate dependency lists, so they won\u2019t trigger each other unintentionally.\ncountry\ncity", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "country\ncity\nThe 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\u2019t break the other Effect\u2019s logic. This means they synchronize different things, and it\u2019s good to split them up. If you\u2019re concerned about duplication, you can improve this code by extracting repetitive logic into a custom Hook.\nAre you reading some state to calculate the next state?", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "Are you reading some state to calculate the next state?\nThis Effect updates the messages state variable with a newly created array every time a new message arrives:\nmessages\nfunction ChatRoom({ roomId }) { const [messages, setMessages] = useState([]); useEffect(() => { const connection = createConnection(); connection.connect(); connection.on('message', (receivedMessage) => { setMessages([...messages, receivedMessage]); }); // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function ChatRoom({ roomId }) { const [messages, setMessages] = useState([]); useEffect(() => { const connection = createConnection(); connection.connect(); connection.on('message', (receivedMessage) => { setMessages([...messages, receivedMessage]); }); // ...\nIt 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 dependency:", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "messages\nmessages\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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function ChatRoom({ roomId }) { const [messages, setMessages] = useState([]); useEffect(() => { const connection = createConnection(); connection.connect(); connection.on('message', (receivedMessage) => { setMessages([...messages, receivedMessage]); }); return () => connection.disconnect(); }, [roomId, messages]); // \u2705 All dependencies declared // ...\nAnd making messages a dependency introduces a problem.\nmessages", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "And making messages a dependency introduces a problem.\nmessages\nEvery 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!\nsetMessages()\nmessages\nmessages", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "setMessages()\nmessages\nmessages\nTo fix the issue, don\u2019t read messages inside the Effect. Instead, pass an updater function to setMessages:\nmessages\nsetMessages", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "messages\nsetMessages\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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function ChatRoom({ roomId }) { const [messages, setMessages] = useState([]); useEffect(() => { const connection = createConnection(); connection.connect(); connection.on('message', (receivedMessage) => { setMessages(msgs => [...msgs, receivedMessage]); }); return () => connection.disconnect(); }, [roomId]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "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\u2019t need to depend on messages anymore. As a result of this fix, receiving a chat message will no longer make the chat re-connect.\nmessages\nmsgs => [...msgs, receivedMessage]\nmsgs\nmessages", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "messages\nmsgs => [...msgs, receivedMessage]\nmsgs\nmessages\nDo you want to read a value without \u201creacting\u201d to its changes?\nUnder Construction\nThis section describes an experimental API that has not yet been released in a stable version of React.\nSuppose that you want to play a sound when the user receives a new message unless isMuted is true:\nisMuted\ntrue", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "isMuted\ntrue\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(); } }); // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function 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(); } }); // ...\nSince your Effect now uses isMuted in its code, you have to add it to the dependencies:\nisMuted", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "isMuted\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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function 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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "The problem is that every time isMuted changes (for example, when the user presses the \u201cMuted\u201d 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\u2014if you do that, isMuted would get \u201cstuck\u201d with its old value.)\nisMuted\nisMuted", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "isMuted\nisMuted\nTo solve this problem, you need to extract the logic that shouldn\u2019t be reactive out of the Effect. You don\u2019t want this Effect to \u201creact\u201d to the changes in isMuted. Move this non-reactive piece of logic into an Effect Event:\nisMuted", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "import { 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) => {", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "connection.connect(); connection.on('message', (receivedMessage) => { onMessage(receivedMessage); }); return () => connection.disconnect(); }, [roomId]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "import { 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) => {", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "connection.connect(); connection.on('message', (receivedMessage) => { onMessage(receivedMessage); }); return () => connection.disconnect(); }, [roomId]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "Effect Events let you split an Effect into reactive parts (which should \u201creact\u201d 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\u2019t need to be a dependency of your Effect. As a result, the chat won\u2019t re-connect when you toggle the \u201cMuted\u201d setting on and off, solving the original issue!\nroomId\nonMessage\nisMuted\nisMuted", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "roomId\nonMessage\nisMuted\nisMuted\nYou might run into a similar problem when your component receives an event handler as a prop:", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "You might run into a similar problem when your component receives an event handler as a prop:\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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function ChatRoom({ roomId, onReceiveMessage }) { const [messages, setMessages] = useState([]); useEffect(() => { const connection = createConnection(); connection.connect(); connection.on('message', (receivedMessage) => { onReceiveMessage(receivedMessage); }); return () => connection.disconnect(); }, [roomId, onReceiveMessage]); // \u2705 All dependencies declared // ...\nSuppose that the parent component passes a different onReceiveMessage function on every render:", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "Suppose that the parent component passes a different onReceiveMessage function on every render:\nonReceiveMessage\n { // ... }}/>\n { // ... }}/>\nSince 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 Event:", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "onReceiveMessage\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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function 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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "Effect Events aren\u2019t reactive, so you don\u2019t 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\u2019s different on every re-render.\nIn 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\u2019t want a change to notificationCount to trigger a log event.\nroomId\nnotificationCount\nnotificationCount", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "roomId\nnotificationCount\nnotificationCount\nThe solution is again to split out the non-reactive code into an Effect Event:\nfunction Chat({ roomId, notificationCount }) { const onVisit = useEffectEvent(visitedRoomId => { logVisit(visitedRoomId, notificationCount); }); useEffect(() => { onVisit(roomId); }, [roomId]); // \u2705 All dependencies declared // ...}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function Chat({ roomId, notificationCount }) { const onVisit = useEffectEvent(visitedRoomId => { logVisit(visitedRoomId, notificationCount); }); useEffect(() => { onVisit(roomId); }, [roomId]); // \u2705 All dependencies declared // ...}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "You want your logic to be reactive with regards to roomId, so you read roomId inside of your Effect. However, you don\u2019t 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.\nroomId\nroomId\nnotificationCount\nnotificationCount\nDoes some reactive value change unintentionally?", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "roomId\nroomId\nnotificationCount\nnotificationCount\nDoes some reactive value change unintentionally?\nSometimes, you do want your Effect to \u201creact\u201d to a certain value, but that value changes more often than you\u2019d like\u2014and might not reflect any actual change from the user\u2019s perspective. For example, let\u2019s say that you create an options object in the body of your component, and then read that object from inside of your Effect:\noptions", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "options\nfunction ChatRoom({ roomId }) { // ... const options = { serverUrl: serverUrl, roomId: roomId }; useEffect(() => { const connection = createConnection(options); connection.connect(); // ...\nfunction ChatRoom({ roomId }) { // ... const options = { serverUrl: serverUrl, roomId: roomId }; useEffect(() => { const connection = createConnection(options); connection.connect(); // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "This object is declared in the component body, so it\u2019s a reactive value. When you read a reactive value like this inside an Effect, you declare it as a dependency. This ensures your Effect \u201creacts\u201d to its changes:\n// ... useEffect(() => { const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [options]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "// ... useEffect(() => { const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [options]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "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 console:\nroomId\noptions\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "const 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]);", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "return (\n <>\n

          Welcome to the {roomId} room!

          \n setMessage(e.target.value)} />\n \n );\n}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "export default function App() {\n const [roomId, setRoomId] = useState('general');\n return (\n <>\n \n
          \n \n \n );\n}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "\n \n
          \n \n \n );\n}\nIn the sandbox above, the input only updates the message state variable. From the user\u2019s 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.\nmessage\nmessage", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "message\nmessage\nA 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.\noptions\nChatRoom\noptions\noptions\noptions", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "options\nChatRoom\noptions\noptions\noptions\nThis problem only affects objects and functions. In JavaScript, each newly created object and function is considered distinct from all the others. It doesn\u2019t matter that the contents inside of them may be the same!", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "// 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", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "// 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\nObject and function dependencies can make your Effect re-synchronize more often than you need.", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "Object and function dependencies can make your Effect re-synchronize more often than you need.\nThis is why, whenever possible, you should try to avoid objects and functions as your Effect\u2019s dependencies. Instead, try moving them outside the component, inside the Effect, or extracting primitive values out of them.\nIf the object does not depend on any props and state, you can move that object outside your component:", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "const options = { serverUrl: 'https://localhost:1234', roomId: 'music'};function ChatRoom() { const [message, setMessage] = useState(''); useEffect(() => { const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, []); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "const options = { serverUrl: 'https://localhost:1234', roomId: 'music'};function ChatRoom() { const [message, setMessage] = useState(''); useEffect(() => { const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, []); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "This way, you prove to the linter that it\u2019s not reactive. It can\u2019t change as a result of a re-render, so it doesn\u2019t need to be a dependency. Now re-rendering ChatRoom won\u2019t cause your Effect to re-synchronize.\nChatRoom\nThis works for functions too:", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "ChatRoom\nThis works for functions too:\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(); }, []); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function 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(); }, []); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "Since createOptions is declared outside your component, it\u2019s not a reactive value. This is why it doesn\u2019t need to be specified in your Effect\u2019s dependencies, and why it won\u2019t ever cause your Effect to re-synchronize.\ncreateOptions\nIf your object depends on some reactive value that may change as a result of a re-render, like a roomId prop, you can\u2019t pull it outside your component. You can, however, move its creation inside of your Effect\u2019s code:\nroomId", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "roomId\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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "const 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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "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\u2019t be unintentionally different. In JavaScript, numbers and strings are compared by their content:\noptions\nroomId\nroomId", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "options\nroomId\nroomId\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// 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\nThanks to this fix, the chat no longer re-connects if you edit the input:", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "Thanks to this fix, the chat no longer re-connects if you edit the input:\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "const 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]);", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "return (\n <>\n

          Welcome to the {roomId} room!

          \n setMessage(e.target.value)} />\n \n );\n}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "export default function App() {\n const [roomId, setRoomId] = useState('general');\n return (\n <>\n \n
          \n \n \n );\n}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "\n \n
          \n \n \n );\n}\nHowever, it does re-connect when you change the roomId dropdown, as you would expect.\nroomId\nThis works for functions, too:", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "roomId\nThis works for functions, too:\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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "const 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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "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\u2019re not reactive values, and so they don\u2019t need to be dependencies of your Effect.\nSometimes, you may receive an object from props:", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "Sometimes, you may receive an object from props:\nfunction ChatRoom({ options }) { const [message, setMessage] = useState(''); useEffect(() => { const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [options]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function ChatRoom({ options }) { const [message, setMessage] = useState(''); useEffect(() => { const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [options]); // \u2705 All dependencies declared // ...\nThe risk here is that the parent component will create the object during rendering:\n", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "\n\nThis 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 dependencies:", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function 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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function 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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "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.\noptions.roomId\noptions.serverUrl", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "options.roomId\noptions.serverUrl\nThe same approach can work for functions. For example, suppose the parent component passes a function:\n { return { serverUrl: serverUrl, roomId: roomId }; }}/>\n { return { serverUrl: serverUrl, roomId: roomId }; }}/>", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "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\u2019t objects, and that you can read from inside your Effect:\nroomId\nserverUrl", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "roomId\nserverUrl\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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "function 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]); // \u2705 All dependencies declared // ...", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "This only works for pure functions because they are safe to call during rendering. If your function is an event handler, but you don\u2019t want its changes to re-synchronize your Effect, wrap it into an Effect Event instead.\nRecap\nDependencies should always match the code.\nWhen you\u2019re not happy with your dependencies, what you need to edit is the code.\nSuppressing the linter leads to very confusing bugs, and you should always avoid it.", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "Suppressing the linter leads to very confusing bugs, and you should always avoid it.\nTo remove a dependency, you need to \u201cprove\u201d to the linter that it\u2019s not necessary.\nIf some code should run in response to a specific interaction, move that code to an event handler.\nIf different parts of your Effect should re-run for different reasons, split it into several Effects.\nIf you want to update some state based on the previous state, pass an updater function.", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "If you want to update some state based on the previous state, pass an updater function.\nIf you want to read the latest value without \u201creacting\u201d it, extract an Effect Event from your Effect.\nIn JavaScript, objects and functions are considered different if they were created at different times.\nTry to avoid object and function dependencies. Move them outside the component or inside the Effect.\nTry out some challenges", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "Try out some challenges\nThis Effect sets up an interval that ticks every second. You\u2019ve noticed something strange happening: it seems like the interval gets destroyed and re-created every time it ticks. Fix the code so that the interval doesn\u2019t get constantly re-created.\nimport { useState, useEffect } from 'react';", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "export default function Timer() {\n const [count, setCount] = useState(0);\n\n useEffect(() => {\n console.log('\u2705 Creating an interval');\n const id = setInterval(() => {\n console.log('\u23f0 Interval tick');\n setCount(count + 1);\n }, 1000);\n return () => {\n console.log('\u274c Clearing an interval');\n clearInterval(id);\n };\n }, [count]);\n\n return

          Counter: {count}

          \n}", + "title": "Removing Effect Dependencies \u2013 React", + "url": "https://react.dev/learn/removing-effect-dependencies" + }, + { + "content": "Adding Interactivity\nSome 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\u2019ll learn how to write components that handle interactions, update their state, and display different output over time.\nIn this chapter\nHow to handle user-initiated events", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "In this chapter\nHow to handle user-initiated events\nHow to make components \u201cremember\u201d information with state\nHow React updates the UI in two phases\nWhy state doesn\u2019t update right after you change it\nHow to queue multiple state updates\nHow to update an object in state\nHow to update an array in state\nResponding to events", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "How to update an object in state\nHow to update an array in state\nResponding to events\nReact 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.", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "Built-in components like \n \n
          \n );\n}", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "function Button({ onClick, children }) {\n return (\n \n );\n}\nReady to learn this topic?\nRead Responding to Events to learn how to add event handlers.\nState: a component\u2019s memory", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "State: a component\u2019s memory\nComponents often need to change what\u2019s on the screen as a result of an interaction. Typing into the form should update the input field, clicking \u201cnext\u201d on an image carousel should change which image is displayed, clicking \u201cbuy\u201d puts a product in the shopping cart. Components need to \u201cremember\u201d things: the current input value, the current image, the shopping cart. In React, this kind of component-specific memory is called state.", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "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 values: the current state, and a state setter function that lets you update it.\nuseState\nuseState\nconst [index, setIndex] = useState(0);const [showMore, setShowMore] = useState(false);", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "useState\nconst [index, setIndex] = useState(0);const [showMore, setShowMore] = useState(false);\nconst [index, setIndex] = useState(0);const [showMore, setShowMore] = useState(false);\nHere is how an image gallery uses and updates state on click:\nimport { useState } from 'react';\nimport { sculptureList } from './data.js';", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "export 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 }", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "let sculpture = sculptureList[index];\n return (\n <>\n \n

          \n {sculpture.name} \n by {sculpture.artist}\n

          \n

          \n ({index + 1} of {sculptureList.length})\n

          \n \n {showMore &&

          {sculpture.description}

          }\n {sculpture.description}

          }\n \n \n );\n}\nReady to learn this topic?\nRead State: A Component\u2019s Memory to learn how to remember a value and update it on interaction.\nRender and commit\nBefore 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.", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "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 steps:\nTriggering a render (delivering the diner\u2019s order to the kitchen)\nRendering the component (preparing the order in the kitchen)\nCommitting to the DOM (placing the order on the table)\nTrigger\nRender\nCommit\nIllustrated by Rachel Lee Nabors", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "Trigger\nRender\nCommit\nIllustrated by Rachel Lee Nabors\nReady to learn this topic?\nRead Render and Commit to learn the lifecycle of a UI update.\nState as a snapshot\nUnlike 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!\nconsole.log(count); // 0setCount(count + 1); // Request a re-render with 1console.log(count); // Still 0!", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "console.log(count); // 0setCount(count + 1); // Request a re-render with 1console.log(count); // Still 0!\nThis behavior helps you avoid subtle bugs. Here is a little chat app. Try to guess what happens if you press \u201cSend\u201d first and then change the recipient to Bob. Whose name will appear in the alert five seconds later?\nalert\nimport { useState } from 'react';", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "export 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 }", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "return (\n
          \n \n setMessage(e.target.value)}\n />\n \n \n );\n}", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "/>\n \n \n );\n}\nReady to learn this topic?\nRead State as a Snapshot to learn why state appears \u201cfixed\u201d and unchanging inside the event handlers.\nQueueing a series of state updates\nThis component is buggy: clicking \u201c+3\u201d increments the score only once.\nimport { useState } from 'react';", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "export default function Counter() {\n const [score, setScore] = useState(0);\n\n function increment() {\n setScore(score + 1);\n }", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "return (\n <>\n \n \n

          Score: {score}

          \n \n )\n}\nState 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).\nscore\n0\nsetScore(score + 1)", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "score\n0\nsetScore(score + 1)\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\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", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "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 \u201c+3\u201d button. This lets you queue multiple state updates.\nsetScore(score + 1)\nsetScore(s => s + 1)\nimport { useState } from 'react';", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "export default function Counter() {\n const [score, setScore] = useState(0);\n\n function increment() {\n setScore(s => s + 1);\n }", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "return (\n <>\n \n \n

          Score: {score}

          \n \n )\n}\nReady to learn this topic?\nRead Queueing a Series of State Updates to learn how to queue a sequence of state updates.\nUpdating objects in state", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "Updating objects in state\nState can hold any kind of JavaScript value, including objects. But you shouldn\u2019t 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.\nUsually, 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 this:", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "...\nimport { useState } from 'react';", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "export 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://i.imgur.com/Sd1AgUOm.jpg',\n }\n });\n\n function handleNameChange(e) {\n setPerson({\n ...person,\n name: e.target.value\n });\n }", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "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 }", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "return (\n <>\n \n \n \n \n \n

          \n {person.artwork.title}\n {' by '}\n {person.name}\n
          \n (located in {person.artwork.city})\n

          \n \n \n );\n}", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "src={person.artwork.image}\n alt={person.artwork.title}\n />\n \n );\n}\nIf copying objects in code gets tedious, you can use a library like Immer to reduce repetitive code:\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\",", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "\"build\": \"react-scripts build\",\n \"test\": \"react-scripts test --env=jsdom\",\n \"eject\": \"react-scripts eject\"\n },\n \"devDependencies\": {}\n}\nReady to learn this topic?\nRead Updating Objects in State to learn how to update objects correctly.\nUpdating arrays in state", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "Read Updating Objects in State to learn how to update objects correctly.\nUpdating arrays in state\nArrays 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 array:\nimport { useState } from 'react';", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "const 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 );", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "export 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 }", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "return (\n <>\n

          Art Bucket List

          \n

          My list of art to see:

          \n \n \n );\n}", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "function ItemList({ artworks, onToggle }) {\n return (\n
            \n {artworks.map(artwork => (\n
          • \n \n
          • \n ))}\n
          \n );\n}", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "{artwork.title}\n \n \n ))}\n \n );\n}\nIf copying arrays in code gets tedious, you can use a library like Immer to reduce repetitive code:\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\",", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "\"build\": \"react-scripts build\",\n \"test\": \"react-scripts test --env=jsdom\",\n \"eject\": \"react-scripts eject\"\n },\n \"devDependencies\": {}\n}\nReady to learn this topic?\nRead Updating Arrays in State to learn how to update arrays correctly.\nWhat\u2019s next?\nHead over to Responding to Events to start reading this chapter page by page!\nOr, if you\u2019re already familiar with these topics, why not read about Managing State?", + "title": "Adding Interactivity \u2013 React", + "url": "https://react.dev/learn/adding-interactivity" + }, + { + "content": "JavaScript in JSX with Curly Braces\nJSX 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.\nYou will learn\nHow to pass strings with quotes\nHow to reference a JavaScript variable inside JSX with curly braces", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "How to pass strings with quotes\nHow to reference a JavaScript variable inside JSX with curly braces\nHow to call a JavaScript function inside JSX with curly braces\nHow to use a JavaScript object inside JSX with curly braces\nPassing strings with quotes\nWhen you want to pass a string attribute to JSX, you put it in single or double quotes:\nexport default function Avatar() {\n return (\n ", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "src=\"https://i.imgur.com/7vQD0fPs.jpg\"\n alt=\"Gregorio Y. Zara\"\n />\n );\n}\nHere, \"https://i.imgur.com/7vQD0fPs.jpg\" and \"Gregorio Y. Zara\" are being passed as strings.\n\"https://i.imgur.com/7vQD0fPs.jpg\"\n\"Gregorio Y. Zara\"\nBut what if you want to dynamically specify the src or alt text? You could use a value from JavaScript by replacing \" and \" with { and }:\nsrc\nalt\n\"\n\"\n{\n}\nexport default function Avatar() {\n const avatar = 'https://i.imgur.com/7vQD0fPs.jpg';", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "alt\n\"\n\"\n{\n}\nexport default function Avatar() {\n const avatar = 'https://i.imgur.com/7vQD0fPs.jpg';\n const description = 'Gregorio Y. Zara';\n return (\n \n );\n}", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "\n );\n}\nNotice 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\u2019s because curly braces let you work with JavaScript right there in your markup!\nclassName=\"avatar\"\n\"avatar\"\nsrc={avatar}\navatar\nUsing curly braces: A window into the JavaScript world", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "\"avatar\"\nsrc={avatar}\navatar\nUsing curly braces: A window into the JavaScript world\nJSX is a special way of writing JavaScript. That means it\u2019s possible to use JavaScript inside it\u2014with curly braces { }. The example below first declares a name for the scientist, name, then embeds it with curly braces inside the

          :\n{ }\nname\n

          \nexport default function TodoList() {\n const name = 'Gregorio Y. Zara';\n return (\n

          {name}'s To Do List

          \n );\n}", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "const name = 'Gregorio Y. Zara';\n return (\n

          {name}'s To Do List

          \n );\n}\nTry changing the name\u2019s value from 'Gregorio Y. Zara' to 'Hedy Lamarr'. See how the list title changes?\nname\n'Gregorio Y. Zara'\n'Hedy Lamarr'\nAny JavaScript expression will work between curly braces, including function calls like formatDate():\nformatDate()\nconst today = new Date();", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "function formatDate(date) {\n return new Intl.DateTimeFormat(\n 'en-US',\n { weekday: 'long' }\n ).format(date);\n}", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "export default function TodoList() {\n return (\n

          To Do List for {formatDate(today)}

          \n );\n}\nWhere to use curly braces\nYou can only use curly braces in two ways inside JSX:\nAs text directly inside a JSX tag:

          {name}'s To Do List

          works, but <{tag}>Gregorio Y. Zara's To Do List will not.\n

          {name}'s To Do List

          \n<{tag}>Gregorio Y. Zara's To Do List", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "

          {name}'s To Do List

          \n<{tag}>Gregorio Y. Zara's To Do List\nAs attributes immediately following the = sign: src={avatar} will read the avatar variable, but src=\"{avatar}\" will pass the string \"{avatar}\".\n=\nsrc={avatar}\navatar\nsrc=\"{avatar}\"\n\"{avatar}\"\nUsing \u201cdouble curlies\u201d: CSS and other objects in JSX", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "src={avatar}\navatar\nsrc=\"{avatar}\"\n\"{avatar}\"\nUsing \u201cdouble curlies\u201d: CSS and other objects in JSX\nIn 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\", inventions: 5 }. Therefore, to pass a JS object in JSX, you must wrap the object in another pair of curly braces: person={{ name: \"Hedy Lamarr\", inventions: 5 }}.\n{ name: \"Hedy Lamarr\", inventions: 5 }", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "{ name: \"Hedy Lamarr\", inventions: 5 }\nperson={{ name: \"Hedy Lamarr\", inventions: 5 }}\nYou 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 attribute:\nstyle\nexport default function TodoList() {\n return (\n
            \n
          • Improve the videophone
          • ", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "backgroundColor: 'black',\n color: 'pink'\n }}>\n
          • Improve the videophone
          • \n
          • Prepare aeronautics lectures
          • \n
          • Work on the alcohol-fuelled engine
          • \n
          \n );\n}\nTry changing the values of backgroundColor and color.\nbackgroundColor\ncolor\nYou can really see the JavaScript object inside the curly braces when you write it like this:\n
            ", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "
              \n
                \nThe next time you see {{ and }} in JSX, know that it\u2019s nothing more than an object inside the JSX curlies!\n{{\n}}\nPitfall\nInline style properties are written in camelCase. For example, HTML
                  would be written as
                    in your component.\nstyle\n
                      ", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "style\n
                        \n
                          \nMore fun with JavaScript objects and curly braces\nYou can move several expressions into one object, and reference them in your JSX inside curly braces:\nconst person = {\n name: 'Gregorio Y. Zara',\n theme: {\n backgroundColor: 'black',\n color: 'pink'\n }\n};", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "export default function TodoList() {\n return (\n
                          \n

                          {person.name}'s Todos

                          \n \n
                            \n
                          • Improve the videophone
                          • \n
                          • Prepare aeronautics lectures
                          • \n
                          • Work on the alcohol-fuelled engine
                          • \n
                          \n
                          \n );\n}", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "
                        • Work on the alcohol-fuelled engine
                        • \n
                        \n
          \n );\n}\nIn this example, the person JavaScript object contains a name string and a theme object:\nperson\nname\ntheme\nconst person = { name: 'Gregorio Y. Zara', theme: { backgroundColor: 'black', color: 'pink' }};\nconst person = { name: 'Gregorio Y. Zara', theme: { backgroundColor: 'black', color: 'pink' }};\nThe component can use these values from person like so:\nperson", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "The component can use these values from person like so:\nperson\n

          {person.name}'s Todos

          \n

          {person.name}'s Todos

          \nJSX is very minimal as a templating language because it lets you organize data and logic using JavaScript.\nRecap\nNow you know almost everything about JSX:\nJSX attributes inside quotes are passed as strings.\nCurly braces let you bring JavaScript logic and variables into your markup.", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "Curly braces let you bring JavaScript logic and variables into your markup.\nThey work inside the JSX tag content or immediately after = in attributes.\n=\n{{ and }} is not special syntax: it\u2019s a JavaScript object tucked inside JSX curly braces.\n{{\n}}\nTry out some challenges\nThis code crashes with an error saying Objects are not valid as a React child:\nObjects are not valid as a React child\nconst person = {\n name: 'Gregorio Y. Zara',\n theme: {\n backgroundColor: 'black',\n color: 'pink'\n }", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "name: 'Gregorio Y. Zara',\n theme: {\n backgroundColor: 'black',\n color: 'pink'\n }\n};", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "export default function TodoList() {\n return (\n
          \n

          {person}'s Todos

          \n \n
            \n
          • Improve the videophone
          • \n
          • Prepare aeronautics lectures
          • \n
          • Work on the alcohol-fuelled engine
          • \n
          \n
          \n );\n}\nCan you find the problem?", + "title": "JavaScript in JSX with Curly Braces \u2013 React", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + }, + { + "content": "Conditional Rendering\nYour 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.\nif\n&&\n? :\nYou will learn\nHow to return different JSX depending on a condition\nHow to conditionally include or exclude a piece of JSX\nCommon conditional syntax shortcuts you\u2019ll encounter in React codebases\nConditionally returning JSX", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "Common conditional syntax shortcuts you\u2019ll encounter in React codebases\nConditionally returning JSX\nLet\u2019s say you have a PackingList component rendering several Items, which can be marked as packed or not:\nPackingList\nItem\nfunction Item({ name, isPacked }) {\n return
        19. {name}
        20. ;\n}", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "export default function PackingList() {\n return (\n
          \n

          Sally Ride's Packing List

          \n
            \n \n \n \n
          \n
          \n );\n}", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "name=\"Photo of Tam\" \n />\n \n

          \n );\n}\nNotice that some of the Item components have their isPacked prop set to true instead of false. You want to add a checkmark (\u2705) to packed items if isPacked={true}.\nItem\nisPacked\ntrue\nfalse\nisPacked={true}\nYou can write this as an if/else statement like so:\nif\nelse\nif (isPacked) { return
        21. {name} \u2705
        22. ;}return
        23. {name}
        24. ;", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "if (isPacked) { return
        25. {name} \u2705
        26. ;}return
        27. {name}
        28. ;\nIf the isPacked prop is true, this code returns a different JSX tree. With this change, some of the items get a checkmark at the end:\nisPacked\ntrue\nfunction Item({ name, isPacked }) {\n if (isPacked) {\n return
        29. {name} \u2705
        30. ;\n }\n return
        31. {name}
        32. ;\n}", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "export default function PackingList() {\n return (\n
          \n

          Sally Ride's Packing List

          \n
            \n \n \n \n
          \n
          \n );\n}\nTry editing what gets returned in either case, and see how the result changes!", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": ");\n}\nTry editing what gets returned in either case, and see how the result changes!\nNotice how you\u2019re creating branching logic with JavaScript\u2019s if and return statements. In React, control flow (like conditions) is handled by JavaScript.\nif\nreturn\nConditionally returning nothing with null\nnull\nIn some situations, you won\u2019t want to render anything at all. For example, say you don\u2019t want to show packed items at all. A component must return something. In this case, you can return null:\nnull", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "null\nif (isPacked) { return null;}return
        33. {name}
        34. ;\nif (isPacked) { return null;}return
        35. {name}
        36. ;\nIf isPacked is true, the component will return nothing, null. Otherwise, it will return JSX to render.\nisPacked\nnull\nfunction Item({ name, isPacked }) {\n if (isPacked) {\n return null;\n }\n return
        37. {name}
        38. ;\n}", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "export default function PackingList() {\n return (\n
          \n

          Sally Ride's Packing List

          \n
            \n \n \n \n
          \n
          \n );\n}", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "name=\"Photo of Tam\" \n />\n \n
          \n );\n}\nIn practice, returning null from a component isn\u2019t 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\u2019s JSX. Here\u2019s how to do that!\nnull\nConditionally including JSX", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "null\nConditionally including JSX\nIn 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:\n
        39. {name} \u2705
        40. \n
        41. {name} \u2705
        42. \nis very similar to\n
        43. {name}
        44. \n
        45. {name}
        46. \nBoth of the conditional branches return
        47. ...
        48. :\n
        49. ...
        50. ", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "
        51. ...
        52. \nif (isPacked) { return
        53. {name} \u2705
        54. ;}return
        55. {name}
        56. ;\nif (isPacked) { return
        57. {name} \u2705
        58. ;}return
        59. {name}
        60. ;\nWhile this duplication isn\u2019t harmful, it could make your code harder to maintain. What if you want to change the className? You\u2019d 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.", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "className\nConditional (ternary) operator (? :)\n? :\nJavaScript has a compact syntax for writing a conditional expression \u2014 the conditional operator or \u201cternary operator\u201d.\nInstead of this:\nif (isPacked) { return
        61. {name} \u2705
        62. ;}return
        63. {name}
        64. ;\nif (isPacked) { return
        65. {name} \u2705
        66. ;}return
        67. {name}
        68. ;\nYou can write this:\nreturn (
        69. {isPacked ? name + ' \u2705' : name}
        70. );", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "You can write this:\nreturn (
        71. {isPacked ? name + ' \u2705' : name}
        72. );\nreturn (
        73. {isPacked ? name + ' \u2705' : name}
        74. );\nYou can read it as \u201cif isPacked is true, then (?) render name + ' \u2705', otherwise (:) render name\u201d.\nisPacked\n?\nname + ' \u2705'\n:\nname", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": ":\nname\nIf you\u2019re 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 \u201cinstances\u201d of
        75. . But JSX elements aren\u2019t \u201cinstances\u201d because they don\u2019t hold any internal state and aren\u2019t real DOM nodes. They\u2019re lightweight descriptions, like blueprints. So these two examples, in fact, are completely equivalent. Preserving and Resetting State goes into detail about how this works.\n
        76. ", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "
        77. \nNow let\u2019s say you want to wrap the completed item\u2019s text into another HTML tag, like to strike it out. You can add even more newlines and parentheses so that it\u2019s easier to nest more JSX in each of the cases:\n\nfunction Item({ name, isPacked }) {\n return (\n
        78. \n {isPacked ? (\n \n {name + ' \u2705'}\n \n ) : (\n name\n )}\n
        79. \n );\n}", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "export default function PackingList() {\n return (\n
          \n

          Sally Ride's Packing List

          \n
            \n \n \n \n
          \n
          \n );\n}", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "name=\"Photo of Tam\" \n />\n \n \n );\n}\nThis 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.\nLogical AND operator (&&)\n&&", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "Logical AND operator (&&)\n&&\nAnother common shortcut you\u2019ll 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 true:\n&&\n&&\nisPacked\ntrue\nreturn (
        80. {name} {isPacked && '\u2705'}
        81. );\nreturn (
        82. {name} {isPacked && '\u2705'}
        83. );", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "return (
        84. {name} {isPacked && '\u2705'}
        85. );\nYou can read this as \u201cif isPacked, then (&&) render the checkmark, otherwise, render nothing\u201d.\nisPacked\n&&\nHere it is in action:\nfunction Item({ name, isPacked }) {\n return (\n
        86. \n {name} {isPacked && '\u2705'}\n
        87. \n );\n}", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "export default function PackingList() {\n return (\n
          \n

          Sally Ride's Packing List

          \n
            \n \n \n \n
          \n
          \n );\n}", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "name=\"Photo of Tam\" \n />\n \n \n );\n}\nA 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 \u201chole\u201d in the JSX tree, just like null or undefined, and doesn\u2019t render anything in its place.\ntrue\nfalse\nfalse\nfalse\nnull\nundefined\nPitfall\nDon\u2019t put numbers on the left side of &&.\n&&", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "true\nfalse\nfalse\nfalse\nnull\nundefined\nPitfall\nDon\u2019t put numbers on the left side of &&.\n&&\nTo 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.\n0\n0\n0", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "0\n0\n0\nFor example, a common mistake is to write code like messageCount &&

          New messages

          . It\u2019s easy to assume that it renders nothing when messageCount is 0, but it really renders the 0 itself!\nmessageCount &&

          New messages

          \nmessageCount\n0\n0\nTo fix it, make the left side a boolean: messageCount > 0 &&

          New messages

          .\nmessageCount > 0 &&

          New messages

          \nConditionally assigning JSX to a variable", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "messageCount > 0 &&

          New messages

          \nConditionally assigning JSX to a variable\nWhen 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 name:\nif\nlet\nlet itemContent = name;\nlet itemContent = name;\nUse an if statement to reassign a JSX expression to itemContent if isPacked is true:\nif\nitemContent\nisPacked\ntrue", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "if\nitemContent\nisPacked\ntrue\nif (isPacked) { itemContent = name + \" \u2705\";}\nif (isPacked) { itemContent = name + \" \u2705\";}\nCurly braces open the \u201cwindow into JavaScript\u201d. Embed the variable with curly braces in the returned JSX tree, nesting the previously calculated expression inside of JSX:\n
        88. {itemContent}
        89. \n
        90. {itemContent}
        91. \nThis style is the most verbose, but it\u2019s also the most flexible. Here it is in action:\nfunction Item({ name, isPacked }) {", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "function Item({ name, isPacked }) {\n let itemContent = name;\n if (isPacked) {\n itemContent = name + \" \u2705\";\n }\n return (\n
        92. \n {itemContent}\n
        93. \n );\n}", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "export default function PackingList() {\n return (\n
          \n

          Sally Ride's Packing List

          \n
            \n \n \n \n
          \n
          \n );\n}\nLike before, this works not only for text, but for arbitrary JSX too:", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "\n );\n}\nLike before, this works not only for text, but for arbitrary JSX too:\nfunction Item({ name, isPacked }) {\n let itemContent = name;\n if (isPacked) {\n itemContent = (\n \n {name + \" \u2705\"}\n \n );\n }\n return (\n
        94. \n {itemContent}\n
        95. \n );\n}", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "export default function PackingList() {\n return (\n
          \n

          Sally Ride's Packing List

          \n
            \n \n \n \n
          \n
          \n );\n}", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "name=\"Photo of Tam\" \n />\n \n \n );\n}\nIf you\u2019re 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 \u2014 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.\nRecap\nIn React, you control branching logic with JavaScript.", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "Recap\nIn React, you control branching logic with JavaScript.\nYou can return a JSX expression conditionally with an if statement.\nif\nYou can conditionally save some JSX to a variable and then include it inside other JSX by using the curly braces.\nIn JSX, {cond ? : } means \u201cif cond, render , otherwise \u201d.\n{cond ? : }\ncond\n\n\nIn JSX, {cond && } means \u201cif cond, render , otherwise nothing\u201d.\n{cond && }\ncond\n", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "{cond && }\ncond\n\nThe shortcuts are common, but you don\u2019t have to use them if you prefer plain if.\nif\nTry out some challenges\n? :\n&&\n? :\nif\n? :\nUse the conditional operator (cond ? a : b) to render a \u274c if isPacked isn\u2019t true.\ncond ? a : b\nisPacked\ntrue\nfunction Item({ name, isPacked }) {\n return (\n
        96. \n {name} {isPacked && '\u2705'}\n
        97. \n );\n}", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "export default function PackingList() {\n return (\n
          \n

          Sally Ride's Packing List

          \n
            \n \n \n \n
          \n
          \n );\n}", + "title": "Conditional Rendering \u2013 React", + "url": "https://react.dev/learn/conditional-rendering" + }, + { + "content": "React Compiler\nThis page will give you an introduction to React Compiler and how to try it out successfully.\nYou will learn\nGetting started with the compiler\nInstalling the compiler and ESLint plugin\nTroubleshooting\nNote\nReact Compiler is a new compiler currently in RC, that we\u2019ve open sourced to get feedback from the community. We now recommend everyone to try the compiler and provide feedback.", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "The latest RC release can be found with the @rc tag, and daily experimental releases with @experimental.\n@rc\n@experimental\nReact Compiler is a new compiler that we\u2019ve open sourced to get feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the Rules of React, so you don\u2019t need to rewrite any code to use it.", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "eslint-plugin-react-hooks also includes an ESLint rule that surfaces the analysis from the compiler right in your editor. We strongly recommend everyone use the linter today. The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler.\nThe compiler is currently released as rc, and is available to try out on React 17+ apps and libraries. To install the RC:\nrc\nOr, if you\u2019re using Yarn:", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "rc\nOr, if you\u2019re using Yarn:\nIf you are not using React 19 yet, please see the section below for further instructions.\nWhat does the compiler do?", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "In order to optimize applications, React Compiler automatically memoizes your code. You may be familiar today with memoization through APIs such as useMemo, useCallback, and React.memo. With these APIs you can tell React that certain parts of your application don\u2019t need to recompute if their inputs haven\u2019t changed, reducing work on updates. While powerful, it\u2019s easy to forget to apply memoization or apply them incorrectly. This can lead to inefficient updates as React has to check parts of your", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "or apply them incorrectly. This can lead to inefficient updates as React has to check parts of your UI that don\u2019t have any meaningful changes.", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "useMemo\nuseCallback\nReact.memo\nThe compiler uses its knowledge of JavaScript and React\u2019s rules to automatically memoize values or groups of values within your components and hooks. If it detects breakages of the rules, it will automatically skip over just those components or hooks, and continue safely compiling other code.\nNote", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "Note\nReact Compiler can statically detect when Rules of React are broken, and safely opt-out of optimizing just the affected components or hooks. It is not necessary for the compiler to optimize 100% of your codebase.\nIf your codebase is already very well-memoized, you might not expect to see major performance improvements with the compiler. However, in practice memoizing the correct dependencies that cause performance issues is tricky to get right by hand.", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "The initial release of React Compiler is primarily focused on improving update performance (re-rendering existing components), so it focuses on these two use cases:\nSkipping cascading re-rendering of components", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "Re-rendering causes many components in its component tree to re-render, even though only has changed\nRe-rendering causes many components in its component tree to re-render, even though only has changed\n\n\nSkipping expensive calculations from outside of React", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "For example, calling expensivelyProcessAReallyLargeArrayOfObjects() inside of your component or hook that needs that data\nFor example, calling expensivelyProcessAReallyLargeArrayOfObjects() inside of your component or hook that needs that data\nexpensivelyProcessAReallyLargeArrayOfObjects()", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component\u2019s state changes, React will re-render that component and all of its children \u2014 unless you have applied some form of manual memoization with useMemo(), useCallback(), or React.memo(). For example, in the following example, will re-render whenever \u2019s state changes:\nuseMemo()\nuseCallback()\nReact.memo()", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "useMemo()\nuseCallback()\nReact.memo()\n\n\nfunction FriendList({ friends }) { const onlineCount = useFriendOnlineCount(); if (friends.length === 0) { return ; } return (
          {onlineCount} online {friends.map((friend) => ( ))}
          );}", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "function FriendList({ friends }) { const onlineCount = useFriendOnlineCount(); if (friends.length === 0) { return ; } return (
          {onlineCount} online {friends.map((friend) => ( ))}
          );}\nSee this example in the React Compiler Playground", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "See this example in the React Compiler Playground\nReact 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 \u201cfine-grained reactivity\u201d. In the above example, React Compiler determines that the return value of can be reused even as friends changes, and can avoid recreating this JSX and avoid re-rendering as the count changes.", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "\nfriends\n\nThe compiler can also automatically memoize for expensive calculations used during rendering:\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); // ...}", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "// **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); // ...}\nSee this example in the React Compiler Playground", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "See this example in the React Compiler Playground\nHowever, if expensivelyProcessAReallyLargeArrayOfObjects is truly an expensive function, you may want to consider implementing its own memoization outside of React, because:\nexpensivelyProcessAReallyLargeArrayOfObjects\nReact Compiler only memoizes React components and hooks, not every function\nReact Compiler\u2019s memoization is not shared across multiple components or hooks", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "React Compiler\u2019s memoization is not shared across multiple components or hooks\nSo 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.\nexpensivelyProcessAReallyLargeArrayOfObjects\nShould I try out the compiler?", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "expensivelyProcessAReallyLargeArrayOfObjects\nShould I try out the compiler?\nThe compiler is now in RC 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\u2019ve followed the Rules of React.", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "You don\u2019t have to rush into using the compiler now. It\u2019s okay to wait until it reaches a stable release before adopting it. However, we do appreciate trying it out in small experiments in your apps so that you can provide feedback to us to help make the compiler better.\nGetting Started\nIn addition to these docs, we recommend checking the React Compiler Working Group for additional information and discussion about the compiler.\nInstalling eslint-plugin-react-hooks", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "Installing eslint-plugin-react-hooks\nReact Compiler also powers an ESLint plugin. You can try it out by installing eslint-plugin-react-hooks@^6.0.0-rc.1.\nSee our editor setup guide for more details.\nThe ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase.\nNote", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "Note\nYou don\u2019t have to fix all ESLint violations straight away. You can address them at your own pace to increase the amount of components and hooks being optimized, but it is not required to fix everything before you can use the compiler.\nRolling out the compiler to your codebase", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "The compiler is designed to compile functional components and hooks that follow the Rules of React. It can also handle code that breaks those rules by bailing out (skipping over) those components or hooks. However, due to the flexible nature of JavaScript, the compiler cannot catch every possible violation and may compile with false negatives: that is, the compiler may accidentally compile a component/hook that breaks the Rules of React which can lead to undefined behavior.", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "For this reason, to adopt the compiler successfully on existing projects, we recommend running it on a small directory in your product code first. You can do this by configuring the compiler to only run on a specific set of directories:\nconst ReactCompilerConfig = { sources: (filename) => { return filename.indexOf('src/path/to/dir') !== -1; },};\nconst ReactCompilerConfig = { sources: (filename) => { return filename.indexOf('src/path/to/dir') !== -1; },};", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "When you have more confidence with rolling out the compiler, you can expand coverage to other directories as well and slowly roll it out to your whole app.\nIf you\u2019re starting a new project, you can enable the compiler on your entire codebase, which is the default behavior.\nUsing React Compiler with React 17 or 18", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "Using React Compiler with React 17 or 18\nReact Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra react-compiler-runtime package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17.\nreact-compiler-runtime\nYou should also add the correct target to your compiler config, where target is the major version of React you are targeting:\ntarget\ntarget", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "target\ntarget\n// babel.config.jsconst ReactCompilerConfig = { target: '18' // '17' | '18' | '19'};module.exports = function () { return { plugins: [ ['babel-plugin-react-compiler', ReactCompilerConfig], ], };};\n// babel.config.jsconst ReactCompilerConfig = { target: '18' // '17' | '18' | '19'};module.exports = function () { return { plugins: [ ['babel-plugin-react-compiler', ReactCompilerConfig], ], };};\nUsing the compiler on libraries", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "Using the compiler on libraries\nReact Compiler can also be used to compile libraries. Because React Compiler needs to run on the original source code prior to any code transformations, it is not possible for an application\u2019s build pipeline to compile the libraries they use. Hence, our recommendation is for library maintainers to independently compile and test their libraries with the compiler, and ship compiled code to npm.", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "Because your code is pre-compiled, users of your library will not need to have the compiler enabled in order to benefit from the automatic memoization applied to your library. If your library targets apps not yet on React 19, specify a minimum target and add react-compiler-runtime as a direct dependency. The runtime package will use the correct implementation of APIs depending on the application\u2019s version, and polyfill the missing APIs if necessary.\ntarget\nreact-compiler-runtime", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "target\nreact-compiler-runtime\nLibrary code can often require more complex patterns and usage of escape hatches. For this reason, we recommend ensuring that you have sufficient testing in order to identify any issues that might arise from using the compiler on your library. If you identify any issues, you can always opt-out the specific components or hooks with the 'use no memo' directive.\n'use no memo'", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "'use no memo'\nSimilarly to apps, it is not necessary to fully compile 100% of your components or hooks to see benefits in your library. A good starting point might be to identify the most performance sensitive parts of your library and ensuring that they don\u2019t break the Rules of React, which you can use eslint-plugin-react-compiler to identify.\neslint-plugin-react-compiler\nUsage\nBabel\nThe compiler includes a Babel plugin which you can use in your build pipeline to run the compiler.", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler.\nAfter installing, add it to your Babel config. Please note that it\u2019s critical that the compiler run first in the pipeline:\n// babel.config.jsconst ReactCompilerConfig = { /* ... */ };module.exports = function () { return { plugins: [ ['babel-plugin-react-compiler', ReactCompilerConfig], // must run first! // ... ], };};", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "// babel.config.jsconst ReactCompilerConfig = { /* ... */ };module.exports = function () { return { plugins: [ ['babel-plugin-react-compiler', ReactCompilerConfig], // must run first! // ... ], };};\nbabel-plugin-react-compiler should run first before other Babel plugins as the compiler requires the input source information for sound analysis.\nbabel-plugin-react-compiler\nVite\nIf you use Vite, you can add the plugin to vite-plugin-react:", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "babel-plugin-react-compiler\nVite\nIf you use Vite, you can add the plugin to vite-plugin-react:\n// vite.config.jsconst ReactCompilerConfig = { /* ... */ };export default defineConfig(() => { return { plugins: [ react({ babel: { plugins: [ [\"babel-plugin-react-compiler\", ReactCompilerConfig], ], }, }), ], // ... };});", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "// vite.config.jsconst ReactCompilerConfig = { /* ... */ };export default defineConfig(() => { return { plugins: [ react({ babel: { plugins: [ [\"babel-plugin-react-compiler\", ReactCompilerConfig], ], }, }), ], // ... };});\nNext.js\nPlease refer to the Next.js docs for more information.\nRemix\nInstall vite-plugin-babel, and add the compiler\u2019s Babel plugin to it:\nvite-plugin-babel", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "Remix\nInstall vite-plugin-babel, and add the compiler\u2019s Babel plugin to it:\nvite-plugin-babel\n// vite.config.jsimport babel from \"vite-plugin-babel\";const ReactCompilerConfig = { /* ... */ };export default defineConfig({ plugins: [ remix({ /* ... */}), babel({ filter: /\\.[jt]sx?$/, babelConfig: { presets: [\"@babel/preset-typescript\"], // if you use TypeScript plugins: [ [\"babel-plugin-react-compiler\", ReactCompilerConfig], ], }, }), ],});", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "// vite.config.jsimport babel from \"vite-plugin-babel\";const ReactCompilerConfig = { /* ... */ };export default defineConfig({ plugins: [ remix({ /* ... */}), babel({ filter: /\\.[jt]sx?$/, babelConfig: { presets: [\"@babel/preset-typescript\"], // if you use TypeScript plugins: [ [\"babel-plugin-react-compiler\", ReactCompilerConfig], ], }, }), ],});\nWebpack\nA community webpack loader is now available here.\nExpo", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "Webpack\nA community webpack loader is now available here.\nExpo\nPlease refer to Expo\u2019s docs to enable and use the React Compiler in Expo apps.\nMetro (React Native)\nReact Native uses Babel via Metro, so refer to the Usage with Babel section for installation instructions.\nRspack\nPlease refer to Rspack\u2019s docs to enable and use the React Compiler in Rspack apps.\nRsbuild\nPlease refer to Rsbuild\u2019s docs to enable and use the React Compiler in Rsbuild apps.\nTroubleshooting", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "Troubleshooting\nTo report issues, please first create a minimal repro on the React Compiler Playground and include it in your bug report. You can open issues in the facebook/react repo.\nYou can also provide feedback in the React Compiler Working Group by applying to be a member. Please see the README for more details on joining.\nWhat does the compiler assume?\nReact Compiler assumes that your code:\nIs valid, semantic JavaScript.", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "React Compiler assumes that your code:\nIs valid, semantic JavaScript.\nTests that nullable/optional values and properties are defined before accessing them (for example, by enabling strictNullChecks if using TypeScript), i.e., if (object.nullableProperty) { object.nullableProperty.foo } or with optional-chaining object.nullableProperty?.foo.\nstrictNullChecks\nif (object.nullableProperty) { object.nullableProperty.foo }\nobject.nullableProperty?.foo\nFollows the Rules of React.", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "object.nullableProperty?.foo\nFollows the Rules of React.\nReact Compiler can verify many of the Rules of React statically, and will safely skip compilation when it detects an error. To see the errors we recommend also installing eslint-plugin-react-compiler.\nHow do I know my components have been optimized?\nReact DevTools (v5.0+) and React Native DevTools have built-in support for React Compiler and will display a \u201cMemo \u2728\u201d badge next to components that have been optimized by the compiler.", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "Something is not working after compilation", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "If you have eslint-plugin-react-compiler installed, the compiler will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. You don\u2019t have to fix all ESLint violations straight away. You can address them at your own pace to increase the amount of components and hooks being", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "away. You can address them at your own pace to increase the amount of components and hooks being optimized.", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "Due to the flexible and dynamic nature of JavaScript however, it\u2019s not possible to comprehensively detect all cases. Bugs and undefined behavior such as infinite loops may occur in those cases.\nIf your app doesn\u2019t work properly after compilation and you aren\u2019t seeing any ESLint errors, the compiler may be incorrectly compiling your code. To confirm this, try to make the issue go away by aggressively opting out any component or hook you think might be related via the \"use no memo\" directive.", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "\"use no memo\"\nfunction SuspiciousComponent() { \"use no memo\"; // opts out this component from being compiled by React Compiler // ...}\nfunction SuspiciousComponent() { \"use no memo\"; // opts out this component from being compiled by React Compiler // ...}\nNote\n\"use no memo\"\n\"use no memo\" is a temporary escape hatch that lets you opt-out components and hooks from being compiled by the React Compiler. This directive is not meant to be long lived the same way as eg \"use client\" is.", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "\"use no memo\"\n\"use client\"\nIt is not recommended to reach for this directive unless it\u2019s strictly necessary. Once you opt-out a component or hook, it is opted-out forever until the directive is removed. This means that even if you fix the code, the compiler will still skip over compiling it unless you remove the directive.", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "When you make the error go away, confirm that removing the opt out directive makes the issue come back. Then share a bug report with us (you can try to reduce it to a small repro, or if it\u2019s open source code you can also just paste the entire source) using the React Compiler Playground so we can identify and help fix the issue.\nOther issues\nPlease see https://github.com/reactwg/react-compiler/discussions/7.", + "title": "React Compiler \u2013 React", + "url": "https://react.dev/learn/react-compiler" + }, + { + "content": "Updating Objects in State\nState can hold any kind of JavaScript value, including objects. But you shouldn\u2019t 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.\nYou will learn\nHow to correctly update an object in React state\nHow to update a nested object without mutating it\nWhat immutability is, and how not to break it", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "How to update a nested object without mutating it\nWhat immutability is, and how not to break it\nHow to make object copying less repetitive with Immer\nWhat\u2019s a mutation?\nYou can store any kind of JavaScript value in state.\nconst [x, setX] = useState(0);\nconst [x, setX] = useState(0);\nSo far you\u2019ve been working with numbers, strings, and booleans. These kinds of JavaScript values are \u201cimmutable\u201d, meaning unchangeable or \u201cread-only\u201d. You can trigger a re-render to replace a value:\nsetX(5);", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "setX(5);\nsetX(5);\nThe x state changed from 0 to 5, but the number 0 itself did not change. It\u2019s not possible to make any changes to the built-in primitive values like numbers, strings, and booleans in JavaScript.\nx\n0\n5\n0\nNow consider an object in state:\nconst [position, setPosition] = useState({ x: 0, y: 0 });\nconst [position, setPosition] = useState({ x: 0, y: 0 });\nTechnically, it is possible to change the contents of the object itself. This is called a mutation:\nposition.x = 5;", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "position.x = 5;\nposition.x = 5;\nHowever, although objects in React state are technically mutable, you should treat them as if they were immutable\u2014like numbers, booleans, and strings. Instead of mutating them, you should always replace them.\nTreat state as read-only\nIn other words, you should treat any JavaScript object that you put into state as read-only.", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "In other words, you should treat any JavaScript object that you put into state as read-only.\nThis 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 position:\nimport { useState } from 'react';", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "export default function MovingDot() {\n const [position, setPosition] = useState({\n x: 0,\n y: 0\n });\n return (\n {\n position.x = e.clientX;\n position.y = e.clientY;\n }}\n style={{\n position: 'relative',\n width: '100vw',\n height: '100vh',\n }}>\n
          \n
          \n );\n}\nThe problem is with this bit of code.\nonPointerMove={e => { position.x = e.clientX; position.y = e.clientY;}}\nonPointerMove={e => { position.x = e.clientX; position.y = e.clientY;}}", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "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\u2019s like trying to change the order after you\u2019ve already eaten the meal. While mutating state can work in some cases, we don\u2019t recommend it. You should treat the state value you have access to in a render as read-only.\nposition", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "position\nTo actually trigger a re-render in this case, create a new object and pass it to the state setting function:\nonPointerMove={e => { setPosition({ x: e.clientX, y: e.clientY });}}\nonPointerMove={e => { setPosition({ x: e.clientX, y: e.clientY });}}\nWith setPosition, you\u2019re telling React:\nsetPosition\nReplace position with this new object\nposition\nAnd render this component again\nNotice how the red dot now follows your pointer when you touch or hover over the preview area:", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "Notice how the red dot now follows your pointer when you touch or hover over the preview area:\nimport { useState } from 'react';", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "export default function MovingDot() {\n const [position, setPosition] = useState({\n x: 0,\n y: 0\n });\n return (\n {\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
          \n
          \n );\n}\nCode like this is a problem because it modifies an existing object in state:\nposition.x = e.clientX;position.y = e.clientY;\nposition.x = e.clientX;position.y = e.clientY;", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "position.x = e.clientX;position.y = e.clientY;\nposition.x = e.clientX;position.y = e.clientY;\nBut code like this is absolutely fine because you\u2019re mutating a fresh object you have just created:\nconst nextPosition = {};nextPosition.x = e.clientX;nextPosition.y = e.clientY;setPosition(nextPosition);\nconst nextPosition = {};nextPosition.x = e.clientX;nextPosition.y = e.clientY;setPosition(nextPosition);\nIn fact, it is completely equivalent to writing this:", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "In fact, it is completely equivalent to writing this:\nsetPosition({ x: e.clientX, y: e.clientY});\nsetPosition({ x: e.clientX, y: e.clientY});", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "setPosition({ x: e.clientX, y: e.clientY});\nsetPosition({ x: e.clientX, y: e.clientY});\nMutation is only a problem when you change existing objects that are already in state. Mutating an object you\u2019ve just created is okay because no other code references it yet. Changing it isn\u2019t going to accidentally impact something that depends on it. This is called a \u201clocal mutation\u201d. You can even do local mutation while rendering. Very convenient and completely okay!", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "Copying objects with the spread syntax\nIn 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\u2019re creating. For example, you may want to update only one field in a form, but keep the previous values for all other fields.\nposition\nThese input fields don\u2019t work because the onChange handlers mutate the state:\nonChange\nimport { useState } from 'react';", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "export 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 }", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "return (\n <>\n \n \n \n

          ", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "onChange={handleEmailChange}\n />\n \n

          \n {person.firstName}{' '}\n {person.lastName}{' '}\n ({person.email})\n

          \n \n );\n}\nFor example, this line mutates the state from a past render:\nperson.firstName = e.target.value;\nperson.firstName = e.target.value;", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "person.firstName = e.target.value;\nperson.firstName = e.target.value;\nThe reliable way to get the behavior you\u2019re 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 changed:\nsetPerson\nsetPerson({ firstName: e.target.value, // New first name from the input lastName: person.lastName, email: person.email});", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "setPerson({ firstName: e.target.value, // New first name from the input lastName: person.lastName, email: person.email});\nYou can use the ... object spread syntax so that you don\u2019t need to copy every property separately.\n...\nsetPerson({ ...person, // Copy the old fields firstName: e.target.value // But override this one});\nsetPerson({ ...person, // Copy the old fields firstName: e.target.value // But override this one});\nNow the form works!", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "Now the form works!\nNotice how you didn\u2019t declare a separate state variable for each input field. For large forms, keeping all data grouped in an object is very convenient\u2014as long as you update it correctly!\nimport { useState } from 'react';", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "export 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 }", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "function handleEmailChange(e) {\n setPerson({\n ...person,\n email: e.target.value\n });\n }", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "return (\n <>\n \n \n \n

          ", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "onChange={handleEmailChange}\n />\n \n

          \n {person.firstName}{' '}\n {person.lastName}{' '}\n ({person.email})\n

          \n \n );\n}\nNote that the ... spread syntax is \u201cshallow\u201d\u2014it only copies things one level deep. This makes it fast, but it also means that if you want to update a nested property, you\u2019ll have to use it more than once.\n...", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "...\nYou 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 ones:\n[\n]\nimport { useState } from 'react';", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "export 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 }", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "return (\n <>\n \n \n \n

          \n {person.firstName}{' '}\n {person.lastName}{' '}\n ({person.email})\n

          \n \n );\n}\nHere, e.target.name refers to the name property given to the DOM element.\ne.target.name\nname\n\nUpdating a nested object\nConsider a nested object structure like this:", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "e.target.name\nname\n\nUpdating a nested object\nConsider a nested object structure like this:\nconst [person, setPerson] = useState({ name: 'Niki de Saint Phalle', artwork: { title: 'Blue Nana', city: 'Hamburg', image: 'https://i.imgur.com/Sd1AgUOm.jpg', }});\nconst [person, setPerson] = useState({ name: 'Niki de Saint Phalle', artwork: { title: 'Blue Nana', city: 'Hamburg', image: 'https://i.imgur.com/Sd1AgUOm.jpg', }});", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "If you wanted to update person.artwork.city, it\u2019s clear how to do it with mutation:\nperson.artwork.city\nperson.artwork.city = 'New Delhi';\nperson.artwork.city = 'New Delhi';\nBut 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 artwork:\ncity\nartwork\nperson\nartwork", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "city\nartwork\nperson\nartwork\nconst nextArtwork = { ...person.artwork, city: 'New Delhi' };const nextPerson = { ...person, artwork: nextArtwork };setPerson(nextPerson);\nconst nextArtwork = { ...person.artwork, city: 'New Delhi' };const nextPerson = { ...person, artwork: nextArtwork };setPerson(nextPerson);\nOr, written as a single function call:", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "Or, written as a single function call:\nsetPerson({ ...person, // Copy other fields artwork: { // but replace the artwork ...person.artwork, // with the same one city: 'New Delhi' // but in New Delhi! }});\nsetPerson({ ...person, // Copy other fields artwork: { // but replace the artwork ...person.artwork, // with the same one city: 'New Delhi' // but in New Delhi! }});\nThis gets a bit wordy, but it works fine for many cases:\nimport { useState } from 'react';", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "export 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://i.imgur.com/Sd1AgUOm.jpg',\n }\n });\n\n function handleNameChange(e) {\n setPerson({\n ...person,\n name: e.target.value\n });\n }", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "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 }", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "return (\n <>\n \n \n \n \n \n

          \n {person.artwork.title}\n {' by '}\n {person.name}\n
          \n (located in {person.artwork.city})\n

          \n {person.artwork.title}\n\n \n );\n}\nAn object like this appears \u201cnested\u201d in code:", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "/>\n \n );\n}\nAn object like this appears \u201cnested\u201d in code:\nlet obj = { name: 'Niki de Saint Phalle', artwork: { title: 'Blue Nana', city: 'Hamburg', image: 'https://i.imgur.com/Sd1AgUOm.jpg', }};\nlet obj = { name: 'Niki de Saint Phalle', artwork: { title: 'Blue Nana', city: 'Hamburg', image: 'https://i.imgur.com/Sd1AgUOm.jpg', }};", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "However, \u201cnesting\u201d is an inaccurate way to think about how objects behave. When the code executes, there is no such thing as a \u201cnested\u201d object. You are really looking at two different objects:\nlet obj1 = { title: 'Blue Nana', city: 'Hamburg', image: 'https://i.imgur.com/Sd1AgUOm.jpg',};let obj2 = { name: 'Niki de Saint Phalle', artwork: obj1};", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "let obj1 = { title: 'Blue Nana', city: 'Hamburg', image: 'https://i.imgur.com/Sd1AgUOm.jpg',};let obj2 = { name: 'Niki de Saint Phalle', artwork: obj1};\nThe obj1 object is not \u201cinside\u201d obj2. For example, obj3 could \u201cpoint\u201d at obj1 too:\nobj1\nobj2\nobj3\nobj1\nlet obj1 = { title: 'Blue Nana', city: 'Hamburg', image: 'https://i.imgur.com/Sd1AgUOm.jpg',};let obj2 = { name: 'Niki de Saint Phalle', artwork: obj1};let obj3 = { name: 'Copycat', artwork: obj1};", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "let obj1 = { title: 'Blue Nana', city: 'Hamburg', image: 'https://i.imgur.com/Sd1AgUOm.jpg',};let obj2 = { name: 'Niki de Saint Phalle', artwork: obj1};let obj3 = { name: 'Copycat', artwork: obj1};", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "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 \u201cnested\u201d. Instead, they are separate objects \u201cpointing\u201d at each other with properties.\nobj3.artwork.city\nobj2.artwork.city\nobj1.city\nobj3.artwork\nobj2.artwork\nobj1\nWrite concise update logic with Immer", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "obj1.city\nobj3.artwork\nobj2.artwork\nobj1\nWrite concise update logic with Immer\nIf your state is deeply nested, you might want to consider flattening it. But, if you don\u2019t 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 \u201cbreaking the rules\u201d and mutating an object:", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "updatePerson(draft => { draft.artwork.city = 'Lagos';});\nupdatePerson(draft => { draft.artwork.city = 'Lagos';});\nBut unlike a regular mutation, it doesn\u2019t overwrite the past state!\nThe draft provided by Immer is a special type of object, called a Proxy, that \u201crecords\u201d 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.\ndraft", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "draft\ndraft\nTo try Immer:\nRun npm install use-immer to add Immer as a dependency\nnpm install use-immer\nThen replace import { useState } from 'react' with import { useImmer } from 'use-immer'\nimport { useState } from 'react'\nimport { useImmer } from 'use-immer'\nHere is the above example converted to Immer:\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\": {", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "\"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}", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "\"eject\": \"react-scripts eject\"\n },\n \"devDependencies\": {}\n}\nNotice 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\u2019s nesting in your state, and copying objects leads to repetitive code.\nuseState\nuseImmer\nThere are a few reasons:", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "useState\nuseImmer\nThere are a few reasons:\nDebugging: If you use console.log and don\u2019t mutate state, your past logs won\u2019t get clobbered by the more recent state changes. So you can clearly see how state has changed between renders.\nconsole.log", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "console.log\nOptimizations: Common 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.\nprevObj === obj", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "prevObj === obj\nNew Features: The new React features we\u2019re building rely on state being treated like a snapshot. If you\u2019re mutating past versions of state, that may prevent you from using the new features.", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "Requirement Changes: Some 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.", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "Simpler Implementation: Because 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 \u201creactive\u201d solutions do. This is also why React lets you put any object into state\u2014no matter how large\u2014without additional performance or correctness pitfalls.", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "In practice, you can often \u201cget away\u201d 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!\nRecap\nTreat all state in React as immutable.\nWhen you store objects in state, mutating them will not trigger renders and will change the state in previous render \u201csnapshots\u201d.", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "Instead of mutating an object, create a new version of it, and trigger a re-render by setting state to it.\nYou can use the {...obj, something: 'newValue'} object spread syntax to create copies of objects.\n{...obj, something: 'newValue'}\nSpread syntax is shallow: it only copies one level deep.\nTo update a nested object, you need to create copies all the way up from the place you\u2019re updating.\nTo reduce repetitive copying code, use Immer.\nTry out some challenges", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "To reduce repetitive copying code, use Immer.\nTry out some challenges\nThis 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 \u201ccaught up\u201d with your changes. Finally, edit the last name, and notice that the score has disappeared completely.\nYour task is to fix all of these bugs. As you fix them, explain why each of them happens.\nimport { useState } from 'react';", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "export 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 }", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "return (\n <>\n \n \n \n \n );\n}", + "title": "Updating Objects in State \u2013 React", + "url": "https://react.dev/learn/updating-objects-in-state" + }, + { + "content": "Tutorial: Tic-Tac-Toe\nYou will build a small tic-tac-toe game during this tutorial. This tutorial does not assume any existing React knowledge. The techniques you\u2019ll learn in the tutorial are fundamental to building any React app, and fully understanding it will give you a deep understanding of React.\nNote", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Note\nThis 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.\nThe tutorial is divided into several sections:\nSetup for the tutorial will give you a starting point to follow the tutorial.\nOverview will teach you the fundamentals of React: components, props, and state.\nCompleting the game will teach you the most common techniques in React development.", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Completing the game will teach you the most common techniques in React development.\nAdding time travel will give you a deeper insight into the unique strengths of React.\nWhat are you building?\nIn this tutorial, you\u2019ll build an interactive tic-tac-toe game with React.\nYou can see what it will look like when you\u2019re finished here:\nimport { useState } from 'react';", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function Square({ value, onSquareClick }) {\n return (\n \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 }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "const winner = calculateWinner(squares);\n let status;\n if (winner) {\n status = 'Winner: ' + winner;\n } else {\n status = 'Next player: ' + (xIsNext ? 'X' : 'O');\n }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return (\n <>\n
          {status}
          \n
          \n handleClick(0)} />\n handleClick(1)} />\n handleClick(2)} />\n
          \n
          \n handleClick(3)} />", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": " handleClick(3)} />\n handleClick(4)} />\n handleClick(5)} />\n
          \n
          \n handleClick(6)} />\n handleClick(7)} />\n handleClick(8)} />", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": " handleClick(8)} />\n
          \n \n );\n}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export 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 }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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
        98. \n \n
        99. \n );\n });", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return (\n
          \n
          \n \n
          \n
          \n
            {moves}
          \n
          \n
          \n );\n}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function 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}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return squares[a];\n }\n }\n return null;\n}\nIf the code doesn\u2019t make sense to you yet, or if you are unfamiliar with the code\u2019s syntax, don\u2019t worry! The goal of this tutorial is to help you understand React and its syntax.", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "We recommend that you check out the tic-tac-toe game above before continuing with the tutorial. One of the features that you\u2019ll notice is that there is a numbered list to the right of the game\u2019s 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.", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Once you\u2019ve played around with the finished tic-tac-toe game, keep scrolling. You\u2019ll start with a simpler template in this tutorial. Our next step is to set you up so that you can start building the game.\nSetup for the tutorial", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Setup for the tutorial\nIn 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\u2019ve created. The new tab should display an empty square and the starter code for this tutorial.\nexport default function Square() {\n return ;\n}\nNote", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export default function Square() {\n return ;\n}\nNote\nYou can also follow this tutorial using your local development environment. To do this, you need to:\nInstall Node.js\nIn 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\nUnzip the archive, then open a terminal and cd to the directory you unzipped\ncd", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Unzip the archive, then open a terminal and cd to the directory you unzipped\ncd\nInstall the dependencies with npm install\nnpm install\nRun npm start to start a local server and follow the prompts to view the code running in a browser\nnpm start\nIf you get stuck, don\u2019t let this stop you! Follow along online instead and try a local setup again later.\nOverview\nNow that you\u2019re set up, let\u2019s get an overview of React!\nInspecting the starter code\nIn CodeSandbox you\u2019ll see three main sections:", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Inspecting the starter code\nIn CodeSandbox you\u2019ll see three main sections:\nThe Files section with a list of files like App.js, index.js, styles.css and a folder called public\nApp.js\nindex.js\nstyles.css\npublic\nThe code editor where you\u2019ll see the source code of your selected file\nThe browser section where you\u2019ll see how the code you\u2019ve written will be displayed\nThe App.js file should be selected in the Files section. The contents of that file in the code editor should be:\nApp.js", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "App.js\nexport default function Square() { return ;}\nexport default function Square() { return ;}\nThe browser section should be displaying a square with an X in it like this:\nNow let\u2019s have a look at the files in the starter code.\nApp.js", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Now let\u2019s have a look at the files in the starter code.\nApp.js\nThe 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\u2019s look at the component line by line to see what\u2019s going on:\nApp.js\nexport default function Square() { return ;}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "App.js\nexport default function Square() { return ;}\nexport default function Square() { return ;}\nThe 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\u2019s the main function in your file.\nSquare\nexport\ndefault", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Square\nexport\ndefault\nexport default function Square() { return ;}\nexport default function Square() { return ;}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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. closes the JSX element to indicate that any following content shouldn\u2019t", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "of the button and closes the JSX element to indicate that any following content shouldn\u2019t be placed inside the button.", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return\n\nstyles.css\nClick 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 .square selector defines the style of any component where the className property is set to square. In your code, that would match the button from your Square component in the App.js file.\nstyles.css\n*\nbody\n.square\nclassName", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "styles.css\n*\nbody\n.square\nclassName\nsquare\nApp.js\nindex.js\nClick on the file labeled index.js in the Files section of CodeSandbox. You won\u2019t be editing this file during the tutorial but it is the bridge between the component you created in the App.js file and the web browser.\nindex.js\nApp.js\nimport { StrictMode } from 'react';import { createRoot } from 'react-dom/client';import './styles.css';import App from './App';", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "import { StrictMode } from 'react';import { createRoot } from 'react-dom/client';import './styles.css';import App from './App';\nLines 1-5 bring all the necessary pieces together:\nReact\nReact\u2019s library to talk to web browsers (React DOM)\nthe styles for your components\nthe component you created in App.js.\nApp.js\nThe remainder of the file brings all the pieces together and injects the final product into index.html in the public folder.\nindex.html\npublic\nBuilding the board", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "index.html\npublic\nBuilding the board\nLet\u2019s get back to App.js. This is where you\u2019ll spend the rest of the tutorial.\nApp.js\nCurrently 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 this:\nexport default function Square() { return ;}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export default function Square() { return ;}\nYou\u2019ll get this error:\n<>...\nReact 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 this:\n<>\n", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "<>\n\nexport default function Square() { return ( <> );}\nexport default function Square() { return ( <> );}\nNow you should see:\nGreat! Now you just need to copy-paste a few times to add nine squares and\u2026", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Now you should see:\nGreat! Now you just need to copy-paste a few times to add nine squares and\u2026\nOh no! The squares are all in a single line, not in a grid like you need for our board. To fix this you\u2019ll need to group your squares into rows with divs and add some CSS classes. While you\u2019re at it, you\u2019ll give each square a number to make sure you know where each square is displayed.\ndiv\nIn the App.js file, update the Square component to look like this:\nApp.js\nSquare", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export default function Square() { return ( <>
          ", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "
          );}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export default function Square() { return ( <>
          ", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "
          );}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "The CSS defined in styles.css styles the divs with the className of board-row. Now that you\u2019ve grouped your components into rows with the styled divs you have your tic-tac-toe board:\nstyles.css\nclassName\nboard-row\ndiv\nBut you now have a problem. Your component named Square, really isn\u2019t a square anymore. Let\u2019s fix that by changing the name to Board:\nSquare\nBoard\nexport default function Board() { //...}\nexport default function Board() { //...}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Square\nBoard\nexport default function Board() { //...}\nexport default function Board() { //...}\nAt this point your code should look something like this:\nexport default function Board() {\n return (\n <>\n
          \n \n \n \n
          \n
          \n ", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "
          \n
          \n \n \n \n
          \n
          \n \n \n \n
          \n \n );\n}\nNote", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "\n \n \n );\n}\nNote\nPsssst\u2026 That\u2019s a lot to type! It\u2019s okay to copy and paste code from this page. However, if you\u2019re up for a little challenge, we recommend only copying code that you\u2019ve manually typed at least once yourself.\nPassing data through props", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Passing data through props\nNext, you\u2019ll want to change the value of a square from empty to \u201cX\u201d when the user clicks on the square. With how you\u2019ve 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\u2019s component architecture allows you to create a reusable component to avoid messy, duplicated code.", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "First, you are going to copy the line defining your first square () from your Board component into a new Square component:\n\nBoard\nSquare\nfunction Square() { return ;}export default function Board() { // ...}\nfunction Square() { return ;}export default function Board() { // ...}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Then you\u2019ll update the Board component to render that Square component using JSX syntax:\nSquare\n// ...export default function Board() { return ( <>
          );}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "// ...export default function Board() { return ( <>
          );}\nNote how unlike the browser divs, your own components Board and Square must start with a capital letter.\ndiv\nBoard\nSquare", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "div\nBoard\nSquare\nLet\u2019s take a look:\nOh no! You lost the numbered squares you had before. Now each square says \u201c1\u201d. To fix this, you will use props to pass the value each square should have from the parent component (Board) to its child (Square).\nBoard\nSquare\nUpdate the Square component to read the value prop that you\u2019ll pass from the Board:\nSquare\nvalue\nBoard\nfunction Square({ value }) { return ;}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Square\nvalue\nBoard\nfunction Square({ value }) { return ;}\nfunction Square({ value }) { return ;}\nfunction Square({ value }) indicates the Square component can be passed a prop called value.\nfunction Square({ value })\nvalue\nNow you want to display that value instead of 1 inside every square. Try doing it like this:\nvalue\n1\nfunction Square({ value }) { return ;}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "value\n1\nfunction Square({ value }) { return ;}\nfunction Square({ value }) { return ;}\nOops, this is not what you wanted:\nYou wanted to render the JavaScript variable called value from your component, not the word \u201cvalue\u201d. To \u201cescape into JavaScript\u201d from JSX, you need curly braces. Add curly braces around value in JSX like so:\nvalue\nvalue", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "value\nvalue\nfunction Square({ value }) { return ;}\nfunction Square({ value }) { return ;}\nFor now, you should see an empty board:\nThis is because the Board component hasn\u2019t passed the value prop to each Square component it renders yet. To fix it you\u2019ll add the value prop to each Square component rendered by the Board component:\nBoard\nvalue\nSquare\nvalue\nSquare\nBoard", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Board\nvalue\nSquare\nvalue\nSquare\nBoard\nexport default function Board() { return ( <>
          );}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export default function Board() { return ( <>
          );}\nNow you should see a grid of numbers again:", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Now you should see a grid of numbers again:\nYour updated code should look like this:\nfunction Square({ value }) {\n return ;\n}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export default function Board() {\n return (\n <>\n
          \n \n \n \n
          \n
          \n \n \n \n
          \n
          \n \n \n \n
          \n \n );\n}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "\n \n \n \n );\n}\nMaking an interactive component\nLet\u2019s 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:\nSquare\nX\nhandleClick\nSquare\nonClick\nSquare", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Square\nX\nhandleClick\nSquare\nonClick\nSquare\nfunction Square({ value }) { function handleClick() { console.log('clicked!'); } return ( );}\nfunction Square({ value }) { function handleClick() { console.log('clicked!'); } return ( );}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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.\n\"clicked!\"\n\"clicked!\"\n\"clicked!\"\nNote", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "\"clicked!\"\n\"clicked!\"\n\"clicked!\"\nNote\nIf you are following this tutorial using your local development environment, you need to open your browser\u2019s 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 + \u2318 + J (on macOS).\nAs a next step, you want the Square component to \u201cremember\u201d that it got clicked, and fill it with an \u201cX\u201d mark. To \u201cremember\u201d things, components use state.", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "React provides a special function called useState that you can call from your component to let it \u201cremember\u201d things. Let\u2019s store the current value of the Square in state, and change it when the Square is clicked.\nuseState\nSquare\nSquare\nImport 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 value:\nuseState\nvalue\nSquare\nSquare\nuseState\nvalue", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "useState\nvalue\nSquare\nSquare\nuseState\nvalue\nimport { useState } from 'react';function Square() { const [value, setValue] = useState(null); function handleClick() { //...\nimport { useState } from 'react';function Square() { const [value, setValue] = useState(null); function handleClick() { //...", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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.\nvalue\nsetValue\nnull\nuseState\nvalue\nnull\nSince the Square component no longer accepts props anymore, you\u2019ll remove the value prop from all nine of the Square components created by the Board component:\nSquare\nvalue", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Square\nvalue\n// ...export default function Board() { return ( <>
          );}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "// ...export default function Board() { return ( <>
          );}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Now you\u2019ll change Square to display an \u201cX\u201d when clicked. Replace the console.log(\"clicked!\"); event handler with setValue('X');. Now your Square component looks like this:\nSquare\nconsole.log(\"clicked!\");\nsetValue('X');\nSquare\nfunction Square() { const [value, setValue] = useState(null); function handleClick() { setValue('X'); } return ( );}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function Square() { const [value, setValue] = useState(null); function handleClick() { setValue('X'); } return ( );}\nBy calling this set function from an onClick handler, you\u2019re telling React to re-render that Square whenever its \n );\n}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export default function Board() {\n return (\n <>\n
          \n \n \n \n
          \n
          \n \n \n \n
          \n
          \n \n \n \n
          \n \n );\n}\nReact Developer Tools", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "\n \n \n \n );\n}\nReact Developer Tools\nReact DevTools let you check the props and the state of your React components. You can find the React DevTools tab at the bottom of the browser section in CodeSandbox:\nTo inspect a particular component on the screen, use the button in the top left corner of React DevTools:\nNote", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Note\nFor local development, React DevTools is available as a Chrome, Firefox, and Edge browser extension. Install it, and the Components tab will appear in your browser Developer Tools for sites using React.\nCompleting the game\nBy 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 \u201cX\u201ds and \u201cO\u201ds on the board, and you need a way to determine a winner.\nLifting state up", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Lifting state up\nCurrently, each Square component maintains a part of the game\u2019s 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.\nSquare\nBoard\nSquare", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "How would you approach that? At first, you might guess that the Board needs to \u201cask\u201d each Square for that Square\u2019s 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\u2019s 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", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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.", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Board\nSquare\nSquare\nBoard\nSquare\nBoard\nSquare\nTo 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.\nLifting state into a parent component is common when React components are refactored.", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Lifting state into a parent component is common when React components are refactored.\nLet\u2019s 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:\nBoard\nsquares\n// ...export default function Board() { const [squares, setSquares] = useState(Array(9).fill(null)); return ( // ... );}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "// ...export default function Board() { const [squares, setSquares] = useState(Array(9).fill(null)); return ( // ... );}\nArray(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\u2019s 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:\nArray(9).fill(null)\nnull\nuseState()\nsquares", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Array(9).fill(null)\nnull\nuseState()\nsquares\nsquares\n['O', null, 'X', 'X', 'X', 'O', 'O', null, null]\n['O', null, 'X', 'X', 'X', 'O', 'O', null, null]\nNow your Board component needs to pass the value prop down to each Square that it renders:\nBoard\nvalue\nSquare", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export default function Board() { const [squares, setSquares] = useState(Array(9).fill(null)); return ( <>
          ", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "/>
          );}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export default function Board() { const [squares, setSquares] = useState(Array(9).fill(null)); return ( <>
          ", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "/>
          );}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Next, you\u2019ll edit the Square component to receive the value prop from the Board component. This will require removing the Square component\u2019s own stateful tracking of value and the button\u2019s onClick prop:\nSquare\nvalue\nvalue\nonClick\nfunction Square({value}) { return ;}\nfunction Square({value}) { return ;}\nAt this point you should see an empty tic-tac-toe board:\nAnd your code should look like this:", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "At this point you should see an empty tic-tac-toe board:\nAnd your code should look like this:\nimport { useState } from 'react';", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function Square({ value }) {\n return ;\n}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export default function Board() {\n const [squares, setSquares] = useState(Array(9).fill(null));\n return (\n <>\n
          \n \n \n \n
          \n
          \n \n \n \n
          \n
          ", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "\n
          \n
          \n \n \n \n
          \n \n );\n}\nEach Square will now receive a value prop that will either be 'X', 'O', or null for empty squares.\nvalue\n'X'\n'O'\nnull", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "value\n'X'\n'O'\nnull\nNext, you need to change what happens when a Square is clicked. The Board component now maintains which squares are filled. You\u2019ll need to create a way for the Square to update the Board\u2019s state. Since state is private to a component that defines it, you cannot update the Board\u2019s state directly from Square.\nSquare\nBoard\nSquare\nBoard\nBoard\nSquare", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Square\nBoard\nSquare\nBoard\nBoard\nSquare\nInstead, you\u2019ll pass down a function from the Board component to the Square component, and you\u2019ll have Square call that function when a square is clicked. You\u2019ll start with the function that the Square component will call when it is clicked. You\u2019ll call that function onSquareClick:\nBoard\nSquare\nSquare\nSquare\nonSquareClick\nfunction Square({ value }) { return ( );}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function Square({ value }) { return ( );}\nNext, you\u2019ll add the onSquareClick function to the Square component\u2019s props:\nonSquareClick\nSquare\nfunction Square({ value, onSquareClick }) { return ( );}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function Square({ value, onSquareClick }) { return ( );}\nNow you\u2019ll connect the onSquareClick prop to a function in the Board component that you\u2019ll name handleClick. To connect onSquareClick to handleClick you\u2019ll pass a function to the onSquareClick prop of the first Square component:\nonSquareClick\nBoard\nhandleClick\nonSquareClick\nhandleClick\nonSquareClick\nSquare", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "onSquareClick\nBoard\nhandleClick\nonSquareClick\nhandleClick\nonSquareClick\nSquare\nexport default function Board() { const [squares, setSquares] = useState(Array(9).fill(null)); return ( <>
          //... );}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export default function Board() { const [squares, setSquares] = useState(Array(9).fill(null)); return ( <>
          //... );}\nLastly, you will define the handleClick function inside the Board component to update the squares array holding your board\u2019s state:\nhandleClick\nsquares", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "handleClick\nsquares\nexport default function Board() { const [squares, setSquares] = useState(Array(9).fill(null)); function handleClick() { const nextSquares = squares.slice(); nextSquares[0] = \"X\"; setSquares(nextSquares); } return ( // ... )}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export default function Board() { const [squares, setSquares] = useState(Array(9).fill(null)); function handleClick() { const nextSquares = squares.slice(); nextSquares[0] = \"X\"; setSquares(nextSquares); } return ( // ... )}\nThe 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.\nhandleClick\nsquares\nnextSquares\nslice()", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "handleClick\nsquares\nnextSquares\nslice()\nhandleClick\nnextSquares\nX\n[0]\nCalling 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).\nsetSquares\nsquares\nBoard\nSquare\nNote", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "setSquares\nsquares\nBoard\nSquare\nNote\nJavaScript 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.\nhandleClick\nBoard\nhandleClick\nsquares\nsetSquares\nBoard", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "handleClick\nBoard\nhandleClick\nsquares\nsetSquares\nBoard\nNow you can add X\u2019s to the board\u2026 but only to the upper left square. Your handleClick function is hardcoded to update the index for the upper left square (0). Let\u2019s 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 update:\nhandleClick\n0\nhandleClick\ni\nhandleClick", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "handleClick\n0\nhandleClick\ni\nhandleClick\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 ( // ... )}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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 ( // ... )}\nNext, 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\u2019t work:\ni\nhandleClick\nonSquareClick\nhandleClick(0)", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "i\nhandleClick\nonSquareClick\nhandleClick(0)\n\n\nHere is why this doesn\u2019t 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 loop:\nhandleClick(0)", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "handleClick(0)\nhandleClick(0)\nsetSquares\nhandleClick(0)\nWhy didn\u2019t this problem happen earlier?\nWhen 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\u2014notice the parentheses in handleClick(0)\u2014and that\u2019s why it runs too early. You don\u2019t want to call handleClick until the user clicks!\nonSquareClick={handleClick}\nhandleClick\nhandleClick(0)\nhandleClick", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "onSquareClick={handleClick}\nhandleClick\nhandleClick(0)\nhandleClick\nYou 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.\nhandleFirstSquareClick\nhandleClick(0)\nhandleSecondSquareClick\nhandleClick(1)", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "handleFirstSquareClick\nhandleClick(0)\nhandleSecondSquareClick\nhandleClick(1)\nonSquareClick={handleFirstSquareClick}\nHowever, defining nine different functions and giving each of them a name is too verbose. Instead, let\u2019s do this:\nexport default function Board() { // ... return ( <>
          handleClick(0)} /> // ... );}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export default function Board() { // ... return ( <>
          handleClick(0)} /> // ... );}\nNotice 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 => \u201carrow\u201d will run, calling handleClick(0).\n() =>\n() => handleClick(0)\n=>\nhandleClick(0)", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "() =>\n() => handleClick(0)\n=>\nhandleClick(0)\nNow 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 square:\nhandleClick\nhandleClick", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export default function Board() { // ... return ( <>
          handleClick(0)} /> handleClick(1)} /> handleClick(2)} />
          handleClick(3)} /> ", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "onSquareClick={() => handleClick(3)} /> handleClick(4)} /> handleClick(5)} />
          handleClick(6)} /> handleClick(7)} /> handleClick(8)} />
          );};", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export default function Board() { // ... return ( <>
          handleClick(0)} /> handleClick(1)} /> handleClick(2)} />
          handleClick(3)} /> ", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "onSquareClick={() => handleClick(3)} /> handleClick(4)} /> handleClick(5)} />
          handleClick(6)} /> handleClick(7)} /> handleClick(8)} />
          );};", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Now you can again add X\u2019s to any square on the board by clicking on them:\nBut this time all the state management is handled by the Board component!\nBoard\nThis is what your code should look like:\nimport { useState } from 'react';", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function Square({ value, onSquareClick }) {\n return (\n \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 }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return (\n <>\n
          \n handleClick(0)} />\n handleClick(1)} />\n handleClick(2)} />\n
          \n
          \n handleClick(3)} />\n handleClick(4)} />", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": " handleClick(4)} />\n handleClick(5)} />\n
          \n
          \n handleClick(6)} />\n handleClick(7)} />\n handleClick(8)} />\n
          \n \n );\n}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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\u2019s 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", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "the state of all squares in the Board component will allow it to determine the winner in the future.", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Board\nBoard\nSquare\nSquare\nSquare\nBoard\nBoard\nBoard\nSquare\nBoard\nLet\u2019s recap what happens when a user clicks the top left square on your board to add an X to it:\nX\nClicking 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.\nbutton\nonClick\nSquare\nSquare", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "button\nonClick\nSquare\nSquare\nonSquareClick\nBoard\nBoard\nhandleClick\n0\nhandleClick uses the argument (0) to update the first element of the squares array from null to X.\nhandleClick\n0\nsquares\nnull\nX\nThe 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.\nsquares\nBoard\nBoard\nvalue\nSquare\n0\nnull\nX", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "squares\nBoard\nBoard\nvalue\nSquare\n0\nnull\nX\nIn the end the user sees that the upper left square has changed from empty to having an X after clicking it.\nX\nNote", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "X\nNote\nThe DOM \n );\n}\n\nexport default function Board() {\n const [xIsNext, setXIsNext] = useState(true);\n const [squares, setSquares] = useState(Array(9).fill(null));", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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 }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return (\n <>\n
          \n handleClick(0)} />\n handleClick(1)} />\n handleClick(2)} />\n
          \n
          \n handleClick(3)} />\n handleClick(4)} />", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": " handleClick(4)} />\n handleClick(5)} />\n
          \n
          \n handleClick(6)} />\n handleClick(7)} />\n handleClick(8)} />\n
          \n \n );\n}\nDeclaring a winner", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "
          \n \n );\n}\nDeclaring a winner\nNow that the players can take turns, you\u2019ll want to show when the game is won and there are no more turns to make. To do this you\u2019ll 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\u2019t worry too much about the calculateWinner function; it\u2019s not specific to React:\ncalculateWinner\n'X'\n'O'\nnull\ncalculateWinner", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "calculateWinner\n'X'\n'O'\nnull\ncalculateWinner\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;}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export 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;}\nNote", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Note\nIt does not matter whether you define calculateWinner before or after the Board. Let\u2019s put it at the end so that you don\u2019t have to scroll past it every time you edit your components.\ncalculateWinner\nBoard\nYou will call calculateWinner(squares) in the Board component\u2019s 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\u2019d like to return early in both cases:", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "calculateWinner(squares)\nBoard\nhandleClick\nX\nO\nfunction handleClick(i) { if (squares[i] || calculateWinner(squares)) { return; } const nextSquares = squares.slice(); //...}\nfunction handleClick(i) { if (squares[i] || calculateWinner(squares)) { return; } const nextSquares = squares.slice(); //...}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "To let the players know when the game is over, you can display text such as \u201cWinner: X\u201d or \u201cWinner: O\u201d. To do that you\u2019ll 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\u2019ll display which player\u2019s turn is next:\nstatus\nBoard", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "status\nBoard\nexport default function Board() { // ... const winner = calculateWinner(squares); let status; if (winner) { status = \"Winner: \" + winner; } else { status = \"Next player: \" + (xIsNext ? \"X\" : \"O\"); } return ( <>
          {status}
          // ... )}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export default function Board() { // ... const winner = calculateWinner(squares); let status; if (winner) { status = \"Winner: \" + winner; } else { status = \"Next player: \" + (xIsNext ? \"X\" : \"O\"); } return ( <>
          {status}
          // ... )}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Congratulations! You now have a working tic-tac-toe game. And you\u2019ve just learned the basics of React too. So you are the real winner here. Here is what the code should look like:\nimport { useState } from 'react';", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function Square({value, onSquareClick}) {\n return (\n \n );\n}\n\nexport default function Board() {\n const [xIsNext, setXIsNext] = useState(true);\n const [squares, setSquares] = useState(Array(9).fill(null));", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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 }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return (\n <>\n
          {status}
          \n
          \n handleClick(0)} />\n handleClick(1)} />\n handleClick(2)} />\n
          \n
          \n handleClick(3)} />", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": " handleClick(3)} />\n handleClick(4)} />\n handleClick(5)} />\n
          \n
          \n handleClick(6)} />\n handleClick(7)} />\n handleClick(8)} />", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": " handleClick(8)} />\n
          \n \n );\n}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function 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}\nAdding time travel", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return squares[a];\n }\n }\n return null;\n}\nAdding time travel\nAs a final exercise, let\u2019s make it possible to \u201cgo back in time\u201d to the previous moves in the game.\nStoring a history of moves\nIf you mutated the squares array, implementing time travel would be very difficult.\nsquares", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "If you mutated the squares array, implementing time travel would be very difficult.\nsquares\nHowever, 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.\nslice()\nsquares\nsquares", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "slice()\nsquares\nsquares\nYou\u2019ll store the past squares arrays in another array called history, which you\u2019ll 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:\nsquares\nhistory\nhistory", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "squares\nhistory\nhistory\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'], // ...]", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "[ // 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'], // ...]\nLifting state up, again\nYou will now write a new top-level component called Game to display a list of past moves. That\u2019s where you will place the history state that contains the entire game history.\nGame\nhistory", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Game\nhistory\nPlacing the history state into the Game component will let you remove the squares state from its child Board component. Just like you \u201clifted state up\u201d 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\u2019s data and lets it instruct the Board to render previous turns from the history.\nhistory\nGame\nsquares\nBoard\nSquare\nBoard\nBoard\nGame\nGame\nBoard\nBoard", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "history\nGame\nsquares\nBoard\nSquare\nBoard\nBoard\nGame\nGame\nBoard\nBoard\nhistory\nFirst, add a Game component with export default. Have it render the Board component and some markup:\nGame\nexport default\nBoard\nfunction Board() { // ...}export default function Game() { return (
            {/*TODO*/}
          );}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function Board() { // ...}export default function Game() { return (
            {/*TODO*/}
          );}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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\u2019ll add to the board later.\nexport default\nfunction Board() {\nfunction Game() {\nindex.js\nGame\nBoard\ndiv\nGame", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export default\nfunction Board() {\nfunction Game() {\nindex.js\nGame\nBoard\ndiv\nGame\nAdd some state to the Game component to track which player is next and the history of moves:\nGame\nexport default function Game() { const [xIsNext, setXIsNext] = useState(true); const [history, setHistory] = useState([Array(9).fill(null)]); // ...\nexport default function Game() { const [xIsNext, setXIsNext] = useState(true); const [history, setHistory] = useState([Array(9).fill(null)]); // ...", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Notice how [Array(9).fill(null)] is an array with a single item, which itself is an array of 9 nulls.\n[Array(9).fill(null)]\nnull\nTo render the squares for the current move, you\u2019ll want to read the last squares array from the history. You don\u2019t need useState for this\u2014you already have enough information to calculate it during rendering:\nhistory\nuseState", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "history\nuseState\nexport default function Game() { const [xIsNext, setXIsNext] = useState(true); const [history, setHistory] = useState([Array(9).fill(null)]); const currentSquares = history[history.length - 1]; // ...\nexport default function Game() { const [xIsNext, setXIsNext] = useState(true); const [history, setHistory] = useState([Array(9).fill(null)]); const currentSquares = history[history.length - 1]; // ...", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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 component:\nhandlePlay\nGame\nBoard\nxIsNext\ncurrentSquares\nhandlePlay\nBoard", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "handlePlay\nGame\nBoard\nxIsNext\ncurrentSquares\nhandlePlay\nBoard\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 (
          //... )}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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) { // TODO } return (
          //... )}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Let\u2019s make the Board component fully controlled by the props it receives. Change the Board component to take three props: xIsNext, 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 useState:\nBoard\nBoard\nxIsNext\nsquares\nonPlay\nBoard\nBoard\nuseState\nfunction Board({ xIsNext, squares, onPlay }) { function handleClick(i) { //... } // ...}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function Board({ xIsNext, squares, onPlay }) { function handleClick(i) { //... } // ...}\nfunction Board({ xIsNext, squares, onPlay }) { function handleClick(i) { //... } // ...}\nNow 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 square:\nsetSquares\nsetXIsNext\nhandleClick\nBoard\nonPlay\nGame\nBoard", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "setSquares\nsetXIsNext\nhandleClick\nBoard\nonPlay\nGame\nBoard\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); } //...}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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); } //...}\nThe 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.\nBoard", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Board\nGame\nhandlePlay\nGame\nWhat 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.\nhandlePlay\nsetSquares\nsquares\nonPlay", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "handlePlay\nsetSquares\nsquares\nonPlay\nThe handlePlay function needs to update Game\u2019s state to trigger a re-render, but you don\u2019t have a setSquares function that you can call any more\u2014you\u2019re now using the history state variable to store this information. You\u2019ll 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 do:\nhandlePlay\nGame\nsetSquares\nhistory\nhistory\nsquares\nxIsNext", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "handlePlay\nGame\nsetSquares\nhistory\nhistory\nsquares\nxIsNext\nexport default function Game() { //... function handlePlay(nextSquares) { setHistory([...history, nextSquares]); setXIsNext(!xIsNext); } //...}\nexport default function Game() { //... function handlePlay(nextSquares) { setHistory([...history, nextSquares]); setXIsNext(!xIsNext); } //...}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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 \u201cenumerate all the items in history\u201d.)\n[...history, nextSquares]\nhistory\nnextSquares\n...history\nhistory\nFor 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\"]].\nhistory", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "history\n[[null,null,null], [\"X\",null,null]]\nnextSquares\n[\"X\",null,\"O\"]\n[...history, nextSquares]\n[[null,null,null], [\"X\",null,null], [\"X\",null,\"O\"]]\nAt this point, you\u2019ve 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 point:\nGame\nimport { useState } from 'react';", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function Square({ value, onSquareClick }) {\n return (\n \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 }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "const winner = calculateWinner(squares);\n let status;\n if (winner) {\n status = 'Winner: ' + winner;\n } else {\n status = 'Next player: ' + (xIsNext ? 'X' : 'O');\n }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return (\n <>\n
          {status}
          \n
          \n handleClick(0)} />\n handleClick(1)} />\n handleClick(2)} />\n
          \n
          \n handleClick(3)} />", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": " handleClick(3)} />\n handleClick(4)} />\n handleClick(5)} />\n
          \n
          \n handleClick(6)} />\n handleClick(7)} />\n handleClick(8)} />", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": " handleClick(8)} />\n
          \n \n );\n}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export 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 }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return (\n
          \n
          \n \n
          \n
          \n
            {/*TODO*/}
          \n
          \n
          \n );\n}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function 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}\nShowing the past moves", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return squares[a];\n }\n }\n return null;\n}\nShowing the past moves\nSince you are recording the tic-tac-toe game\u2019s history, you can now display a list of past moves to the player.\nReact elements like ); }); return (
            {moves}
          );}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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 {", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "{ let description; if (move > 0) { description = 'Go to move #' + move; } else { description = 'Go to game start'; } return (
        100. ); }); return (
            {moves}
          );}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "You can see what your code should look like below. Note that you should see an error in the developer tools console that says:\nYou\u2019ll fix this error in the next section.\nimport { useState } from 'react';", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function Square({ value, onSquareClick }) {\n return (\n \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 }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "const winner = calculateWinner(squares);\n let status;\n if (winner) {\n status = 'Winner: ' + winner;\n } else {\n status = 'Next player: ' + (xIsNext ? 'X' : 'O');\n }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return (\n <>\n
          {status}
          \n
          \n handleClick(0)} />\n handleClick(1)} />\n handleClick(2)} />\n
          \n
          \n handleClick(3)} />", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": " handleClick(3)} />\n handleClick(4)} />\n handleClick(5)} />\n
          \n
          \n handleClick(6)} />\n handleClick(7)} />\n handleClick(8)} />", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": " handleClick(8)} />\n
          \n \n );\n}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export 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 }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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
        101. \n \n
        102. \n );\n });", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return (\n
          \n
          \n \n
          \n
          \n
            {moves}
          \n
          \n
          \n );\n}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function 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}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return squares[a];\n }\n }\n return null;\n}\nAs 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 index: 0, 1, 2, \u2026. (In most cases, you\u2019d need the actual array elements, but to render a list of moves you will only need indexes.)\nhistory\nmap\nsquares\nhistory\nmove\n0\n1\n2", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "history\nmap\nsquares\nhistory\nmove\n0\n1\n2\nFor each move in the tic-tac-toe game\u2019s history, you create a list item
        103. which contains a button
        104. );});\nconst moves = history.map((squares, move) => { //... return (
        105. );});\nimport { useState } from 'react';", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function Square({ value, onSquareClick }) {\n return (\n \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 }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "const winner = calculateWinner(squares);\n let status;\n if (winner) {\n status = 'Winner: ' + winner;\n } else {\n status = 'Next player: ' + (xIsNext ? 'X' : 'O');\n }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return (\n <>\n
          {status}
          \n
          \n handleClick(0)} />\n handleClick(1)} />\n handleClick(2)} />\n
          \n
          \n handleClick(3)} />", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": " handleClick(3)} />\n handleClick(4)} />\n handleClick(5)} />\n
          \n
          \n handleClick(6)} />\n handleClick(7)} />\n handleClick(8)} />", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": " handleClick(8)} />\n
          \n \n );\n}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export 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 }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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
        106. \n \n
        107. \n );\n });", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return (\n
          \n
          \n \n
          \n
          \n
            {moves}
          \n
          \n
          \n );\n}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function 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}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return squares[a];\n }\n }\n return null;\n}\nBefore 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 0:\njumpTo\nGame\ncurrentMove\n0", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "jumpTo\nGame\ncurrentMove\n0\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]; //...}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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[history.length - 1]; //...}\nNext, update the jumpTo function inside Game to update that currentMove. You\u2019ll also set xIsNext to true if the number that you\u2019re changing currentMove to is even.\njumpTo\nGame\ncurrentMove\nxIsNext\ntrue\ncurrentMove", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "jumpTo\nGame\ncurrentMove\nxIsNext\ntrue\ncurrentMove\nexport default function Game() { // ... function jumpTo(nextMove) { setCurrentMove(nextMove); setXIsNext(nextMove % 2 === 0); } //...}\nexport default function Game() { // ... function jumpTo(nextMove) { setCurrentMove(nextMove); setXIsNext(nextMove % 2 === 0); } //...}\nYou will now make two changes to the Game\u2019s handlePlay function which is called when you click on a square.\nGame\nhandlePlay", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Game\nhandlePlay\nIf you \u201cgo back in time\u201d 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\u2019ll add it after all items in history.slice(0, currentMove + 1) so that you\u2019re only keeping that portion of the old history.\nnextSquares\n...\nhistory\nhistory.slice(0, currentMove + 1)\nEach time a move is made, you need to update currentMove to point to the latest history entry.", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Each time a move is made, you need to update currentMove to point to the latest history entry.\ncurrentMove\nfunction handlePlay(nextSquares) { const nextHistory = [...history.slice(0, currentMove + 1), nextSquares]; setHistory(nextHistory); setCurrentMove(nextHistory.length - 1); setXIsNext(!xIsNext);}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function handlePlay(nextSquares) { const nextHistory = [...history.slice(0, currentMove + 1), nextSquares]; setHistory(nextHistory); setCurrentMove(nextHistory.length - 1); setXIsNext(!xIsNext);}\nFinally, you will modify the Game component to render the currently selected move, instead of always rendering the final move:\nGame", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Game\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]; // ...}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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]; // ...}\nIf you click on any step in the game\u2019s history, the tic-tac-toe board should immediately update to show what the board looked like after that step occurred.\nimport { useState } from 'react';", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function Square({value, onSquareClick}) {\n return (\n \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 }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "const winner = calculateWinner(squares);\n let status;\n if (winner) {\n status = 'Winner: ' + winner;\n } else {\n status = 'Next player: ' + (xIsNext ? 'X' : 'O');\n }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return (\n <>\n
          {status}
          \n
          \n handleClick(0)} />\n handleClick(1)} />\n handleClick(2)} />\n
          \n
          \n handleClick(3)} />", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": " handleClick(3)} />\n handleClick(4)} />\n handleClick(5)} />\n
          \n
          \n handleClick(6)} />\n handleClick(7)} />\n handleClick(8)} />", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": " handleClick(8)} />\n
          \n \n );\n}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export 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 }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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
        108. \n \n
        109. \n );\n });", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return (\n
          \n
          \n \n
          \n
          \n
            {moves}
          \n
          \n
          \n );\n}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function 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}\nFinal cleanup", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return squares[a];\n }\n }\n return null;\n}\nFinal cleanup\nIf 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.\nxIsNext === true\ncurrentMove\nxIsNext === false\ncurrentMove\ncurrentMove\nxIsNext", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "xIsNext === true\ncurrentMove\nxIsNext === false\ncurrentMove\ncurrentMove\nxIsNext\nThere\u2019s 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\u2019t store xIsNext as a separate state variable and instead figures it out based on the currentMove:\nGame\nxIsNext\ncurrentMove", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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); } // ...}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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); } // ...}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "You no longer need the xIsNext state declaration or the calls to setXIsNext. Now, there\u2019s no chance for xIsNext to get out of sync with currentMove, even if you make a mistake while coding the components.\nxIsNext\nsetXIsNext\nxIsNext\ncurrentMove\nWrapping up\nCongratulations! You\u2019ve created a tic-tac-toe game that:\nLets you play tic-tac-toe,\nIndicates when a player has won the game,\nStores a game\u2019s history as a game progresses,", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Indicates when a player has won the game,\nStores a game\u2019s history as a game progresses,\nAllows players to review a game\u2019s history and see previous versions of a game\u2019s board.\nNice work! We hope you now feel like you have a decent grasp of how React works.\nCheck out the final result here:\nimport { useState } from 'react';", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function Square({ value, onSquareClick }) {\n return (\n \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 }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "const winner = calculateWinner(squares);\n let status;\n if (winner) {\n status = 'Winner: ' + winner;\n } else {\n status = 'Next player: ' + (xIsNext ? 'X' : 'O');\n }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return (\n <>\n
          {status}
          \n
          \n handleClick(0)} />\n handleClick(1)} />\n handleClick(2)} />\n
          \n
          \n handleClick(3)} />", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": " handleClick(3)} />\n handleClick(4)} />\n handleClick(5)} />\n
          \n
          \n handleClick(6)} />\n handleClick(7)} />\n handleClick(8)} />", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": " handleClick(8)} />\n
          \n \n );\n}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "export 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 }", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "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
        110. \n \n
        111. \n );\n });", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return (\n
          \n
          \n \n
          \n
          \n
            {moves}
          \n
          \n
          \n );\n}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "function 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}", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "return squares[a];\n }\n }\n return null;\n}\nIf 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 difficulty:\nFor the current move only, show \u201cYou are at move #\u2026\u201d instead of a button.\nRewrite Board to use two loops to make the squares instead of hardcoding them.\nBoard\nAdd a toggle button that lets you sort the moves in either ascending or descending order.", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Board\nAdd a toggle button that lets you sort the moves in either ascending or descending order.\nWhen someone wins, highlight the three squares that caused the win (and when no one wins, display a message about the result being a draw).\nDisplay the location for each move in the format (row, col) in the move history list.", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Display the location for each move in the format (row, col) in the move history list.\nThroughout this tutorial, you\u2019ve touched on React concepts including elements, components, props, and state. Now that you\u2019ve 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\u2019s UI.", + "title": "Tutorial: Tic-Tac-Toe \u2013 React", + "url": "https://react.dev/learn/tutorial-tic-tac-toe" + }, + { + "content": "Lifecycle of Reactive Effects\nEffects have a different lifecycle from components. Components may mount, update, or unmount. An Effect can only do two things: to 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. React provides a linter rule to check that you\u2019ve specified your Effect\u2019s dependencies correctly. This keeps your Effect synchronized to the latest props and state.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "You will learn\nHow an Effect\u2019s lifecycle is different from a component\u2019s lifecycle\nHow to think about each individual Effect in isolation\nWhen your Effect needs to re-synchronize, and why\nHow your Effect\u2019s dependencies are determined\nWhat it means for a value to be reactive\nWhat an empty dependency array means\nHow React verifies your dependencies are correct with a linter\nWhat to do when you disagree with the linter\nThe lifecycle of an Effect", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "What to do when you disagree with the linter\nThe lifecycle of an Effect\nEvery React component goes through the same lifecycle:\nA component mounts when it\u2019s added to the screen.\nA component updates when it receives new props or state, usually in response to an interaction.\nA component unmounts when it\u2019s removed from the screen.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "A component unmounts when it\u2019s removed from the screen.\nIt\u2019s a good way to think about components, but not about Effects. Instead, try to think about each Effect independently from your component\u2019s lifecycle. An Effect describes how to synchronize an external system to the current props and state. As your code changes, synchronization will need to happen more or less often.\nTo illustrate this point, consider this Effect connecting your component to a chat server:", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "To illustrate this point, consider this Effect connecting your component to a chat server:\nconst serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; }, [roomId]); // ...}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "const serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; }, [roomId]); // ...}\nYour Effect\u2019s body specifies how to start synchronizing:\n// ... const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; // ...", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "// ... const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; // ...\nThe cleanup function returned by your Effect specifies how to stop synchronizing:\n// ... const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; // ...", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "// ... const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; // ...\nIntuitively, you might think that React would start synchronizing when your component mounts and stop synchronizing when your component unmounts. However, this is not the end of the story! Sometimes, it may also be necessary to start and stop synchronizing multiple times while the component remains mounted.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Let\u2019s look at why this is necessary, when it happens, and how you can control this behavior.\nNote\nSome Effects don\u2019t return a cleanup function at all. More often than not, you\u2019ll want to return one\u2014but if you don\u2019t, React will behave as if you returned an empty cleanup function.\nWhy synchronization may need to happen more than once", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Why synchronization may need to happen more than once\nImagine this ChatRoom component receives a roomId prop that the user picks in a dropdown. Let\u2019s say that initially the user picks the \"general\" room as the roomId. Your app displays the \"general\" chat room:\nChatRoom\nroomId\n\"general\"\nroomId\n\"general\"\nconst serverUrl = 'https://localhost:1234';function ChatRoom({ roomId /* \"general\" */ }) { // ... return

          Welcome to the {roomId} room!

          ;}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "const serverUrl = 'https://localhost:1234';function ChatRoom({ roomId /* \"general\" */ }) { // ... return

          Welcome to the {roomId} room!

          ;}\nAfter the UI is displayed, React will run your Effect to start synchronizing. It connects to the \"general\" room:\n\"general\"", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "\"general\"\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]); // ...", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "function 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]); // ...\nSo far, so good.\nLater, the user picks a different room in the dropdown (for example, \"travel\"). First, React will update the UI:\n\"travel\"", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "\"travel\"\nfunction ChatRoom({ roomId /* \"travel\" */ }) { // ... return

          Welcome to the {roomId} room!

          ;}\nfunction ChatRoom({ roomId /* \"travel\" */ }) { // ... return

          Welcome to the {roomId} room!

          ;}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Think about what should happen next. The user sees that \"travel\" is the selected chat room in the UI. However, the Effect that ran the last time is still connected to the \"general\" room. The roomId prop has changed, so what your Effect did back then (connecting to the \"general\" room) no longer matches the UI.\n\"travel\"\n\"general\"\nroomId\n\"general\"\nAt this point, you want React to do two things:\nStop synchronizing with the old roomId (disconnect from the \"general\" room)\nroomId\n\"general\"", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Stop synchronizing with the old roomId (disconnect from the \"general\" room)\nroomId\n\"general\"\nStart synchronizing with the new roomId (connect to the \"travel\" room)\nroomId\n\"travel\"", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "\"general\"\nStart synchronizing with the new roomId (connect to the \"travel\" room)\nroomId\n\"travel\"\nLuckily, you\u2019ve already taught React how to do both of these things! Your Effect\u2019s body specifies how to start synchronizing, and your cleanup function specifies how to stop synchronizing. All that React needs to do now is to call them in the correct order and with the correct props and state. Let\u2019s see how exactly that happens.\nHow React re-synchronizes your Effect", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "How React re-synchronizes your Effect\nRecall that your ChatRoom component has received a new value for its roomId prop. It used to be \"general\", and now it is \"travel\". React needs to re-synchronize your Effect to re-connect you to a different room.\nChatRoom\nroomId\n\"general\"\n\"travel\"\nTo stop synchronizing, React will call the cleanup function that your Effect returned after connecting to the \"general\" room. Since roomId was \"general\", the cleanup function disconnects from the \"general\" room:", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "\"general\"\nroomId\n\"general\"\n\"general\"\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 }; // ...", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "function ChatRoom({ roomId /* \"general\" */ }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); // Connects to the \"general\" room connection.connect(); return () => { connection.disconnect(); // Disconnects from the \"general\" room }; // ...", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Then React will run the Effect that you\u2019ve provided during this render. This time, roomId is \"travel\" so it will start synchronizing to the \"travel\" chat room (until its cleanup function is eventually called too):\nroomId\n\"travel\"\n\"travel\"\nfunction ChatRoom({ roomId /* \"travel\" */ }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); // Connects to the \"travel\" room connection.connect(); // ...", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "function ChatRoom({ roomId /* \"travel\" */ }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); // Connects to the \"travel\" room connection.connect(); // ...\nThanks to this, you\u2019re now connected to the same room that the user chose in the UI. Disaster averted!", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Every time after your component re-renders with a different roomId, your Effect will re-synchronize. For example, let\u2019s say the user changes roomId from \"travel\" to \"music\". React will again stop synchronizing your Effect by calling its cleanup function (disconnecting you from the \"travel\" room). Then it will start synchronizing again by running its body with the new roomId prop (connecting you to the \"music\" room).\nroomId\nroomId\n\"travel\"\n\"music\"\n\"travel\"\nroomId\n\"music\"", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "roomId\nroomId\n\"travel\"\n\"music\"\n\"travel\"\nroomId\n\"music\"\nFinally, when the user goes to a different screen, ChatRoom unmounts. Now there is no need to stay connected at all. React will stop synchronizing your Effect one last time and disconnect you from the \"music\" chat room.\nChatRoom\n\"music\"\nThinking from the Effect\u2019s perspective\nLet\u2019s recap everything that\u2019s happened from the ChatRoom component\u2019s perspective:\nChatRoom\nChatRoom mounted with roomId set to \"general\"\nChatRoom\nroomId\n\"general\"", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "ChatRoom\nChatRoom mounted with roomId set to \"general\"\nChatRoom\nroomId\n\"general\"\nChatRoom updated with roomId set to \"travel\"\nChatRoom\nroomId\n\"travel\"\nChatRoom updated with roomId set to \"music\"\nChatRoom\nroomId\n\"music\"\nChatRoom unmounted\nChatRoom\nDuring each of these points in the component\u2019s lifecycle, your Effect did different things:\nYour Effect connected to the \"general\" room\n\"general\"\nYour Effect disconnected from the \"general\" room and connected to the \"travel\" room\n\"general\"\n\"travel\"", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "\"general\"\n\"travel\"\nYour Effect disconnected from the \"travel\" room and connected to the \"music\" room\n\"travel\"\n\"music\"\nYour Effect disconnected from the \"music\" room\n\"music\"\nNow let\u2019s think about what happened from the perspective of the Effect itself:", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "\"music\"\nNow let\u2019s think about what happened from the perspective of the Effect itself:\nuseEffect(() => { // Your Effect connected to the room specified with roomId... const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { // ...until it disconnected connection.disconnect(); }; }, [roomId]);", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "useEffect(() => { // Your Effect connected to the room specified with roomId... const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { // ...until it disconnected connection.disconnect(); }; }, [roomId]);\nThis code\u2019s structure might inspire you to see what happened as a sequence of non-overlapping time periods:\nYour Effect connected to the \"general\" room (until it disconnected)\n\"general\"", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Your Effect connected to the \"general\" room (until it disconnected)\n\"general\"\nYour Effect connected to the \"travel\" room (until it disconnected)\n\"travel\"\nYour Effect connected to the \"music\" room (until it disconnected)\n\"music\"", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "\"travel\"\nYour Effect connected to the \"music\" room (until it disconnected)\n\"music\"\nPreviously, you were thinking from the component\u2019s perspective. When you looked from the component\u2019s perspective, it was tempting to think of Effects as \u201ccallbacks\u201d or \u201clifecycle events\u201d that fire at a specific time like \u201cafter a render\u201d or \u201cbefore unmount\u201d. This way of thinking gets complicated very fast, so it\u2019s best to avoid.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Instead, always focus on a single start/stop cycle at a time. It shouldn\u2019t matter whether a component is mounting, updating, or unmounting. All you need to do is to describe how to start synchronization and how to stop it. If you do it well, your Effect will be resilient to being started and stopped as many times as it\u2019s needed.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "This might remind you how you don\u2019t think whether a component is mounting or updating when you write the rendering logic that creates JSX. You describe what should be on the screen, and React figures out the rest.\nHow React verifies that your Effect can re-synchronize\nHere is a live example that you can play with. Press \u201cOpen chat\u201d to mount the ChatRoom component:\nChatRoom\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "const 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

          Welcome to the {roomId} room!

          ;\n}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "export default function App() {\n const [roomId, setRoomId] = useState('general');\n const [show, setShow] = useState(false);\n return (\n <>\n ", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "\n \n \n \n {show &&
          }\n {show && }\n \n );\n}\nNotice that when the component mounts for the first time, you see three logs:\n\u2705 Connecting to \"general\" room at https://localhost:1234... (development-only)\n\u2705 Connecting to \"general\" room at https://localhost:1234...", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "\u2705 Connecting to \"general\" room at https://localhost:1234...\n\u274c Disconnected from \"general\" room at https://localhost:1234. (development-only)\n\u274c Disconnected from \"general\" room at https://localhost:1234.\n\u2705 Connecting to \"general\" room at https://localhost:1234...\n\u2705 Connecting to \"general\" room at https://localhost:1234...\nThe first two logs are development-only. In development, React always remounts each component once.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "The first two logs are development-only. In development, React always remounts each component once.\nReact verifies that your Effect can re-synchronize by forcing it to do that immediately in development. This might remind you of opening a door and closing it an extra time to check if the door lock works. React starts and stops your Effect one extra time in development to check you\u2019ve implemented its cleanup well.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "The main reason your Effect will re-synchronize in practice is if some data it uses has changed. In the sandbox above, change the selected chat room. Notice how, when the roomId changes, your Effect re-synchronizes.\nroomId", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "roomId\nHowever, there are also more unusual cases in which re-synchronization is necessary. For example, try editing the serverUrl in the sandbox above while the chat is open. Notice how the Effect re-synchronizes in response to your edits to the code. In the future, React may add more features that rely on re-synchronization.\nserverUrl\nHow React knows that it needs to re-synchronize the Effect", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "serverUrl\nHow React knows that it needs to re-synchronize the Effect\nYou might be wondering how React knew that your Effect needed to re-synchronize after roomId changes. It\u2019s because you told React that its code depends on roomId by including it in the list of dependencies:\nroomId\nroomId", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "roomId\nroomId\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 // ...", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "function 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 // ...\nHere\u2019s how this works:\nYou knew roomId is a prop, which means it can change over time.\nroomId", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Here\u2019s how this works:\nYou knew roomId is a prop, which means it can change over time.\nroomId\nYou knew that your Effect reads roomId (so its logic depends on a value that may change later).\nroomId\nThis is why you specified it as your Effect\u2019s dependency (so that it re-synchronizes when roomId changes).\nroomId", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "roomId\nEvery time after your component re-renders, React will look at the array of dependencies that you have passed. If any of the values in the array is different from the value at the same spot that you passed during the previous render, React will re-synchronize your Effect.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "For example, if you passed [\"general\"] during the initial render, and later you passed [\"travel\"] during the next render, React will compare \"general\" and \"travel\". These are different values (compared with Object.is), so React will re-synchronize your Effect. On the other hand, if your component re-renders but roomId has not changed, your Effect will remain connected to the same room.\n[\"general\"]\n[\"travel\"]\n\"general\"\n\"travel\"\nObject.is\nroomId", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "[\"general\"]\n[\"travel\"]\n\"general\"\n\"travel\"\nObject.is\nroomId\nEach Effect represents a separate synchronization process\nResist adding unrelated logic to your Effect only because this logic needs to run at the same time as an Effect you already wrote. For example, let\u2019s say you want to send an analytics event when the user visits the room. You already have an Effect that depends on roomId, so you might feel tempted to add the analytics call there:\nroomId", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "roomId\nfunction ChatRoom({ roomId }) { useEffect(() => { logVisit(roomId); const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; }, [roomId]); // ...}\nfunction ChatRoom({ roomId }) { useEffect(() => { logVisit(roomId); const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; }, [roomId]); // ...}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "But imagine you later add another dependency to this Effect that needs to re-establish the connection. If this Effect re-synchronizes, it will also call logVisit(roomId) for the same room, which you did not intend. Logging the visit is a separate process from connecting. Write them as two separate Effects:\nlogVisit(roomId)", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "logVisit(roomId)\nfunction ChatRoom({ roomId }) { useEffect(() => { logVisit(roomId); }, [roomId]); useEffect(() => { const connection = createConnection(serverUrl, roomId); // ... }, [roomId]); // ...}\nfunction ChatRoom({ roomId }) { useEffect(() => { logVisit(roomId); }, [roomId]); useEffect(() => { const connection = createConnection(serverUrl, roomId); // ... }, [roomId]); // ...}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Each Effect in your code should represent a separate and independent synchronization process.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "In the above example, deleting one Effect wouldn\u2019t break the other Effect\u2019s logic. This is a good indication that they synchronize different things, and so it made sense to split them up. On the other hand, if you split up a cohesive piece of logic into separate Effects, the code may look \u201ccleaner\u201d but will be more difficult to maintain. This is why you should think whether the processes are same or separate, not whether the code looks cleaner.\nEffects \u201creact\u201d to reactive values", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Effects \u201creact\u201d to reactive values\nYour Effect reads two variables (serverUrl and roomId), but you only specified roomId as a dependency:\nserverUrl\nroomId\nroomId\nconst serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; }, [roomId]); // ...}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "const serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; }, [roomId]); // ...}\nWhy doesn\u2019t serverUrl need to be a dependency?\nserverUrl", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Why doesn\u2019t serverUrl need to be a dependency?\nserverUrl\nThis is because the serverUrl never changes due to a re-render. It\u2019s always the same no matter how many times the component re-renders and why. Since serverUrl never changes, it wouldn\u2019t make sense to specify it as a dependency. After all, dependencies only do something when they change over time!\nserverUrl\nserverUrl", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "serverUrl\nserverUrl\nOn the other hand, roomId may be different on a re-render. Props, state, and other values declared inside the component are reactive because they\u2019re calculated during rendering and participate in the React data flow.\nroomId\nIf serverUrl was a state variable, it would be reactive. Reactive values must be included in dependencies:\nserverUrl", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "serverUrl\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 // ...}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "function 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 // ...}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "By including serverUrl as a dependency, you ensure that the Effect re-synchronizes after it changes.\nserverUrl\nTry changing the selected chat room or edit the server URL in this sandbox:\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "function 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]);", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "return (\n <>\n \n

          Welcome to the {roomId} room!

          \n \n );\n}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "export default function App() {\n const [roomId, setRoomId] = useState('general');\n return (\n <>\n \n
          \n \n \n );\n}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "\n \n
          \n \n \n );\n}\nWhenever you change a reactive value like roomId or serverUrl, the Effect re-connects to the chat server.\nroomId\nserverUrl\nWhat an Effect with empty dependencies means\nWhat happens if you move both serverUrl and roomId outside the component?\nserverUrl\nroomId", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "What happens if you move both serverUrl and roomId outside the component?\nserverUrl\nroomId\nconst serverUrl = 'https://localhost:1234';const roomId = 'general';function ChatRoom() { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; }, []); // \u2705 All dependencies declared // ...}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "const serverUrl = 'https://localhost:1234';const roomId = 'general';function ChatRoom() { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; }, []); // \u2705 All dependencies declared // ...}\nNow your Effect\u2019s code does not use any reactive values, so its dependencies can be empty ([]).\n[]", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Now your Effect\u2019s code does not use any reactive values, so its dependencies can be empty ([]).\n[]\nThinking from the component\u2019s perspective, the empty [] dependency array means this Effect connects to the chat room only when the component mounts, and disconnects only when the component unmounts. (Keep in mind that React would still re-synchronize it an extra time in development to stress-test your logic.)\n[]\nimport { useState, useEffect } from 'react';", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "[]\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "const 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

          Welcome to the {roomId} room!

          ;\n}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "export default function App() {\n const [show, setShow] = useState(false);\n return (\n <>\n \n {show &&
          }\n {show && }\n \n );\n}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "{show && }\n \n );\n}\nHowever, if you think from the Effect\u2019s perspective, you don\u2019t need to think about mounting and unmounting at all. What\u2019s important is you\u2019ve specified what your Effect does to start and stop synchronizing. Today, it has no reactive dependencies. But if you ever want the user to change roomId or serverUrl over time (and they would become reactive), your Effect\u2019s code won\u2019t change. You will only need to add them to the dependencies.\nroomId\nserverUrl", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "roomId\nserverUrl\nAll variables declared in the component body are reactive\nProps and state aren\u2019t the only reactive values. Values that you calculate from them are also reactive. If the props or state change, your component will re-render, and the values calculated from them will also change. This is why all variables from the component body used by the Effect should be in the Effect dependency list.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Let\u2019s say that the user can pick a chat server in the dropdown, but they can also configure a default server in settings. Suppose you\u2019ve already put the settings state in a context so you read the settings from that context. Now you calculate the serverUrl based on the selected server from props and the default server:\nsettings\nserverUrl", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "function 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", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "connection.disconnect(); }; }, [roomId, serverUrl]); // So it needs to re-synchronize when either of them changes! // ...}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "function 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", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "connection.disconnect(); }; }, [roomId, serverUrl]); // So it needs to re-synchronize when either of them changes! // ...}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "In this example, serverUrl is not a prop or a state variable. It\u2019s a regular variable that you calculate during rendering. But it\u2019s calculated during rendering, so it can change due to a re-render. This is why it\u2019s reactive.\nserverUrl\nAll values inside the component (including props, state, and variables in your component\u2019s body) are reactive. Any reactive value can change on a re-render, so you need to include reactive values as Effect\u2019s dependencies.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "In other words, Effects \u201creact\u201d to all values from the component body.\nMutable values (including global variables) aren\u2019t reactive.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "A mutable value like location.pathname can\u2019t be a dependency. It\u2019s mutable, so it can change at any time completely outside of the React rendering data flow. Changing it wouldn\u2019t trigger a re-render of your component. Therefore, even if you specified it in the dependencies, React wouldn\u2019t know to re-synchronize the Effect when it changes. This also breaks the rules of React because reading mutable data during rendering (which is when you calculate the dependencies) breaks purity of rendering.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "data during rendering (which is when you calculate the dependencies) breaks purity of rendering. Instead, you should read and subscribe to an external mutable value with useSyncExternalStore.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "location.pathname\nuseSyncExternalStore\nA mutable value like ref.current or things you read from it also can\u2019t be a dependency. The ref object returned by useRef itself can be a dependency, but its current property is intentionally mutable. It lets you keep track of something without triggering a re-render. But since changing it doesn\u2019t trigger a re-render, it\u2019s not a reactive value, and React won\u2019t know to re-run your Effect when it changes.\nref.current\nuseRef\ncurrent", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "ref.current\nuseRef\ncurrent\nAs you\u2019ll learn below on this page, a linter will check for these issues automatically.\nReact verifies that you specified every reactive value as a dependency\nIf your linter is configured for React, it will check that every reactive value used by your Effect\u2019s code is declared as its dependency. For example, this is a lint error because both roomId and serverUrl are reactive:\nroomId\nserverUrl\nimport { useState, useEffect } from 'react';", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "roomId\nserverUrl\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "function 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!", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "return (\n <>\n \n

          Welcome to the {roomId} room!

          \n \n );\n}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "export default function App() {\n const [roomId, setRoomId] = useState('general');\n return (\n <>\n \n
          \n \n \n );\n}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "\n \n
          \n \n \n );\n}\nThis may look like a React error, but really React is pointing out a bug in your code. Both roomId and serverUrl may change over time, but you\u2019re forgetting to re-synchronize your Effect when they change. You will remain connected to the initial roomId and serverUrl even after the user picks different values in the UI.\nroomId\nserverUrl\nroomId\nserverUrl", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "roomId\nserverUrl\nroomId\nserverUrl\nTo fix the bug, follow the linter\u2019s suggestion to specify roomId and serverUrl as dependencies of your Effect:\nroomId\nserverUrl", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "roomId\nserverUrl\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]); // \u2705 All dependencies declared // ...}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "function 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]); // \u2705 All dependencies declared // ...}\nTry this fix in the sandbox above. Verify that the linter error is gone, and the chat re-connects when needed.\nNote", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Note\nIn some cases, React knows that a value never changes even though it\u2019s declared inside the component. For example, the set function returned from useState and the ref object returned by useRef are stable\u2014they are guaranteed to not change on a re-render. Stable values aren\u2019t reactive, so you may omit them from the list. Including them is allowed: they won\u2019t change, so it doesn\u2019t matter.\nset\nuseState\nuseRef\nWhat to do when you don\u2019t want to re-synchronize", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "set\nuseState\nuseRef\nWhat to do when you don\u2019t want to re-synchronize\nIn the previous example, you\u2019ve fixed the lint error by listing roomId and serverUrl as dependencies.\nroomId\nserverUrl", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "roomId\nserverUrl\nHowever, you could instead \u201cprove\u201d to the linter that these values aren\u2019t reactive values, i.e. that they can\u2019t change as a result of a re-render. For example, if serverUrl and roomId don\u2019t depend on rendering and always have the same values, you can move them outside the component. Now they don\u2019t need to be dependencies:\nserverUrl\nroomId", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "serverUrl\nroomId\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(); }; }, []); // \u2705 All dependencies declared // ...}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "const 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(); }; }, []); // \u2705 All dependencies declared // ...}\nYou can also move them inside the Effect. They aren\u2019t calculated during rendering, so they\u2019re not reactive:", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "function 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(); }; }, []); // \u2705 All dependencies declared // ...}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "function 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(); }; }, []); // \u2705 All dependencies declared // ...}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Effects are reactive blocks of code. They re-synchronize when the values you read inside of them change. Unlike event handlers, which only run once per interaction, Effects run whenever synchronization is necessary.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "You can\u2019t \u201cchoose\u201d your dependencies. Your dependencies must include every reactive value you read in the Effect. The linter enforces this. Sometimes this may lead to problems like infinite loops and to your Effect re-synchronizing too often. Don\u2019t fix these problems by suppressing the linter! Here\u2019s what to try instead:", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Check that your Effect represents an independent synchronization process. If your Effect doesn\u2019t synchronize anything, it might be unnecessary. If it synchronizes several independent things, split it up.\nCheck that your Effect represents an independent synchronization process. If your Effect doesn\u2019t synchronize anything, it might be unnecessary. If it synchronizes several independent things, split it up.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "If you want to read the latest value of props or state without \u201creacting\u201d to it and re-synchronizing the Effect, you can split your Effect into a reactive part (which you\u2019ll keep in the Effect) and a non-reactive part (which you\u2019ll extract into something called an Effect Event). Read about separating Events from Effects.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "If you want to read the latest value of props or state without \u201creacting\u201d to it and re-synchronizing the Effect, you can split your Effect into a reactive part (which you\u2019ll keep in the Effect) and a non-reactive part (which you\u2019ll extract into something called an Effect Event). Read about separating Events from Effects.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Avoid relying on objects and functions as dependencies. If you create objects and functions during rendering and then read them from an Effect, they will be different on every render. This will cause your Effect to re-synchronize every time. Read more about removing unnecessary dependencies from Effects.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Avoid relying on objects and functions as dependencies. If you create objects and functions during rendering and then read them from an Effect, they will be different on every render. This will cause your Effect to re-synchronize every time. Read more about removing unnecessary dependencies from Effects.\nPitfall", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Pitfall\nThe linter is your friend, but its powers are limited. The linter only knows when the dependencies are wrong. It doesn\u2019t know the best way to solve each case. If the linter suggests a dependency, but adding it causes a loop, it doesn\u2019t mean the linter should be ignored. You need to change the code inside (or outside) the Effect so that that value isn\u2019t reactive and doesn\u2019t need to be a dependency.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "If you have an existing codebase, you might have some Effects that suppress the linter like this:\nuseEffect(() => { // ... // \ud83d\udd34 Avoid suppressing the linter like this: // eslint-ignore-next-line react-hooks/exhaustive-deps}, []);\nuseEffect(() => { // ... // \ud83d\udd34 Avoid suppressing the linter like this: // eslint-ignore-next-line react-hooks/exhaustive-deps}, []);\nOn the next pages, you\u2019ll learn how to fix this code without breaking the rules. It\u2019s always worth fixing!\nRecap", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Recap\nComponents can mount, update, and unmount.\nEach Effect has a separate lifecycle from the surrounding component.\nEach Effect describes a separate synchronization process that can start and stop.\nWhen you write and read Effects, think from each individual Effect\u2019s perspective (how to start and stop synchronization) rather than from the component\u2019s perspective (how it mounts, updates, or unmounts).\nValues declared inside the component body are \u201creactive\u201d.", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Values declared inside the component body are \u201creactive\u201d.\nReactive values should re-synchronize the Effect because they can change over time.\nThe linter verifies that all reactive values used inside the Effect are specified as dependencies.\nAll errors flagged by the linter are legitimate. There\u2019s always a way to fix the code to not break the rules.\nTry out some challenges", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Try out some challenges\nIn this example, the ChatRoom component connects to the chat room when the component mounts, disconnects when it unmounts, and reconnects when you select a different chat room. This behavior is correct, so you need to keep it working.\nChatRoom", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "ChatRoom\nHowever, there is a problem. Whenever you type into the message box input at the bottom, ChatRoom also reconnects to the chat. (You can notice this by clearing the console and typing into the input.) Fix the issue so that this doesn\u2019t happen.\nChatRoom\nimport { useState, useEffect } from 'react';\nimport { createConnection } from './chat.js';", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "const 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

          Welcome to the {roomId} room!

          \n setMessage(e.target.value)}\n />\n \n );\n}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "export default function App() {\n const [roomId, setRoomId] = useState('general');\n return (\n <>\n \n
          \n \n \n );\n}", + "title": "Lifecycle of Reactive Effects \u2013 React", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "content": "Reacting to Input with State\nReact 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.\nYou will learn\nHow declarative UI programming differs from imperative UI programming\nHow to enumerate the different visual states your component can be in", + "title": "Reacting to Input with State \u2013 React", + "url": "https://react.dev/learn/reacting-to-input-with-state" + }, + { + "content": "How to enumerate the different visual states your component can be in\nHow to trigger the changes between the different visual states from code\nHow declarative UI compares to imperative\nWhen 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 answer:\nWhen you type something into the form, the \u201cSubmit\u201d button becomes enabled.", + "title": "Reacting to Input with State \u2013 React", + "url": "https://react.dev/learn/reacting-to-input-with-state" + }, + { + "content": "When you type something into the form, the \u201cSubmit\u201d button becomes enabled.\nWhen you press \u201cSubmit\u201d, both the form and the button become disabled, and a spinner appears.\nIf the network request succeeds, the form gets hidden, and the \u201cThank you\u201d message appears.\nIf the network request fails, an error message appears, and the form becomes enabled again.", + "title": "Reacting to Input with State \u2013 React", + "url": "https://react.dev/learn/reacting-to-input-with-state" + }, + { + "content": "If the network request fails, an error message appears, and the form becomes enabled again.\nIn 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\u2019s another way to think about this: imagine riding next to someone in a car and telling them turn by turn where to go.\nIllustrated by Rachel Lee Nabors", + "title": "Reacting to Input with State \u2013 React", + "url": "https://react.dev/learn/reacting-to-input-with-state" + }, + { + "content": "Illustrated by Rachel Lee Nabors\nThey don\u2019t 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\u2019s called imperative because you have to \u201ccommand\u201d each element, from the spinner to the button, telling the computer how to update the UI.\nIn this example of imperative UI programming, the form is built without React. It only uses the browser DOM:\nasync function handleFormSubmit(e) {\n e.preventDefault();", + "title": "Reacting to Input with State \u2013 React", + "url": "https://react.dev/learn/reacting-to-input-with-state" + }, + { + "content": "async 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}", + "title": "Reacting to Input with State \u2013 React", + "url": "https://react.dev/learn/reacting-to-input-with-state" + }, + { + "content": "function 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}", + "title": "Reacting to Input with State \u2013 React", + "url": "https://react.dev/learn/reacting-to-input-with-state" + }, + { + "content": "function 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}", + "title": "Reacting to Input with State \u2013 React", + "url": "https://react.dev/learn/reacting-to-input-with-state" + }, + { + "content": "let 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;", + "title": "Reacting to Input with State \u2013 React", + "url": "https://react.dev/learn/reacting-to-input-with-state" + }, + { + "content": "form.onsubmit = handleFormSubmit;\ntextarea.oninput = handleTextareaChange;\nManipulating 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\u2019t introduced a bug (for example, forgetting to show or hide something).", + "title": "Reacting to Input with State \u2013 React", + "url": "https://react.dev/learn/reacting-to-input-with-state" + }, + { + "content": "React was built to solve this problem.\nIn React, you don\u2019t directly manipulate the UI\u2014meaning you don\u2019t 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\u2019s the driver\u2019s job to get you there, and they might even know some shortcuts you haven\u2019t considered!", + "title": "Reacting to Input with State \u2013 React", + "url": "https://react.dev/learn/reacting-to-input-with-state" + }, + { + "content": "Illustrated by Rachel Lee Nabors\nThinking about UI declaratively\nYou\u2019ve seen how to implement a form imperatively above. To better understand how to think in React, you\u2019ll walk through reimplementing this UI in React below:\nIdentify your component\u2019s different visual states\nDetermine what triggers those state changes\nRepresent the state in memory using useState\nuseState\nRemove any non-essential state variables\nConnect the event handlers to set the state", + "title": "Reacting to Input with State \u2013 React", + "url": "https://react.dev/learn/reacting-to-input-with-state" + }, + { + "content": "useState\nRemove any non-essential state variables\nConnect the event handlers to set the state\nStep 1: Identify your component\u2019s different visual states\nIn computer science, you may hear about a \u201cstate machine\u201d being in one of several \u201cstates\u201d. If you work with a designer, you may have seen mockups for different \u201cvisual states\u201d. React stands at the intersection of design and computer science, so both of these ideas are sources of inspiration.", + "title": "Reacting to Input with State \u2013 React", + "url": "https://react.dev/learn/reacting-to-input-with-state" + }, + { + "content": "First, you need to visualize all the different \u201cstates\u201d of the UI the user might see:\nEmpty: Form has a disabled \u201cSubmit\u201d button.\nTyping: Form has an enabled \u201cSubmit\u201d button.\nSubmitting: Form is completely disabled. Spinner is shown.\nSuccess: \u201cThank you\u201d message is shown instead of a form.\nError: Same as Typing state, but with an extra error message.", + "title": "Reacting to Input with State \u2013 React", + "url": "https://react.dev/learn/reacting-to-input-with-state" + }, + { + "content": "Error: Same as Typing state, but with an extra error message.\nJust like a designer, you\u2019ll want to \u201cmock up\u201d or create \u201cmocks\u201d 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':\nstatus\n'empty'\nexport default function Form({\n status = 'empty'\n}) {\n if (status === 'success') {\n return

          That's right!

          \n }\n return (\n <>", + "title": "Reacting to Input with State \u2013 React", + "url": "https://react.dev/learn/reacting-to-input-with-state" + }, + { + "content": "}) {\n if (status === 'success') {\n return

          That's right!

          \n }\n return (\n <>\n

          City quiz

          \n

          \n In which city is there a billboard that turns air into drinkable water?\n

          \n
          \n