My problem is that the state in my react context is resetting on every render. I thought that’s not the thing behind react context and global states. Well I don’t know how to fix that.
When I log the "Hi", it get’s logged every time the child component is rendered and of course the alerts state is resetted to the empty array.
Here is my root layout:
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en" className='bg-base-300'>
<body className={`${inter.className} bg-base-300`}>
<NextAuthProvider>
<AlertProvider>
<Navbar>
{children}
</Navbar>
</AlertProvider>
</NextAuthProvider>
</body>
</html>
)
}
That’s my AlertProvider and my AlertContext:
export const AlertContext = createContext<{
alerts: Alert[],
setAlerts: React.Dispatch<React.SetStateAction<Alert[]>>
}>({
alerts: [],
setAlerts: () => { }
});
const AlertProvider = ({ children }: { children: React.ReactNode }) => {
console.log("Hi")
const [ alerts, setAlerts ] = useState<Alert[]>([]);
return (
<AlertContext.Provider value={{alerts, setAlerts}}>
{children}
</AlertContext.Provider>
);
};
EDIT: More information
In my Commands
-component I call the context and pass it into a method which has alerts and setAlerts as parameters. In that addAlert method I call the setAlerts and that works. But only with one alert at the same time.
In my Commands component:
addAlert(new Alert("error", `There was an error while deleting ${commandName} command.`, null), alertClass.alerts, alertClass.setAlerts);
The addAlert Method:
export const addAlert = (alert: Alert, alerts: Alert[], setAlerts: React.Dispatch<React.SetStateAction<Alert[]>>) => {
// Some unimportant code
const timeoutId = setTimeout(() => {
removeAlert(
alerts.findIndex(
(alert) =>
alert.type === alert.type && alert.message === alert.message
),
alerts,
setAlerts
);
}, 10000);
const newAlert: Alert = { type: alert.type, message: alert.message, timeout: timeoutId };
setAlerts([
...alerts,
newAlert
])
}
2
Answers
Context api causes all the components inside the context to re-render each time the context changes and this can cause that problems, that’s why the use of context is not recommended as a first solution for a problem that could be solved with redux or zustand. Anyways, if you still want to use context you will have to use UseRef to hold a reference to your state variables and persist them between all the renders caused by the context.
There are several blogs where you can learn more about why you shouldn’t use context to handle states or why you should use context to solve other kind of problems and if its worth it.
The issue you’re experiencing with your React context resetting on every render is likely due to the way you are rendering your components and managing state. Based on the code you provided, it seems like you have nested context providers, which could lead to multiple instances of the context being created.
Here are a few suggestions to fix this issue:
Ensure that you are rendering your
RootLayout
component only once in your application’s entry point (usually in yourindex.js
orApp.js
).Remove the
AlertProvider
component from yourRootLayout
and place it at a higher level in your component hierarchy, where it will not be re-rendered frequently. It should ideally wrap the entire application.You should avoid creating multiple instances of the
AlertProvider
because each instance will have its own state, leading to the resetting issue you described. Instead, you should create a single instance of theAlertProvider
at the highest level of your application, so the state is shared across all components.Here’s an updated example of how you might structure your application:
By following this structure, you ensure that the
AlertProvider
is only created once at the top level of your application, and the context state won’t be reset on every render. Make sure to adjust your component imports and hierarchy as needed to fit your project structure.Additionally, ensure that you are not creating multiple instances of the
AlertProvider
elsewhere in your application, as that can lead to multiple separate instances of the context.