I'm trying to create persistent state with localStorage and React hooks in Next.js SSR app and everything seems to look good but when I reload page after update my data I'm getting error:
Warning: Text content did not match. Server: "0" Client: "5
What can I do to repair that? This is my code:
// src/utils/Store.js
import React, { createContext, useContext, useReducer, useEffect } from "react";
import lscache from "lscache";
import Reducer, {initialState as defaultState} from "../utils/Reducer";
const StoreContext = createContext();
const initialState = lscache.get('state') ? lscache.get('state') : defaultState;
export const StoreProvider = ({ children }) => {
let [state, dispatch] = useReducer(Reducer, initialState);
useEffect(
function saveStateToLocalStorage() {
lscache.set('state', state)
},
[state]
);
const updateStateFromLocalStorage = () => {
const newState = lscache.get('state') ? lscache.get('state') : defaultState;
dispatch({ type: "updatefromlocalstorage", newState });
};
useEffect(function watchForChanges() {
window.addEventListener("storage", updateStateFromLocalStorage);
return () => {
window.removeEventListener("storage", updateStateFromLocalStorage);
};
}, []);
return (
<StoreContext.Provider value={{ state, dispatch }}>
{children}
</StoreContext.Provider>
);
};
export const useStore = () => useContext(StoreContext);
Working example in codesandbox:
Top comments (2)
Hello Klaudiusz!
I found your thread on Google trying to solve mine ๐
I don't have a similar issue but I successfully did something similar, I figure, it's better that I post it than not at all.
As you can see, my version use 2
useEffect. One to initialized the data using thelocalStorageif it's there is something (otherwise, it defaults to[]) and one to keep thelocalStorageupdated with the app.Happy to answer question if you have some ๐
To fix the issue you're experiencing, you can update the
updateStateFromLocalStoragefunction to use thenewStateparameter passed to it from thestorageevent listener, instead of trying to retrieve the state from localStorage again. This will ensure that the correct state is passed to the reducer and the correct value is displayed on the page.Here's an updated version of the
StoreProvidercomponent that uses this approach:This updated version uses the
newValueproperty of thestorageevent to get the updated value of thestatekey in localStorage, and it passes this value to the reducer when theupdatefromlocalstorageaction is dispatched. This ensures that the correct value is used for thestatevariable and that it is displayed on the page.I hope this helps! Let me know if you have any other questions.
I'm an experimental help bot that leverages ChatGPT. As such, the answers I provide may be incorrect, incomplete, or even nonsensical. I am not associated with OpenAI.
Please reply to my comment(s) with your own corrections and feedback.