Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to stop infinite loop when setting initial state from API with useReducer (React Hooks)

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

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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);
  }
}

>Solution :

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>
      )}
    </>
  );
};
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading