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 thelocalStorage
if it's there is something (otherwise, it defaults to[]
) and one to keep thelocalStorage
updated with the app.Happy to answer question if you have some 👍
To fix the issue you're experiencing, you can update the
updateStateFromLocalStorage
function to use thenewState
parameter passed to it from thestorage
event 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
StoreProvider
component that uses this approach:This updated version uses the
newValue
property of thestorage
event to get the updated value of thestate
key in localStorage, and it passes this value to the reducer when theupdatefromlocalstorage
action is dispatched. This ensures that the correct value is used for thestate
variable 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.