So I'm trying to check if localStorage is empty or not and if it's then I want my state to be changed immediately.
I've created this state and I'm setting this state initially empty
const [isLoggedIn, setLogin] = useState();
Then I'm using useEffect hook to get item from localStorage if something has in localStorage it will set my state true otherwise false
useEffect(() => {
if (localStorage.getItem("info") !== null) {
setLogin(true);
} else {
setLogin(false);
}
}, []);
So, when I add something or delete from my localStorage it doesn't work and I need refresh my page in order to make it work.
I've created a code sandbox to check what's going on, please have a look and help to make it work.
https://codesandbox.io/s/great-mclaren-vypyo?file=/src/App.js:164-304
CodePudding user response:
Your localStorage commands look correct. But the issue is that you are not checking the storage everytime. You should have a state variable which you can use to indicate that something has changed and the storage needs to be checked again.
import "./styles.css";
import React, { useState, useRef, useEffect } from "react";
export default function App() {
const [isLoggedIn, setLogin] = useState();
const [change, setChange] = useState(false);
useEffect(() => {
if (localStorage.getItem("info") !== null) {
setLogin(true);
} else {
setLogin(false);
}
}, [change]);
console.log(isLoggedIn);
return (
<div className="App">
{isLoggedIn ? (
<h1>LocalStorage has something</h1>
) : (
<h2>LocalStorage has nothing</h2>
)}
<button
onClick={() => {
localStorage.setItem("info", "true");
setChange((change) => !change);
}}
>
Add to Local
</button>
<button
onClick={() => {
localStorage.removeItem("info");
setChange((change) => !change);
}}
>
Remove to Local
</button>
</div>
);
}
In the above code, change
is changed when one of your storage command runs. You could have had a counter or anything else too. The main purpose is to check the storage everytime you are chaning stuff. This way you can have multiple storage commands (even more than 2), and then you can check your storage after every change.
Another simple approach could be to simply set the logged in state inside your functions where you run localStorage
commands :
import "./styles.css";
import React, { useState, useRef, useEffect } from "react";
export default function App() {
const [isLoggedIn, setLogin] = useState();
useEffect(() => {
if (localStorage.getItem("info") !== null) {
setLogin(true);
} else {
setLogin(false);
}
}, [isLoggedIn]);
console.log(isLoggedIn);
return (
<div className="App">
{isLoggedIn ? (
<h1>LocalStorage has something</h1>
) : (
<h2>LocalStorage has nothing</h2>
)}
<button
onClick={() => {
localStorage.setItem("info", "true");
setLogin(true);
}}
>
Add to Local
</button>
<button
onClick={() => {
localStorage.removeItem("info");
setLogin(false);
}}
>
Remove to Local
</button>
</div>
);
}
Now you have one lesser state variable, but you will be directly manipulating the logged in state from your buttons.
CodePudding user response:
If you don't setItem("info") I mean If "info" does not exist in localStorage then you'll get "null" and your code will work. But If you set something to "info" in localStorage for example if you do localStorage.setItem(""), then you won't get null, you'll get empty string. Therefore your code should be:
useEffect(() => {
if (localStorage.getItem("info") !== null || localStorage.getItem("info") !== "") {
setLogin(true);
} else {
setLogin(false);
}
}, []);
if you use array instead of string in "info" then
useEffect(() => {
if (localStorage.getItem("info") !== null || JSON.parse(localStorage.getItem("info")).length > 0) {
setLogin(true);
} else {
setLogin(false);
}
}, []);
CodePudding user response:
The problem is that on the load of the page, you are setting the existence/non-existence of the localStorage item in the state of the component. However, when an action (setItem
/removeItem
) is performed, you are not updating the state. The simple way to accomplish it is to update the state in the event listener itself.
<button onClick={() => {
localStorage.setItem("info", "true");
setLogin(true);
}}>Add to Local</button>
<button onClick={() => {
localStorage.removeItem("info");
setLogin(false);
}}>Remove to Local</button>
Here is an updated, forked sandbox link.
CodePudding user response:
You can use qs.
Then localStorage.setItem("info", qs.stringify(your_value_you_want_to_store));
if (!qs.parse(localStorage.getItem("info"))) {
setLogin(false);
} else {
setLogin(true);
}
CodePudding user response:
I added an example here.
What is going on is that, the localstorage isnt reactive, and therefore you cannot listen to changes on it directl. you will need a mechanism to listen to changes. therefore i created a custom hook, that can get and set local storage values, and i used that instead.
import { useState, useEffect } from "react";
function getStorageValue(key, defaultValue) {
// getting stored value
const saved = localStorage.getItem(key);
const initial = JSON.parse(saved);
return initial || defaultValue;
}
export const useLocalStorage = (key, defaultValue) => {
const [value, setValue] = useState(() => {
return getStorageValue(key, defaultValue);
});
useEffect(() => {
// storing input name
console.log("called", value);
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
};
Now if you set new changes, you will get an updated state. Fell free to extend it however you like.