
React Context is great for maintaining state among all your descendent components. Simply define the context with React.createContext() and pass the initial values via the value prop to the provider:
const initialContext = {
myData: null,
};
const MyContext = React.createContext(initialContext);
export function MyPage() {
return (
<MyContext.Provider value={initialContext}>
<MyPageChildren />
</MyContext.Provider>
);
}
But what if you needed a way to reset the context back to its initial value later on? In this example, the context values persist even if you unmount and remount the MyPage component, e.g. by navigating to a different route and back again. This is because initialContext is a global variable, and any updates we make will persist for the lifetime of the app.
Create a copy?
You could try to fix this by creating a copy of initialContext instead:
export function MyPage() {
return (
<MyContext.Provider value={{ ...initialContext }}>
<MyPageChildren />
</MyContext.Provider>
);
}
This will guarantee a new object every time. But the problem with this approach is that any re-render from a prop or state update will also destroy the context values, which is not what we want. If we want to keep the values across re-renders, but reset the values on unmount, what can we do?
useRef to the rescue!
We can advantage of React.useRef() to make sure the context is maintained across updates, but is reset on unmount:
export function MyPage() {
const { current: myContext } = React.useRef({
...initialContext,
});
return (
<MyContext.Provider value={myContext}>
My page
</MyContext.Provider>
);
}
This will create a new context on mount, and will hold the copy for the lifetime of the MyPage component. If the page gets unmounted, e.g. by navigating to a different route, the context will be reset when you return. Problem solved!