I’m trying to keep the input value on page refresh, basically, when I type something in an input and hit refresh, I want the input to still hold the value that I typed. I’ve done some searching and found that I could solve that problem with the help of localStorage. I’ve tried using it on a practice react app, where I have only one input and I’m using the state that I declared in that component. Like this :
function App() {
const [data, setData] = useState("");
useEffect(() => {
setData(window.localStorage.getItem('data'));
}, []);
useEffect(() => {
window.localStorage.setItem('data',data);
}, [data]);
return (
<div className="container">
<input type="text" placeholder="Name" value={data} onChange={(e)=>setData(e.target.value)}/>
</div>
)
}
export default App;
And this works perfectly fine, I’m able to keep the data as I wanted to. However, when I try to implement the same method in my actual project, it simply doesn’t work that way and I suspect it’s because I’m using useContext to pass the state from another component but I have no idea how to fix the problem since the console doesn’t give me any errors, it just doesn’t work.
Here’s my project’s App.js file, where I have set up my state and use context to pass it through my components :
function App() {
const [name, setName] = useState("");
return (
<FormContext.Provider value={{name,setName}}>
<Router>
<Routes>
<Route path='/' element={<Home/>}/>
<Route path='/Personal' element={<Personal/>}/>
<Route path='/Experience' element={<Experience/>}/>
<Route path='/Completed' element={<Completed/>}/>
</Routes>
</Router>
</FormContext.Provider>
);
}
export default App;
And here’s my Personal.jsx file, where I have the input:
const {name,setName} = useContext(FormContext)
useEffect(() => {
setName(window.localStorage.getItem('name'));
}, []);
useEffect(() => {
window.localStorage.setItem('name',name);
}, [name]);
Here’s what the input looks like:
<Input value={name} onChange={(e)=>setName(e.target.value)} type="text" placeholder="Name *"/>
I implement the same method as in my practice app, but It doesn’t work here somehow, I could use any advice, thanks!
>Solution :
It does not work because you override name each time you invoke <Personal /> element by executing that second useEffect. That second effect is executing both initially and whenever name changes – and that initial execution is one that was overriding your name, because name initially have "" as value from context, and you basically use that "" to update local storage each time you invoke element.
You should move local storage part one level up, to context. Rewrite to something like this:
function App() {
const [name, setInputName] = useState(window.localStorage.getItem('name')); // Here you are initially trying to retrieve last saved value
const setName = (name) => {
setInputName(name);
window.localStorage.setItem('name',name); // And here you are saving to local storage each time user change input content
}
return (
<FormContext.Provider value={{name, setName}}>
<Router>
<Routes>
<Route path='/' element={<Home/>}/>
<Route path='/Personal' element={<Personal/>}/>
<Route path='/Experience' element={<Experience/>}/>
<Route path='/Completed' element={<Completed/>}/>
</Routes>
</Router>
</FormContext.Provider>
);
}
export default App;
And like this no need to bother with local storage inside Personal.jsx, you hide that implementation inside form context, and expose only getter and setter to Personal. So Personal should be rewritten to something like this:
const {name,setName} = useContext(FormContext)
return <Input value={name} onChange={(e)=>setName(e.target.value)} type="text" placeholder="Name *"/>
As you can see there is no need for useEffects now, you just use bare minimums, only getter and setter that are exposed from context, and context will do any additional work.