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])