can someone help explain why this code is causing an infinite loop and what is the best approach to fixing it please and thank you.
I am assuming its because of the useEffect within the App component which is causing a re-render which then the useState also causes a render therefore causing an infinite loop. I think I am not understanding how useEffect and useState works properly.
import "./styles.css";
import React, { useEffect, useState } from "react";
interface IObject {
isLoading: boolean;
isError: boolean;
data: any[] | any;
}
function useHook1(): IObject {
console.log("hook 1 too many re-renders?");
return { isLoading: false, isError: false, data: [] };
}
function useHook2(): IObject {
const result = { isLoading: false, isError: false, data: "testing" };
console.log("hook 2 too many re-renders?");
return result;
}
export default function App() {
const { isLoading, isError, data } = useHook1();
const testResult = useHook2();
const [state, setState] = useState();
useEffect(() => {
console.log("inside useEffect within App")
setState(testResult.data)
}, [testResult])
console.log("too many re-renders?");
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<p>{testing}</p>
</div>
);
}
CodePudding user response:
useHook2
returns a new object every time it runs. This means testResult
is new/changed on every render, and your useEffect
runs whenever testResult
changes. So:
Your effect updates state, which causes a re-render.
On the rerender,
useHook2
gets invoked andtestResult
is updated.testResult
changed, so your effect runs again and you return to step 1, entering an infinite loop.
The solution, if I understand what you're trying to do, is to do the state management in the custom hook:
function useHook1(): IObject {
const [state, dispatch] = useReducer(
(state, action) => ({...state, ...action}),
{ isLoading: false, isError: false, data: [] }
);
return [
state,
dispatch
];
}
export default function App () {
const [{ isLoading, isError, data }, setState] = useHook1();
return isLoading ? <div>Loading</div> : (
<div onClick={() => setState({ data: ["new data"]})}>...</div>
)
}