cf.completefrontend
Open lab My progress
THE REACT FIELD GUIDE

When React re-renders

See what makes a React component render again: its state, its parent, or a context. Learn why a re-render isn't a DOM change, and when renders cost something.

By the end, you can
  • 01
    Name what makes a component renderIts own state, its parent rendering, or a context it reads, and know that the same props don't stop a render while the same state does.
  • 02
    Tell a render from a change to the pageCount renders and DOM changes side by side, and explain why many renders can end in one change, or none.
  • 03
    Decide when a render mattersSpot a render slow enough to feel, see renders with React DevTools, and fix one by moving state down or passing children.

A gift note that renders the whole page

This lesson opens the Performance stage. Before you make anything faster, you need to see what React is doing, and the first thing to see is when a component renders again: when React calls your component function another time to get a new result. The Render and commit lesson showed the steps of one update; this one counts them.

Here is a tea shop with a gift note. Each component shows a small counter, from the RenderCount.jsx tab, of how many times it has rendered, and its box flashes blue each time. You don't need to read that tab to use it. Click in the box and type Hi:

Typing a note renders the whole pagePop out in the code editor (opens in a new tab)JSX
import { useState } from "react";import RenderCount from "./RenderCount.jsx"; function Header() {  return <h3 className="box">Tea shop <RenderCount /></h3>;} function Bestsellers() {  return <p className="box">Bestsellers: green tea, chai <RenderCount /></p>;} export default function App() {  const [note, setNote] = useState("");   return (    <div className="box">      <Header />      <input placeholder="Gift note" value={note} onChange={(event) => setNote(event.target.value)} />      <p>Note: {note} <RenderCount /></p>      <Bestsellers />    </div>  );}
ResultLoading…

Line 13 keeps the note in App's state, and line 18 calls setNote on every key. The counter on line 19 sits in App's own paragraph, so it counts App's renders. Header (lines 4 to 6) and Bestsellers (lines 8 to 10) have their own. They all start at renders: 1, the first render.

After Hi, all three say renders: 3. Each key changed App's state, so React rendered App, and then Header and Bestsellers, which App returns on lines 17 and 20. They rendered twice more, though they showed exactly the same text every time.

A component tree after typing one letter in the gift note. App, at the top, holds the note in state and renders. Arrows lead down to Header, the note paragraph, and Bestsellers. All three render again too, though Header and Bestsellers show exactly what they showed before.App: note changedrenders againHeaderNote: HBestsellersrenders again,shows the sameshows the new noterenders again,shows the same
Typing changes note, which lives in App. React renders App, and then every component App returns, all the way down, even Header and Bestsellers, which show the same as before.

Is that a problem? Usually not. These components take a tiny fraction of a millisecond to render, and React only changes the page where the result differs. This lesson shows what makes a component render, why a render isn't a change to the page, and how to tell when a render costs enough to fix.

Real-life analogyA proofreader and a printer

An author changes one word in a chapter. The proofreader doesn't know which pages it affects, so she reads the whole chapter again. Then the printer reprints only the page where the word changed. For a short chapter, the reading is quick. For a very long one, everyone waits for her.

In real life: An author changes one word in a chapter
In React: A state change in App
In real life: The proofreader reads the whole chapter again
In React: React renders App and every component inside it
In real life: The printer reprints only the page with the new word
In React: React changes only the DOM that differs
In real life: For a short chapter, the reading takes no time at all
In React: For small components, renders cost nothing you'd notice
The main idea

A component renders again when its state changes, when its parent renders, or when a context it reads changes. A render only calls your function; React then changes the page only where the result differs. Most renders are cheap. Fix the ones that are slow enough to feel.

Three reasons a component renders

After the first render, there are exactly three reasons React calls a component again. This shop shows two of them; the gift note above showed the third. Press Like, then Add to cart twice, and watch every counter:

A like button and a cart, each with its own counterPop out in the code editor (opens in a new tab)JSX
import { createContext, useContext, useState } from "react";import RenderCount from "./RenderCount.jsx"; const CartContext = createContext(0); function CartProvider({ children }) {  const [count, setCount] = useState(0);  return (    <CartContext value={count}>      <button onClick={() => setCount(count + 1)}>Add to cart</button>      {children}    </CartContext>  );} function CartBadge() {  const count = useContext(CartContext);  return <p className="box">Cart: {count} <RenderCount /></p>;} function LikeButton() {  const [liked, setLiked] = useState(false);  return (    <button className="box" onClick={() => setLiked(!liked)}>      {liked ? "Liked" : "Like"} <RenderCount />    </button>  );} function ProductCard() {  return (    <div className="box">      Green tea <RenderCount />      <LikeButton />    </div>  );} export default function App() {  return (    <CartProvider>      <CartBadge />      <ProductCard />    </CartProvider>  );}
ResultLoading…
  1. Its own state changes. LikeButton (lines 21 to 28) keeps liked on line 22. Like changes it, and only LikeButton's counter goes up. ProductCard, its parent, stays at 1: a render goes down from the component whose state changed, never up.
  2. Its parent renders. That's the gift note: App rendered, so everything it returned rendered.
  3. A context it reads changes. CartProvider (lines 6 to 14) keeps the count on line 7 and provides it on line 9. CartBadge reads it with useContext on line 17, so after each Add to cart, CartBadge renders: renders: 3 after two clicks.

Look at ProductCard and LikeButton after Add to cart: still the same. CartProvider rendered, but it shows its children on line 11, and those elements were made by App on lines 42 and 43. App didn't render, so they're the same elements as last time, and React skips them. Only components that read the context render because of it, as the context lesson showed. (If you want to see the check React makes to skip them, the Reconciliation and the diffing algorithm lesson, in the Under the hood stage, reads it in React's code.)

Three panels. Own state: LikeButton calls setLiked, and only LikeButton renders. A parent: App renders, so its child Header renders too. A context: CartProvider's value changes, and CartBadge, which reads it, renders, though the components between them don't.1. its own statesetLiked(true)LikeButtononly this one renders,with what it returns2. its parentApp rendersHeaderevery child renders,even with the same props3. a context it readsCartContext: 2CartBadgeevery reader renders,wherever it is below
A component renders again when its own state changes, when its parent renders, or when a context it reads changes. Nothing else starts a render.

How to read the table: each row is something that happens, what renders because of it, and where you can see it. The last row is the one exception, coming up in the next section.

What makes a component render again
What happensWhat rendersWhere you see it
Its own state changesThat component, and every component it returns, all the way down.Like renders only LikeButton.
Its parent rendersEvery child the parent returns, even when its props are the same as last time.Header and Bestsellers as you type a note.
A context it reads changesEvery component that reads that context, even when the components between didn't render.CartBadge after Add to cart.
Its state is set to the value it already hasNothing. React compares with Object.is and skips the render.Set the same quantity.

The playground puts all of this in one shop, like React DevTools would show it. Every box is a component. Type in the note, press Add to cart, and star a tea, then switch where the note's state lives:

Playground: which components render?
ShopPageJSX
function ShopPage() {
  const [note, setNote] = useState("");
  return (
    <>
      <Header />
      <GiftNote note={note} onChange={setNote} />
      <CartProvider>
        <CartBadge />
        <ProductList />
      </CartProvider>
    </>
  );
}
The shopnote in ShopPage
ShopPage
Header Tea shop
GiftNote

Note:

CartProvider
CartBadge Cart: 0
ProductList
ProductRow (Green tea)
ProductRow (Chai)
ProductRow (Mint tea)
Try it yourself

Type in the gift note, press Add to cart, or star a tea. Each box flashes when its component renders, and its counter goes up.

The shop runs here with React, written the way the code beside it shows. Each box is one component: it flashes when the component renders, and its counter counts the renders (React's extra development-only call isn't counted). The page changes are the text and elements a MutationObserver saw React change. Picking where the note's state lives starts again.

With the note's state in ShopPage, one key renders all nine components, for one change on the page: the note. Move the state into GiftNote and the same key renders one. Add to cart renders CartProvider and CartBadge, and a star renders only its row. Clear note on an empty note renders nothing, which is the exception the next section explains.

The same props don't stop a render

It's natural to think a child renders only when its props change. It doesn't work that way. Here ShippingNote gets the same prop every time. Press Add one a few times:

A child with the same props, every timePop out in the code editor (opens in a new tab)JSX
import { useState } from "react";import RenderCount from "./RenderCount.jsx"; function ShippingNote({ country }) {  return <p className="box">Ships to {country} <RenderCount /></p>;} export default function App() {  const [quantity, setQuantity] = useState(1);   return (    <div className="box">      <button onClick={() => setQuantity(quantity + 1)}>Add one</button>      <button onClick={() => setQuantity(quantity)}>Set the same quantity</button>      <p>Green tea × {quantity} <RenderCount /></p>      <ShippingNote country="India" />    </div>  );}
ResultLoading…

Line 16 passes country="India", the same string on every render. Still, every Add one (line 13) makes ShippingNote's counter go up with App's. When a parent renders, React renders its children without comparing their props one by one. That's on purpose: most renders are cheap, and comparing every prop of every component would take time too.

You can ask React to compare: memo wraps a component so it skips the render when every prop is the same as last time. Press Edit & run, change line 1 to import { memo, useState } from "react";, line 4 to const ShippingNote = memo(function ShippingNote({ country }) {, and line 6 to });. Now Add one leaves ShippingNote at renders: 1. The next lesson, memo, useMemo and useCallback, covers memo and why it often doesn't help, and the React Compiler adds it for you.

State is different. Press Set the same quantity (line 14): it sets quantity to the value it already has, and nothing renders. Before React renders for a state change, it compares the new state with the old one using Object.is, and skips the render when they're the same. (Rarely, React calls the component once before it notices, but it still skips the children. The What setState really does lesson, in the Under the hood stage, shows why.) That's why you must make a new object or array to update state, as Updating objects in state explains: a changed object that is the same object looks unchanged.

A render is not a change to the page

A render only means React called your function. What reaches the page is decided after, in the commit. This example adds a second tab, watchDom.js: it prints a DOM: line in the console for every change React makes to the page, and shades the element around it orange, while the counters still flash blue. Press Add one:

Four renders, one change to the pagePop out in the code editor (opens in a new tab)JSX
import { useState } from "react";import RenderCount from "./RenderCount.jsx";import "./watchDom.js"; function Header() {  return <h3 className="box">Tea shop <RenderCount /></h3>;} function Price({ quantity }) {  return <p className="box">Total: ${quantity * 4} <RenderCount /></p>;} function Delivery() {  return <p className="box">Free delivery over $20 <RenderCount /></p>;} export default function App() {  const [quantity, setQuantity] = useState(1);   return (    <div className="box">      <Header />      <button onClick={() => setQuantity(quantity + 1)}>Add one</button>      <Price quantity={quantity} />      <Delivery />      <RenderCount />    </div>  );}
ResultLoading…

Line 3 imports watchDom.js. Line 18 keeps the quantity, and line 23's button adds one. Four counters go up: App's on line 26, and Header, Price, and Delivery, which App returns on lines 22, 24, and 25. Four boxes flash blue. But the console adds one line, DOM: text "4" → "8", and only the total's paragraph, which holds that text, turns orange. (The line before it, DOM: added <div>, is the first render putting the page in place.)

React compared each component's new result with its last one. Header and Delivery returned the same elements, so React left their DOM alone. In Price (line 10), only the number differs, so React changed that one text node, not even the whole paragraph.

Left, the render: four function cards, App, Header, Price, and Delivery, all rendered after Add one. An arrow labelled compare leads to the right, the commit: a page window where Tea shop and Free delivery are the same, and only one text changed, from Total $4 to Total $8.Render: 4 componentsAppHeaderPriceDeliverycomparewith the last resultCommit: 1 changepageTea shop: the sameTotal: $4 → $8Free delivery: the same
After Add one, four components render, but React compares their new result with the last one and changes only one thing on the page: the total's text. Rendering is React calling your functions; the page changes only where the result differs.

How to read the table: each row asks one question of the render and of the commit.

Render or commit
QuestionRenderCommit
What happens?React calls your components to get a new result.React changes the page where the new result differs from the last one.
How much of it?The component that changed and every component below it.Only what differs, often one text, sometimes nothing.
What does it cost?The time your component functions take to run.The time the browser takes to change the page and draw it again.
What shows it here?The counters, and React DevTools' Highlight updates.watchDom.js, and the browser's Paint flashing.

When a render costs something

A render costs the time your component takes to run. For most components that's a few microseconds, and a few extra renders don't matter. It matters when two things meet: a component that is slow to render, and a render that happens often, like on every key. Here the product list is slow on purpose: lines 5 to 8 of the SlowProductList.jsx tab wait 100 milliseconds in a loop, like a list with a lot to draw. Type Happy birthday quickly:

A slow list next to the gift notePop out in the code editor (opens in a new tab)JSX
import { useState } from "react";import RenderCount from "./RenderCount.jsx";import SlowProductList from "./SlowProductList.jsx"; export default function App() {  const [note, setNote] = useState("");   return (    <div className="box">      <input placeholder="Gift note" value={note} onChange={(event) => setNote(event.target.value)} />      <p>Note: {note} <RenderCount /></p>      <SlowProductList />    </div>  );}
ResultLoading…

The letters fall behind your fingers and arrive in jumps. Line 6 keeps the note in App, and line 12 renders SlowProductList as a child, so every key renders the list, and the list's counter climbs with every letter. The box can't show your key until the render ends, 100 ms later, and 200 ms in development, where StrictMode renders every component twice.

A timeline of frames, each about 16 milliseconds. Top row, a cheap render: the key shows in the next frame. Bottom row, a render that takes 100 milliseconds: the key waits about six frames before it shows.frames, about 16 ms each12345678cheap renderkeyshows at once100 ms renderkeySlowProductList renders…showsthe screen can't change while React renders
At 60 frames a second, the browser has about 16 ms per frame. A render that fits shows your key in the next frame. A 100 ms render holds the screen for about six frames, and twice that in development, where StrictMode renders twice.

A screen that shows 60 frames a second draws a new frame about every 16 milliseconds. A render that takes longer holds the screen for several frames, and that's when people feel it. So before you fix a render, measure it: performance.now() around the slow part (the Measuring performance lesson shows how), or the React DevTools Profiler, which the Profiling React apps lesson covers. A render that takes a millisecond can run on every key without anyone noticing.

There are a few ways to fix a slow render like this one. The simplest is in the practical section: move the state so the slow part doesn't render at all. Another is useDeferredValue, which lets the slow part lag behind while the box stays fast.

See renders with React DevTools

The counters in this lesson are a stand-in for a tool you can use on any React app: React Developer Tools, a free browser extension from the React team for Chrome, Firefox, and Edge. It works on your own app, like the one from Setting up a React project. To see renders:

  1. Install React Developer Tools and open your app in development.
  2. Open the browser's developer tools and choose the Components tab.
  3. Click the gear icon for its settings, and in General, turn on Highlight updates when components render.
  4. Use your app. A colored outline flashes around each component that renders.

The outlines are renders, not changes to the page, exactly like the blue flashes here. When one component renders many times in a short time, its outline's color moves from teal toward yellow, so a component that renders on every key stands out. The colors are a list in canvas.js in React's DevTools code. The Profiler tab goes further: it records renders, how long each took, and, with "Record why each component rendered while profiling" turned on in its settings, why.

To see changes to the page instead

Chrome's own developer tools can show what the browser draws again. Open the Rendering panel (from the three-dot menu, More tools, then Rendering) and turn on Paint flashing: areas the browser repaints flash green. Use both, and you see the two halves of this lesson: React DevTools for renders, Paint flashing for what changed on screen.

Moving state down to fix a slow page

The slow page had a simple cause: the note's state lived in App, above the slow list, so every key rendered the list. Only the text box and the note need that state. Move it down into a component of their own:

The note's state moved down into GiftNotePop out in the code editor (opens in a new tab)JSX
import { useState } from "react";import RenderCount from "./RenderCount.jsx";import SlowProductList from "./SlowProductList.jsx"; function GiftNote() {  const [note, setNote] = useState("");   return (    <>      <input placeholder="Gift note" value={note} onChange={(event) => setNote(event.target.value)} />      <p>Note: {note} <RenderCount /></p>    </>  );} export default function App() {  return (    <div className="box">      <GiftNote />      <SlowProductList />    </div>  );}
ResultLoading…

GiftNote on lines 5 to 14 now keeps the note (line 6) and shows the box and the note. App on lines 16 to 23 has no state at all, so typing renders GiftNote and nothing else. Type Happy birthday again: the letters keep up, and the list's counter stays at renders: 1. No memo, no measuring, only a better place for the state.

Three more fixes come from the same idea, keeping the slow part out of the render:

  • Pass content as children. A component with state that wraps other content, like CartProvider, can take it as children. The children are made by the parent, so the wrapper's state changes don't render them. Exercise 4 practices it.
  • Read context as low as you can. If only one line of a slow component needs a context, put that line in a small component of its own. Exercise 5 practices it.
  • Skip the render. When moving things isn't possible, memo skips a component whose props didn't change, and the React Compiler does it for you. memo, useMemo and useCallback and The React Compiler come next.
Does ProductRow render again?
  • Its parent, ProductList, renders.
  • Its own starred state changes.
  • A context it reads with useContext gets a new value.
  • ProductList renders and passes exactly the same props as last time.
  • Another ProductRow's state changes.
  • Its starred state is set to the value it already has.
  • A context it doesn't read changes, and ProductList doesn't render.
  • The page's Header renders.
Try it yourself
0 of 8 correct

ProductRow has its own starred state, and ProductList renders it with no memo. Sort each event: does ProductRow render again, or not?

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Common mix-ups

  • "A re-render means React rebuilt the page." No. It means React called your function. The page changes only where the new result differs, often in one text or nowhere.
  • "If the props didn't change, the child won't render." No. A parent's render renders its children whatever their props, unless the child is wrapped in memo.
  • "Every extra render is a bug to remove." No. Renders are how React works, and most are cheap. Fix the ones you can feel, after measuring.
  • "Only the component that called the set function renders." No. Everything it returns renders too, all the way down.
  • "Setting state always causes a render." No. Setting it to the value it already has (by Object.is) renders nothing.
  • "StrictMode's double renders show a performance problem." No. They happen only in development, to catch impure components. A production build renders once.

Practice exercises

Read the counters in each result. Try a guess first, then press Edit & run and check, and use the hints if you're stuck.

Exercise 1 · Warm-upPredict Delivery's counter

You click Add one twice. What does Delivery's counter say?

import { useState } from "react";
import RenderCount from "./RenderCount.jsx";

function Header() {
  return <h3 className="box">Tea shop <RenderCount /></h3>;
}

function Price({ quantity }) {
  return <p className="box">Total: ${quantity * 4} <RenderCount /></p>;
}

function Delivery() {
  return <p className="box">Free delivery over $20 <RenderCount /></p>;
}

export default function App() {
  const [quantity, setQuantity] = useState(1);

  return (
    <div className="box">
      <Header />
      <button onClick={() => setQuantity(quantity + 1)}>Add one</button>
      <Price quantity={quantity} />
      <Delivery />
      <RenderCount />
    </div>
  );
}

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · Warm-upPredict a reset

    You click Add one, Reset, then Reset again. What does Price's counter say? Then click it in the result.

    import { useState } from "react";
    import RenderCount from "./RenderCount.jsx";
    
    function Price({ quantity }) {
      return <p className="box">Total: ${quantity * 4} <RenderCount /></p>;
    }
    
    export default function App() {
      const [quantity, setQuantity] = useState(1);
    
      return (
        <div className="box">
          <button onClick={() => setQuantity(quantity + 1)}>Add one</button>
          <button onClick={() => setQuantity(1)}>Reset</button>
          <Price quantity={quantity} />
        </div>
      );
    }

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeMove the note's state down

      Typing lags because every key renders the slow list. Fix it without touching the list. After your fix, what does the list's counter say after you type Hi?

      import { useState } from "react";import RenderCount from "./RenderCount.jsx";import SlowProductList from "./SlowProductList.jsx"; export default function App() {  const [note, setNote] = useState("");   return (    <div className="box">      <input placeholder="Gift note" value={note} onChange={(event) => setNote(event.target.value)} />      <p>Note: {note} <RenderCount /></p>      <SlowProductList />    </div>  );}
      ResultLoading…

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticePass the readers as children

        Every Add to cart renders ProductList, which shows nothing about the cart. Fix it with children. After two adds, what does ProductList's counter say?

        import { createContext, useContext, useState } from "react";import RenderCount from "./RenderCount.jsx"; const CartContext = createContext(0); function CartBadge() {  const count = useContext(CartContext);  return <p className="box">Cart: {count} <RenderCount /></p>;} function ProductList() {  return <p className="box">Green tea, chai, mint tea <RenderCount /></p>;} function CartProvider() {  const [count, setCount] = useState(0);  return (    <CartContext value={count}>      <button onClick={() => setCount(count + 1)}>Add to cart</button>      <CartBadge />      <ProductList />    </CartContext>  );} export default function App() {  return <CartProvider />;}
        ResultLoading…

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeRead the context lower down

          Each Add to cart takes at least 100 ms, because the slow list reads the cart for one line. Fix it. After two adds, what does the list's counter say?

          import { createContext, useContext, useState } from "react";import RenderCount from "./RenderCount.jsx"; const CartContext = createContext(0); function CartProvider({ children }) {  const [count, setCount] = useState(0);  return (    <CartContext value={count}>      <button onClick={() => setCount(count + 1)}>Add to cart</button>      {children}    </CartContext>  );} function SlowProductList() {  const count = useContext(CartContext);  const start = performance.now();  while (performance.now() - start < 100) {    // Pretend this list has a lot to draw.  }  return (    <div className="box">      200 teas <RenderCount />      <p>In your cart: {count}</p>    </div>  );} export default function App() {  return (    <CartProvider>      <SlowProductList />    </CartProvider>  );}
          ResultLoading…

          Answer, then press Check. Spacing and letter case don’t matter.

            Exercise 6 · ChallengeA clock that renders the whole page

            A sale countdown renders the whole page every second. Fix it. After your fix, what does ProductList's counter say three seconds later?

            import { useEffect, useState } from "react";import RenderCount from "./RenderCount.jsx"; function ProductList() {  return <p className="box">Green tea, chai, mint tea <RenderCount /></p>;} export default function App() {  const [seconds, setSeconds] = useState(0);   useEffect(() => {    const id = setInterval(() => setSeconds((value) => value + 1), 1000);    return () => clearInterval(id);  }, []);   return (    <div className="box">      <p>Sale ends in {60 - seconds} seconds</p>      <ProductList />    </div>  );}
            ResultLoading…

            Answer, then press Check. Spacing and letter case don’t matter.

              Check your understanding

              For each question, find where the state lives, then follow the render down from there. Remember that a render and a change to the page are two different things.

              The re-render quiz · 7 questionsScore: first tries count
              1. Question 1 of 7Which of these does NOT make a component render again?

                Choose an answer to see the explanation.

              2. Question 2 of 7You click Add one three times. Counting the first render, how many times has GiftNote rendered?

                Read the code, then predictPop out in the code editor (opens in a new tab)JSX
                import { useState } from "react";
                
                function GiftNote({ text }) {
                  console.log("GiftNote renders");
                  return <p>{text}</p>;
                }
                
                export default function App() {
                  const [count, setCount] = useState(0);
                  return (
                    <>
                      <button onClick={() => setCount(count + 1)}>Add one</button>
                      <GiftNote text="Happy birthday" />
                    </>
                  );
                }

                Choose an answer to see the explanation.

              3. Question 3 of 7The theme is already "light", and you click Light. What does React do?

                Read the code, then predictJSX
                const [theme, setTheme] = useState("light");
                
                <button onClick={() => setTheme("light")}>Light</button>

                Choose an answer to see the explanation.

              4. Question 4 of 7In the example with Header, Price, and Delivery, you click Add one. Four components render. How many things does React change on the page?

                Choose an answer to see the explanation.

              5. Question 5 of 7Why doesn't ProductCard render when you press Add to cart?

                Choose an answer to see the explanation.

              6. Question 6 of 7When is a re-render worth fixing?

                Choose an answer to see the explanation.

              7. Question 7 of 7What does React DevTools' "Highlight updates when components render" show?

                Choose an answer to see the explanation.

              Key takeaways

              • A component renders again when its own state changes, when its parent renders, or when a context it reads changes.
              • A render goes down from the component that changed: everything it returns renders, even with the same props, unless it's wrapped in memo.
              • Setting state to the value it already has renders nothing. Children passed in from a parent that didn't render are skipped.
              • A render calls your function; the commit changes the page only where the result differs. Many renders can end in one change, or none.
              • Most renders are cheap. Measure, find the slow ones that run often, and fix them first by moving state down, passing children, or reading context lower.
              • React DevTools' Highlight updates outlines renders; Chrome's Paint flashing shows what was drawn again.

              Remember the one-liner.
              State, parent, or context makes a component render; the page changes only where the result differs.

              Coming next: memo, useMemo and useCallback. It shows how to skip a render whose inputs didn't change, and why that often doesn't help.

              CompleteFrontend Clear concepts. Working examples.