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?
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.
<>
<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.