I am trying to set my initial state via useReducer. This data comes from an API, so I have placed it within useEffect
and applied a dispatch method. (I need to use useReducer
because I have more complex logic to come later.)This works however it causes an infinite number of calls to the API and if I console log the state, it just loops draining the memory.
For reference, when I log with eg:
const { state, dispatch } = useContext(CanvasContext);
// console.log(state);
I would just like it to run once on load, however when I add specific values to the useEffect
array it doesn't help. Is there a way to stop the infinite loop? I have tried to use a check if mounted approach (as recommended by other answers, but don't really understand what I should be doing with it).
Thank you.
export const CanvasContext = React.createContext([]);
function cartReducer(state, action) {
switch (action.type) {
case "INITIALIZE":
return action.payload;
default:
return state;
}
}
const initialState = {
initialized: false,
robots: [],
cart: [],
};
export const CanvasProvider = ({ children }) => {
const [state, dispatch] = useReducer(cartReducer, initialState);
useEffect(() => {
getStoredCanvas().then((response) => {
dispatch({
type: "INITIALIZE",
payload: {
...initialState,
robots: response?.data.elements,
initialized: true,
},
});
});
}, []);
return (
<>
{state.robots.length && (
<CanvasContext.Provider value={{ state, dispatch }}>
{children}
</CanvasContext.Provider>
)}
</>
);
};
// getStoredCanvas
export async function getStoredCanvas() {
let canvas;
try {
if (useLocal) {
canvas = axios.get(endPoints.local);
} else {
canvas = axios.post(endPoints.remote, testLoadCanvas);
// .then((response) => console.log(response));
}
return canvas;
} catch (error) {
console.error(error);
}
}
CodePudding user response:
Looks like you're throwing around an initialized
variable, but never using it. Seems like that variable is only ever relevant whenever the provider is mounted. With that being said, I would move the variable into a state variable and use it to ensure the initialization process only ever happens once:
export const CanvasProvider = ({ children }) => {
const [state, dispatch] = useReducer(cartReducer, initialState);
const [initialized, setInitialized] = useState(false)
useEffect(() => {
if(initialized) return
getStoredCanvas().then((response) => {
setInitialized(true)
dispatch({
type: "INITIALIZE",
payload: {
...initialState,
robots: response?.data.elements,
},
});
});
}, [dispatch, initialized]);
return (
<>
{state.robots.length && (
<CanvasContext.Provider value={{ state, dispatch }}>
{children}
</CanvasContext.Provider>
)}
</>
);
};