Reputation: 6798
Here's the use case. Our individual AJAX calls are behind a hook (we use apollo hooks). However, sometimes we need to make a variable number of calls (a variable for-loop). An initial AJAX calls determines how many variable calls to make to another endpoint. Unfortunately, this code does not run (React runtime error):
https://jsfiddle.net/dm3b2Lgh/
I've looked at this other question but the given approach does not work: Why can't React Hooks be called inside loops or nested function?
Is there a way to make this work?
function useInitialAjaxCall() {
const [result, setResult] = React.useState(0);
React.useEffect(() => {
const resultSize = Math.floor((Math.random() * 100) + 1);
Promise.resolve().then(() => setResult(
resultSize
))
}, [])
return result;
}
function useMockAjaxCall(i) {
const [result, setResult] = React.useState();
React.useEffect(() => {
Promise.resolve().then(() => setResult(i));
}, [i])
return result;
}
function useMakeNCalls(n) {
return [...Array(n)].map((_, i) => useMockAjaxCall(i));
}
function useCombineAjaxCalls(n) {
const resultArray = useMakeNCalls(n);
const resultCombined = React.useMemo(() => {
return resultArray.reduce((total, cur) => total + cur, 0);
}, [resultArray])
return resultCombined;
}
function Hello(props) {
const initial = useInitialAjaxCall();
const count = useCombineAjaxCalls(
initial
);
return (
<div>
<div>{initial}</div>
<div>{count}</div>
</div>
);
}
ReactDOM.render(
<Hello name="World" />,
document.getElementById('container')
);
Upvotes: 0
Views: 5314
Reputation: 22322
The original question was asking about a fixed for-loop:
if we call useState inside a loop where the number of iterations doen't change over the time
However, in your code, useInitialAjaxCall()
will return undefined during first render (because useEffect
is asynchronous - it will be executed AFTER the first render).
Then, useCombineAjaxCalls(undefined)
will call useMakeNCalls(undefined)
which will call useMockAjaxCall(0)
, calling useState
only once.
In the end of first render, initial
will be undefined and count
will be NaN.
Assuming resultSize
is different from 1, in the next render, your code will try to call useState
different number of times than 1, which is not possible as explained in the original question.
It is NOT possible to "Run react hook inside variable for-loop" - but you can create 1 state that is an array.
Upvotes: 2