'UseReducer hook doesn't update state (Can't perform a React state update on an unmounted component)

I'm trying to use useReducer instead of useState in a custom hook that loads the initial data from the API, and getting an error updating a state. (I use useReducer here for learning purposes).

The component fetches data firstly correctly, the error occurs when I update the state (book/edit/delete interview).

I left the previous useState code in the comments for better understanding.

import { useReducer, useEffect } from "react";
import axios from "axios";

const SET_DAY = "SET_DAY";
const SET_APPLICATION_DATA = "SET_APPLICATION_DATA";
const SET_INTERVIEW = "SET_INTERVIEW";

const reducer = (state, action) => {
  switch (action.type) {
    case SET_DAY:
      return { ...state, day: action.day }
    case SET_APPLICATION_DATA:
      return {
        ...state,
        days: action.days,
        appointments: action.appointments,
        interviewers: action.interviewers
      }
    case SET_INTERVIEW: {
      return { ...state, id: action.id, interview: action.interview }
    }
    default:
      throw new Error();
  }
}

export default function useApplicationData() {
  // const [state, setState] = useState({
  //   day: "Monday",
  //   days: [],
  //   appointments: {},
  //   interviewers: {}
  // });

  const initialState = {
    day: "Monday",
    days: [],
    appointments: {},
    interviewers: {}
  };
  
  const [state, dispatch] = useReducer(reducer, initialState);

  //updates the spots remaining when book/edit/cancel interview
  const updateSpots = (requestType) => {
    const days = state.days.map(day => {
      if(day.name === state.day) {
        if (requestType === 'bookInterview') {
          // return { ...day, spots: day.spots - 1 }
          return dispatch({ type: SET_DAY, spots: day.spots - 1 });
        }else {
          // return { ...day, spots: day.spots + 1 }
          return dispatch({ type: SET_DAY, spots: day.spots + 1 });
        }
      }
      // return { ...day };
      return dispatch({ type: SET_DAY, spots: day.spots });
    });
    return days;
  }

  //sets the current day data
  // const setDay = day => setState(prev => ({ ...prev, day }));
  const setDay = (day) => dispatch({ type: SET_DAY, day });

  //adds new interview data to database
  const bookInterview = (id, interview) => {
    const appointment = { ...state.appointments[id] };
    const bookOrEdit = appointment.interview ? 'edit' : 'book'; //defines the request type
    appointment.interview = { ...interview };
    const appointments = { ...state.appointments, [id]: appointment };
    
    let days = state.days;
    if (bookOrEdit === 'book') {
      days = updateSpots('bookInterview');
    } 

    return axios
      .put(`/api/appointments/${id}`, {interview})
      .then(() => {
        //setState({ ...state, appointments, days });  
        dispatch({ type: SET_INTERVIEW, id, interview });
    })
  };

 //deletes interview data from database
  const cancelInterview = (id) => {
    const appointment = {...state.appointments[id], interview: null};
    const appointments = {...state.appointments, [id]: appointment };
    const days = updateSpots();
    
    return axios
      .delete(`/api/appointments/${id}`)
      .then(() => {
        //setState({ ...state, appointments, days });
        dispatch({ type: SET_INTERVIEW, id, interview: null });
      })
  };
 
  useEffect(() => {
    let isMounted = false;
    Promise.all([
      axios.get('/api/days'),
      axios.get('/api/appointments'),
      axios.get('/api/interviewers')
    ])
    .then((all) => {
    //   setState(prev => ({
    //     ...prev,
    //     days: all[0].data,
    //     appointments: all[1].data,
    //     interviewers: all[2].data}));
    // });
      if (!isMounted) {
        console.log("done!");
      }
      isMounted = true;
 
      dispatch({ type: SET_APPLICATION_DATA, days: all[0].data, appointments: all[1].data, interviewers:all[2].data });
  
    });  
  }, []);
  return { state, setDay, bookInterview, cancelInterview }
};

I'd be appreciated for pointing me in the right direction on what I'm doing wrong. Thank you!



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source