I was learning React and localStorage. Then, I came across an article saying that localStorage is best to be used via useEffect() due to side-effects. So, this code is bad:
import React from 'react';
const App = () => {
const [value, setValue] = React.useState('');
const onChange = event => {
localStorage.setItem('myValueInLocalStorage', event.target.value);
setValue(event.target.value);
};
return (
<div>
<h1>Hello React with Local Storage!</h1>
<input value={value} type="text" onChange={onChange} />
<p>{value}</p>
</div>
);
};
export default App;
But this code is right:
import React from 'react';
const App = () => {
const [value, setValue] = React.useState('');
React.useEffect(() => {
localStorage.setItem('myValueInLocalStorage', value);
}, [value]);
const onChange = event => setValue(event.target.value);
return (
<div>
<h1>Hello React with Local Storage!</h1>
<input value={value} type="text" onChange={onChange} />
<p>{value}</p>
</div>
);
};
export default App;
One question WHY? Why is wrong with the first code and what re the benefits of the second code with useEffect()
The correct way to perform the side effect in our User component is as follows: We import useEffect from "react" We call it above the returned JSX in our component. We pass it two arguments: a function and an array.
React is really good at efficiently deciding what should update and scheduling any changes. Sometimes, however, we need our components to reach outside this data-flow process and directly interact with other APIs. An action that impinges on the outside world in some way is called a side effect.
If you're familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount , componentDidUpdate , and componentWillUnmount combined. There are two common kinds of side effects in React components: those that don't require cleanup, and those that do.
Some effects might require cleanup to avoid memory leaks. useEffect() allows us to perform different kinds of side effects after a component renders, and then clean them up depending on their kind.
Data fetching, setting up a subscription, and manually changing the DOM in React components are all examples of side effects. Whether or not you’re used to calling these operations “side effects” (or just “effects”), you’ve likely performed them in your components before.
When React renders our component, it will remember the effect we used, and then run our effect after updating the DOM. This happens for every render, including the first one. Experienced JavaScript developers might notice that the function passed to useEffect is going to be different on every render.
If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined. There are two common kinds of side effects in React components: those that don’t require cleanup, and those that do. Let’s look at this distinction in more detail.
By default, it runs both after the first render and after every update. (We will later talk about how to customize this .) Instead of thinking in terms of “mounting” and “updating”, you might find it easier to think that effects happen “after render”. React guarantees the DOM has been updated by the time it runs the effects.
Both cases of your code are fine. The reason the first case doesn't need to be wrapped in useEffect
is because it's already in an event handler, and it will be called only once per change. Likewise, the reason we use useEffect
in the second case is so that React can ensure it only calls the effect once.
Why bother? React may retry rendering your component when it likes, and it expects the same JSX for the same state/props regardless of how many times it renders--i.e., your component should be "pure". This enables lots of performance enhancements like Suspense, but you don't need to concern yourself with that as long as you don't run side-effects directly in the render function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With