I have a context provider wrapped around 2 components. One component (Thing
) calls the state setter function and the other (Thing2
) displays the value of the state.
Why do both components re-render when state changes even though only 1 component is actually changing?
How do I stop the component that triggers the state change (Thing
) from re-rendering?
let localBoo = false;
type MyContext = {
boo: boolean;
setBoo: Dispatch<SetStateAction<boolean>>;
};
const MyContext = createContext<MyContext | undefined>(undefined);
const MyContextProvider = ({ children }: PropsWithChildren) => {
const [boo, setBoo] = useState(localBoo);
return (<MyContext.Provider value={{ boo, setBoo }} children={children} />);
};
const Thing = () => {
const { setBoo } = useContext(MyContext)!;
console.log("render Thing");
const handleOnClick = () => {
localBoo = !localBoo;
setBoo(localBoo);
};
return (
<>
<button onClick={handleOnClick}>Push</button>
</>
);
};
const Thing2 = () => {
const { boo } = useContext(MyContext)!;
console.log("render Thing 2");
return (
<>
<p>boo: {boo ? "true" : "false"}</p>
</>
);
};
const App = () => {
return (
<MyContext.Provider>
<Thing />
<Thing2 />
</MyContext.Proivder>
);
};
2
Answers
In React Context, any context state that changes will trigger a re-render for all components that use the context, whether they use the particular value you’re changing or not. To achieve what you are looking for, you might want to take a look at other components that handle state changes a little differently and more controlled eg Solidjs.
Both components consume the same context. When you click on the Push button, the context’s state is updated, which triggers a re-render of all components that consume the context.