Reputation: 1763
This may seem like a weird question, but I do not really see many use cases for useEffect
in React (I am currently working on a several thousand-lines React codebase, and never used it once), and I think that there may be something I do not fully grasp.
If you are writing a functional component, what difference does it make to put your "effect" code in a useEffect
hook vs. simply executing it in the body of the functional component (which is also executed on every render) ?
A typical use case would be fetching data when mounting a component : I see two approaches to this, one with useEffect
and one without :
// without useEffect
const MyComponent = () => {
[data, setData] = useState();
if (!data) fetchDataFromAPI().then(res => setData(res));
return(
{data ? <div>{data}</div> : <div>Loading...</div>}
)
}
// with useEffect
const MyComponent = () => {
[data, setData] = useState();
useEffect(() => {
fetchDataFromAPI().then(res => setData(res))
}, []);
return(
{data ? <div>{data}</div> : <div>Loading...</div>}
)
}
Is there an advantage (performance-wise or other) to useEffect
in such usecases ?
Upvotes: 5
Views: 1059
Reputation: 901
useEffect is handling the side effect of the problem. useEffect is the combination of componentDidMount and componentDidUpdate. every initial render and whenever props updated it will be executed.
For an exmaple:
useEffect(() => {
fetchDataFromAPI().then(res => setData(res))
}, []);
Another example:
let's assume you have multiple state variables, the component will re-render for every state values change. But We may need to run useEffect in a specific scenario, rather than executing it for each state change.
function SimpleUseEffect() {
let [userCount, setUserCount] = useState(0);
let [simpleCount, setSimpleCount] = useState(0);
useEffect(() => {
alert("Component User Count Updated...");
}, [userCount]);
useEffect(() => {
alert("Component Simple Count Updated");
}, [simpleCount]);
return (
<div>
<b>User Count: {userCount}</b>
<b>Simple Count: {simpleCount}</b>
<input type="button" onClick={() => setUserCount(userCount + 1}} value="Add Employee" />
<input type="button" onClick={() => setSimpleCount(simpleCount + 1}} value="Update Simple Count" />
</div>
)
}
In the above code whenever your props request changed, fetchDataFromAPI executes and updated the response data. If you don't use useEffect, You need to automatically handle all type of side effects.
Making asynchronous API calls for data
Setting a subscription to an observable
Manually updating the DOM element
Updating global variables from inside a function
for more details see this blog https://medium.com/better-programming/https-medium-com-mayank-gupta-6-88-react-useeffect-hooks-in-action-2da971cfe83f
Upvotes: 0
Reputation: 6325
The thing is, useEffect is not executed on every render.
To see this more clearly, let's suppose that your component MyComponent
is being rendered by a parent component (let's call it ParentComponent
) and it receives a prop from that parent component that can change from a user action.
ParentComponent
const ParentComponent = () => {
const [ counter, setCounter ] = useState(0);
const onButtonClicked = () => setCounter(counter + 1);
return (
<>
<button onClick={onButtonClicked}>Click me!</button>
<MyComponent counter={counter} />
</>
);
}
And your MyComponent
(slightly modified to read and use counter
prop):
const MyComponent = ({ counter }) => {
[data, setData] = useState();
useEffect(() => {
fetchDataFromAPI().then(res => setData(res))
}, []);
return(
<div>
<div>{counter}</div>
{data ? <div>{data}</div> : <div>Loading...</div>}
</div>
)
}
Now, when the component MyComponent
is mounted for the first time, the fetch operation will be performed. If later the user clicks on the button and the counter is increased, the useEffect will not be executed (but the MyComponent
function will be called in order to update due to counter
having changed)!
If you don't use useEffect, when the user clicks on the button, the fetch operation will be executed again, since the counter prop has changed and the render method of MyComponent
is executed.
Upvotes: 0
Reputation: 11600
I. Cleanup
What if your component gets destroyed before the fetch is completed? You get an error.
useEffect
gives you an easy way to cleanup in handler's return value.
II. Reactions to prop change.
What if you have a userId
passed in a props that you use to fetch data. Without useEffect
you'll have to duplicate userId
in the state to be able to tell if it changed so that you can fetch the new data.
Upvotes: 1