I’m fetching some data from an API, but since I am using this data to update a state within a useEffect
, this state becomes a required dependency, which causes a circular loop.
state is updated -> useEffect is called -> state is updated ...
I read a lot of answers and articles about that, but I couldn’t find an answer to my specific question.
This is my initial code:
let [state, setState] = React.useState<IDataSource[]>([]) React.useEffect(() => { let dataSource: IDataSource[] = [] dataFetched.forEach((item, index) => { // Some logic }) setState(state.concat(dataSource)) }, [dataFetched, state])
Then I decided to update the state using a function called by useEffect
and passing an argument:
let [state, setState] = React.useState<IDataSource[]>([]) const updateData = (arg: IDataSource[] => { setData(state.concat(arg)) } React.useEffect(() => { let dataSource: IDataSource[] = [] dataFetched.forEach((item, index) => { //Some logic }) updateData(dataSource) }, [dataFetched, updateData])
This works, but since I have updateData
as a useEffect depency
I have to wrap the function with useCallback
:
const updateData = React.useCallback((arg: IDataSource[]) => { setData(state.concat(arg)) }, [state]) React.useEffect(() => { let dataSource: IDataSource[] = [] dataFetched.forEach((item, index) => { //Some logic }) updateData(dataSource) }, [dataFetched, updateData])
But in this case I also have state
as a useCallback depency
and I’m back to the starting problem, a circular loop.
Apparently I should use React.useRef
when I have an array as useEffect dependency
, but state
is not just an array, it is actually a state, which is being set with useState
, so I don’t know how to do that in this case or even if this is possible.
Is there a way to solve that?
Advertisement
Answer
You can remove data
from the useEffect
array and call setState
with an updater function like this setState(prevState => prevState.concat(dataSource))
const [state, setState] = React.useState<IDataSource[]>([]) React.useEffect(() => { const dataSource: IDataSource[] = [] dataFetched.forEach((item, index) => { // Some logic to fill the dataSource array ?? }) setState(prevState => prevState.concat(dataSource)) }, [dataFetched])