skip to Main Content

The app works fine and adds the added data to the localhost but when I reload I lose the data, But it should be there from Localhost. It looks like I am using the useEffect the wrong way. Please check the code and help me to know what I am doing wrong here. Thanks

import { useEffect, useState } from 'react';

function PetApp() {
  const [pets, setPets] = useState([]);
  useEffect(() => {
    if (localStorage.getItem('examplePetData')) {
      setPets(JSON.parse(localStorage.getItem('examplePetData')));
    }
  }, []);

  useEffect(() => {
    localStorage.setItem('examplePetData', JSON.stringify(pets));
  }, [pets]);

  return (
    <>
      <AddPetForm setPets={setPets} />
      <ul>
        {pets.map(pet => (
          <Pet setPets={setPets} id={pet.id} name={pet.name} species={pet.species} age={pet.age} key={pet.id} />
        ))}
      </ul>
    </>
  );
}

function AddPetForm(props) {
  const [name, setName] = useState();
  const [species, setSpecies] = useState();
  const [age, setAge] = useState();

  function handleSubmit(e) {
    e.preventDefault();
    props.setPets(prev => prev.concat({ name, species, age, id: Date.now() }));
    setName('');
    setSpecies('');
    setAge('');
  }

  return (
    <form onSubmit={handleSubmit}>
      <fieldset>
        <legend>Add New Pet</legend>
        <input value={name} onChange={e => setName(e.target.value)} placeholder="Name" />
        <input value={species} onChange={e => setSpecies(e.target.value)} placeholder="species" />
        <input value={age} onChange={e => setAge(e.target.value)} placeholder="age in years" />
        <button>Add Pet</button>
      </fieldset>
    </form>
  );
}

function Pet(props) {
  function handleDelete() {
    props.setPets(prev => prev.filter(pet => pet.id != props.id));
  }

  return (
    <li>
      {props.name} is a {props.species} and is {props.age} years old.
      <button onClick={handleDelete}>Delete</button>
    </li>
  );
}
export default PetApp;

2

Answers


  1. This is because you are in React.Strict mode where the effects are called twice and ideally if your methods are pure this should give the same response.
    React strict mode helps find impurities like this only. You could validate this by removing the strict mode and your code would work.

    However this should be fixed instead of removing strict mode

    https://react.dev/reference/react/useMemo#my-calculation-runs-twice-on-every-re-render

    You could fix this by setting the initial state like

      const [pets, setPets] = useState(()=>{
        if (localStorage.getItem('examplePetData')) {
          return JSON.parse(localStorage.getItem('examplePetData'));
        }
        return [];
      });
    

    and removing the

      useEffect(() => {
        if (localStorage.getItem('examplePetData')) {
          setPets(JSON.parse(localStorage.getItem('examplePetData')));
        }
      }, []);
    
    Login or Signup to reply.
  2. I think the problem is here

     useEffect(() => {
        localStorage.setItem('examplePetData', JSON.stringify(pets));
      }, [pets]);
    

    whenever pets value changes you’re setting it to localstorage, now when the application loads the empty array will be saved in local storage thus empty data.

    let’s have a new function

    const handleSetPets = (newPet) => {
        setPets([...pets, newpet]);
        localStorage.setItem('examplePetData', JSON.stringify(pets));
    }
    

    now pass this function to AddPetForm
    <AddPetForm handleSetPets={handleSetPets } />

    Finally, in AddPetForm
    instead of calling setPets directly do this

      function handleSubmit(e) {
        e.preventDefault();
        props.handleSetPets({name, species, age, id: Date.now() });
        setName('');
        setSpecies('');
        setAge('');
      }
    

    you can use similar approach for delete function.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search