Search code examples
reactjslocal-storage

React: Why is a variable in local storage resetting to undefined after briefly being the desired value?


I am new to React and was writing some toy code whose desired behavior is to allow a user to enter their name in the form and the page will display "Hello {user's name}" after submitting.

However, the observed behavior is that the page flickers briefly to render "Hello {user's name}" and then returns to the default rendering as if no name had been submitted.

My current approach is to save the user's name in local storage upon submission with a useEffect. However, from observing console logs, the local storage appears to be resetting the name variable to undefined immediately after setting it to the inputted name.
Below is the code:

function NameForm() {
  const [name, setName] = useState(window.localStorage.getItem("name") || "");
  useEffect(() => {
    setName(window.localStorage.setItem("name", name));
    console.log(name);
  }, [name]);
  return (
    <>
      <form
        onSubmit={event => {
          event.preventDefault();
          setName(event.target.elements.usernameInput.value);
          return false;
        }}
      >
        <label>Enter your name</label>
        <input id="usernameInput" />
        <button type="submit"> Submit</button>
      </form>
      <h1>Hello {name}</h1>
    </>
  );
}
export default function App() {
  return (
    <div className="App">
      <NameForm />
    </div>
  );
}

Here is also the codesandbox used to run the code.

Why is this unexpected behavior occurring and how can I fix it?


Solution

  • why unexpected behavior window.localStorage.setItem("name", name) returns undefined. So you are essencially doing setName(undefined) in your useEffect. Hence the issue.

    how to fix? You can fix in a number of ways. One way is to simply get rid of your useEffect and do localStorage.setItem in onSubmit and then do setName immediately.

    Updated codesandbox link

    <>
          <form
            onSubmit={event => {
              event.preventDefault();
              window.localStorage.setItem(
                "name",
                event.target.elements.usernameInput.value
              );
              setName(event.target.elements.usernameInput.value);
            }}
          >
            <label>Enter your name</label>
            <input id="usernameInput" />
            <button type="submit"> Submit</button>
          </form>
          <h1>Hello {name}</h1>
        </>
    

    You can solve your issue with controlled input.