To force a React component to re-render (rerender), change its state. In a function component, the usual “forceUpdate” is a reducer that increments a counter: const [, forceUpdate] = useReducer(x => x + 1, 0); call forceUpdate() and the component renders again. Class components have this.forceUpdate() built in. To force a child component to re-render from scratch (and reset its state), change its key prop. Most of the time, though, a component that “does not re-render” has a bug, like mutating state; this guide covers those causes first-hand, with each example built and clicked in a real browser.
Every example was built with React 19.3.0 and Vite 8.3.0 (npx vite build) and opened in Microsoft Edge; the buttons were clicked with real mouse events and the outputs are the browser console messages. Reference: forceUpdate and Preserving and resetting state on react.dev.
Force re-render a function component (forceUpdate with useReducer)
Changing a ref does not re-render, so the screen shows old data. A reducer that returns a new number every time gives you a forceUpdate function:
import { useReducer, useRef } from "react";
export default function App() {
const [, forceUpdate] = useReducer((x) => x + 1, 0); // calling forceUpdate() re-renders
const lastSync = useRef("never"); // a ref change does NOT re-render
console.log("render, lastSync =", lastSync.current);
return (
<div>
<p>Last sync: <strong>{lastSync.current}</strong></p>
<button id="sync" onClick={() => { lastSync.current = "09:30"; }}>Sync (ref only)</button>
<button id="refresh" onClick={forceUpdate}>Force re-render</button>
</div>
);
}
Console output after clicking “Sync (ref only)” and then “Force re-render”:
render, lastSync = never
render, lastSync = 09:30
forceUpdate().There is no render after the first click; the second click renders and shows the value the ref already had. This works, but it is a workaround: if the value matters for the UI, keep it in state (useState) and React re-renders on its own.
Why your component does not re-render: mutating state
React compares the new state with the old one using Object.is. If you mutate an array or object and pass the same reference to the setter, React sees no change and skips the render. Creating a new array fixes it; no forcing needed:
import { useState } from "react";
export default function App() {
const [items, setItems] = useState(["milk"]);
console.log("render:", items.join(", "));
const addWrong = () => {
items.push("eggs"); // mutates the same array
setItems(items); // same reference -> React skips the re-render
};
const addRight = () => setItems([...items, "bread"]); // new array -> re-render
return (
<div>
<p>Shopping list: {items.join(", ")}</p>
<button id="wrong" onClick={addWrong}>Add eggs (mutate)</button>
<button id="right" onClick={addRight}>Add bread (new array)</button>
</div>
);
}
Console output after clicking “Add eggs (mutate)” and then “Add bread (new array)”:
render: milk
render: milk, eggs, bread
The first click logged nothing: the mutated array was not rendered. The second click rendered, and the list suddenly contains both items, a typical sign of mutation bugs.
forceUpdate() in class components
Class components have a built-in forceUpdate() method. It skips shouldComponentUpdate and calls render() again:
import { Component } from "react";
const settings = { theme: "light" }; // data outside React state
export default class App extends Component {
render() {
console.log("render, theme =", settings.theme);
return (
<div>
<p>Theme: {settings.theme}</p>
<button id="toggle" onClick={() => {
settings.theme = settings.theme === "light" ? "dark" : "light";
this.forceUpdate(); // class components have forceUpdate()
}}>Toggle theme</button>
</div>
);
}
}
Console output after clicking “Toggle theme” twice:
render, theme = light
render, theme = dark
render, theme = light
Force a child component to re-render (and reset) with key
A child re-renders whenever its parent re-renders, but it keeps its state. To start a child over, give it a key and change the key; React unmounts the old instance and mounts a new one:
import { useState } from "react";
function Counter({ label }) {
const [count, setCount] = useState(0);
return (
<p>
{label}: {count}{" "}
<button className="inc" onClick={() => setCount(count + 1)}>+1</button>
</p>
);
}
export default function App() {
const [resetKey, setResetKey] = useState(0);
const [, setTick] = useState(0);
return (
<div>
<Counter key={`a-${resetKey}`} label="Counter A (key changes on reset)" />
<Counter label="Counter B (no key)" />
<button id="rerender" onClick={() => setTick((t) => t + 1)}>Re-render parent</button>
<button id="reset" onClick={() => setResetKey((k) => k + 1)}>Reset A with a new key</button>
</div>
);
}
Re-render a memoized child
A child wrapped in memo re-renders only when its props change. If it reads data that was mutated in place, pass a prop that changes (a version number here) so it updates:
import { memo, useState } from "react";
const Chart = memo(function Chart({ data, version }) {
console.log("Chart rendered, version", version);
return <p>Chart of {data.length} points (version {version})</p>;
});
const data = [3, 7, 4]; // mutated in place below, so memo sees the same reference
export default function App() {
const [version, setVersion] = useState(1);
const [clicks, setClicks] = useState(0);
return (
<div>
<Chart data={data} version={version} />
<p>Parent clicks: {clicks}</p>
<button id="parent" onClick={() => setClicks((c) => c + 1)}>Update parent only</button>
<button id="add" onClick={() => { data.push(9); setVersion((v) => v + 1); }}>Add point and bump version</button>
</div>
);
}
Console output after two parent-only updates and one “Add point” click:
Chart rendered, version 1
Chart rendered, version 2
version changed.The cleaner fix is to keep data in state and replace it with a new array; then memo works without the extra prop.
Data outside React: useSyncExternalStore instead of forceUpdate
If the data lives in your own store (or a browser API), subscribe to it with useSyncExternalStore. React re-renders the component whenever the snapshot changes:
import { useSyncExternalStore } from "react";
// a tiny store outside React
let cart = [];
const listeners = new Set();
const store = {
add(item) { cart = [...cart, item]; listeners.forEach((l) => l()); },
subscribe(l) { listeners.add(l); return () => listeners.delete(l); },
getSnapshot() { return cart; },
};
function CartBadge() {
const items = useSyncExternalStore(store.subscribe, store.getSnapshot);
console.log("CartBadge rendered with", items.length, "items");
return <p>Cart: {items.length} items</p>;
}
export default function App() {
return (
<div>
<CartBadge />
<button id="add" onClick={() => store.add("book")}>Add a book</button>
</div>
);
}
Console output after clicking “Add a book” twice:
CartBadge rendered with 0 items
CartBadge rendered with 1 items
CartBadge rendered with 2 items
| Situation | Best way to get a re-render |
|---|---|
| Value shown on screen | Keep it in useState and call the setter |
| Updated an array/object | Set a new array/object: setItems([...items, x]) |
| Need a quick “forceUpdate” | const [, forceUpdate] = useReducer(x => x + 1, 0) |
| Class component | this.forceUpdate() |
| Reset a child completely | Change the child’s key prop |
| Memoized child with stale data | Pass changed props (or new data references) |
| External store or API | useSyncExternalStore |
Here are some related React guides:
- Why a React component renders multiple times
- Reload a React component
- Force update a functional component
- Call a function in a child component
Frequently asked questions
How do I force a React component to re-render?
Update its state. For a manual trigger in a function component, use const [, forceUpdate] = useReducer(x => x + 1, 0) and call forceUpdate().
Is there forceUpdate for functional components?
Not built in. The useReducer counter above does the same job; this.forceUpdate() exists only in class components.
Why does my component not re-render after setState?
Usually because the state was mutated and the same object or array was passed to the setter. Create a new one instead.
How do I force a child component to re-render?
Re-render the parent or change a prop the child uses. To reset the child’s state completely, change its key.
Does changing a ref re-render the component?
No. Refs are for values that do not affect the output. Use state for anything shown on screen.
Why do my components render twice in development?
React StrictMode renders components twice in development to find side effects. Production builds render once.
Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn