Home > front end >  persist state after page refresh in React using local storage
persist state after page refresh in React using local storage

Time:01-27

What I would like to happen is when displayBtn() is clicked for the items in localStorage to display.

In useEffect() there is localStorage.setItem("localValue", JSON.stringify(myLeads)) MyLeads is an array which holds leads const const [myLeads, setMyLeads] = useState([]); myLeads state is changed when the saveBtn() is clicked setMyLeads((prev) => [...prev, leadValue.inputVal]);

In DevTools > Applications, localStorage is being updated but when the page is refreshed localStorage is empty []. How do you make localStorage persist state after refresh? I came across this article and have applied the logic but it hasn't solved the issue. I know it is something I have done incorrectly.

import List from './components/List'
import { SaveBtn } from './components/Buttons';

function App() {
  const [myLeads, setMyLeads] = useState([]);
  const [leadValue, setLeadValue] = useState({
    inputVal: "",
  });

  const [display, setDisplay] = useState(false);

  const handleChange = (event) => {
    const { name, value } = event.target;
    setLeadValue((prev) => {
      return {
        ...prev,
        [name]: value,
      };
    });
  };

  const localStoredValue = JSON.parse(localStorage.getItem("localValue")) ;

  const [localItems] = useState(localStoredValue || []);

  useEffect(() => {
    localStorage.setItem("localValue", JSON.stringify(myLeads));
  }, [myLeads]);

  const saveBtn = () => {
    setMyLeads((prev) => [...prev, leadValue.inputVal]);
    // setLocalItems((prevItems) => [...prevItems, leadValue.inputVal]);

    setDisplay(false);
  };

  const displayBtn = () => {
    setDisplay(true);    
  };


  const displayLocalItems = localItems.map((item) => {
    return <List key={item} val={item} />;
  });

  return (
    <main>
      <input
        name="inputVal"
        value={leadValue.inputVal}
        type="text"
        onChange={handleChange}
        required
      />

      <SaveBtn saveBtn={saveBtn} />

      <button onClick={displayBtn}>Display Leads</button>

      {display && <ul>{displayLocalItems}</ul>}
    </main>
  );
}

export default App;```

CodePudding user response:

You've fallen into a classic React Hooks trap - because using useState() is so easy, you're actually overusing it.

If localStorage is your storage mechanism, then you don't need useState() for that AT ALL. You'll end up having a fight at some point between your two sources about what is "the right state".

All you need for your use-case is something to hold the text that feeds your controlled input component (I've called it leadText), and something to hold your display boolean:

  const [leadText, setLeadText] = useState('')
  const [display, setDisplay] = useState(false)
  const localStoredValues = JSON.parse(window.localStorage.getItem('localValue') || '[]')

  const handleChange = (event) => {
    const { name, value } = event.target
    setLeadText(value)
  }

  const saveBtn = () => {
    const updatedArray = [...localStoredValues, leadText]
    localStorage.setItem('localValue', JSON.stringify(updatedArray))
    setDisplay(false)
  }

  const displayBtn = () => {
    setDisplay(true)
  }

  const displayLocalItems = localStoredValues.map((item) => {
    return <li key={item}>{item}</li>
  })

  return (
    <main>
      <input name="inputVal" value={leadText} type="text" onChange={handleChange} required />

      <button onClick={saveBtn}> Save </button>

      <button onClick={displayBtn}>Display Leads</button>

      {display && <ul>{displayLocalItems}</ul>}
    </main>
  )
  •  Tags:  
  • Related