Generally speaking, using setState inside useEffect will create an infinite loop that most likely you don't want to cause. There are a couple of exceptions to that rule which I will get into later.
useEffect is called after each render and when setState is used inside of it, it will cause the component to re-render which will call useEffect and so on and so on.
One of the popular cases that using useState inside of useEffect will not cause an infinite loop is when you pass an empty array as a second argument to useEffect like useEffect(() => {....}, []) which means that the effect function should be called once: after the first mount/render only. This is used widely when you're doing data fetching in a component and you want to save the request data in the component's state.
Can I set state inside a useEffect hook
Can't use useEffect inside a useEffect (react ts)
Understanding useEffect()
how to get an useEffect inside a function in React?
Videos
Generally speaking, using setState inside useEffect will create an infinite loop that most likely you don't want to cause. There are a couple of exceptions to that rule which I will get into later.
useEffect is called after each render and when setState is used inside of it, it will cause the component to re-render which will call useEffect and so on and so on.
One of the popular cases that using useState inside of useEffect will not cause an infinite loop is when you pass an empty array as a second argument to useEffect like useEffect(() => {....}, []) which means that the effect function should be called once: after the first mount/render only. This is used widely when you're doing data fetching in a component and you want to save the request data in the component's state.
For future purposes, this may help too:
It's ok to use setState in useEffect . To do so, however, you need to ensure you don't unintentionally create an infinite loop.
An infinite loop is not the only problem that may occur. See below:
Imagine that you have a component Comp that receives props from parent and according to a props change, you want to set Comp's state. For some reason, you need to change for each prop in a different useEffect:
DO NOT DO THIS
useEffect(() => {
setState({ ...state, a: props.a });
}, [props.a]);
useEffect(() => {
setState({ ...state, b: props.b });
}, [props.b]);
It may never change the state of a , as you can see in this example:
https://codesandbox.io/s/confident-lederberg-dtx7w
The reason this occurs is that both useEffect hooks run during the same react render cycle. When props.a and props.b change at the same time, each useEffect captures the same stale state value from before the update. As a result, when the first effect runs, it calls setState({ ...state, a: props.a }) . Then, the second effect runs immediately after and calls setState({ ...state, b: props.b}) with the same stale state value, thereby overwriting the first update. The result is that a never appears to update. The second setState replaces the first one rather than merging the two updates together.
DO THIS INSTEAD
The solution to this problem is to call setState like this:
useEffect(() => {
setState(previousState => ({ ...previousState, a: props.a }));
}, [props.a]);
useEffect(() => {
setState(previousState => ({ ...previousState, b: props.b }));
}, [props.b]);
For more information, check the solution here: https://codesandbox.io/s/mutable-surf-nynlx
With this approach, you will always receive the most updated and correct value of the state.
I have a custom hook inside my post context file. I use it for the api call. And I call this function inside my page. I want this function to run first when my page is rendering , since I call another function there too. So i tried to put it in a useEffect but it gives me the error that I cant call useEffect inside a useEffect. Any ideas of how to solve this?
Context provider:
export const PostContextProvider = ({ children }: ChildrenType) => {const [data, setData] = useState<Post[]>([]);const [loading, setLoading] = useState(false);const [error, setError] = useState(false);const UsePosts = (url: string) => {const apiCall = useCallback(() => {setLoading(true);// console.log("post run")axios .get(url) .then((response) => {setData(response.data);setLoading(false); }) .catch((err) => {setError(err); }); }, [url]);useEffect(() => {apiCall(); }, [apiCall]); };return (<PostContext.Provider
Page:
const { postData, postLoading, postError, getPost, voteHandler } =useContext(PostContext);
const { subredditsData, getSubreddits } = useContext(SubredditContext);
useEffect(() => {
getSubreddits(https://6040c786f34cf600173c8cb7.mockapi.io/subreddits);
getPost(https://6040c786f34cf600173c8cb7.mockapi.io/subreddits/${subredditId}/posts${urlParam}); }, []);
Error says Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component.
Hi friends !
I'm quite new to ReactJS and there are some concepts that I can't figure out. One of them is useEffect...
I really dont get the difference between using useEffect and simply calling a function... I looked the documentation but it's not clearing my mind...
Someone can explain me useEffect like i was 5 years old ?
Thanks !!
You can use setInterval instead of using setTimout
Fix your code to this:
import './App.css';
import React, { useEffect, useState } from 'react';
function App() {
const time = 20;
const [count, setCount] = useState(time);
const [isStart, setIsStart] = useState(false);
useEffect(() => {
if (isStart) {
const timer = setInterval(() => {
if (count > 0) {
setCount(count - 1)
} else {
setCount('Times up');
clearInterval(timer);
}
}, 1000);
}
}, [isStart]);
return (
<div className="App">
<div>{count}</div>
<button onClick={() => setIsStart(true)}> start </button>
<button> pauze </button>
</div>
);
}
export default App;
You're trying to add useEffect inside a plain javascript function, that is why it throws an error that the useEffect you called is in a function that is not a React function component.
useEffect should not be put inside a function. You do not need that start count function. onClick can update a state, and let useEffect listen to the change of that state.