dispatch(toggleSwitch({ dispatch }))}> {active ? "Pause" : "Start"} // " /> dispatch(toggleSwitch({ dispatch }))}> {active ? "Pause" : "Start"} // " /> dispatch(toggleSwitch({ dispatch }))}> {active ? "Pause" : "Start"} // "/>

In Redux Toolkit, how to call a reducer function from the inside of the other

56 views Asked by At

Here is my code:

// index.tsx
<button id="start_stop" onClick={() => dispatch(toggleSwitch({ dispatch }))}>
  {active ? "Pause" : "Start"}
</button>

// timerSlice.ts
// ...
const timerSlice = createSlice({
  name: "timer",
  initialState,
  reducers: {
    toggleSwitch: (state, action) => {
      const { dispatch } = action.payload;
      if (state.intervalId) {
        clearInterval(state.intervalId);
        return {
          ...state,
          intervalId: null,
          active: false,
        };
      } else {
        // I NEED HELP WITH THIS PART
        const intervalId = setInterval(() => {
          if (state.timer === 0) {
            const audio = document.getElementById("beep") as HTMLAudioElement;
            playAudio(audio);
            // 1. How to call to sibling reducer function
            // 2. Is it correct to use dispatch
            dispatch(timerSlice.actions.toggleStatus());
            dispatch(timerSlice.actions.recalculateTimer());
            return;
          }
          dispatch(timerSlice.actions.decreaseTimer());
        }, 1000);
        return {
          ...state,
          active: true,
          intervalId,
        };
      }
    },
    decreaseBreak: (state, action) => {
      const { dispatch } = action.payload;
      if (state.active || state.break <= 1) return;
      state.break = state.break - 1;
      if (state.status === "BREAK") {
        // 3. How can I call a common-use reducer from another, like nested functions 
        dispatch(timerSlice.actions.recalculateTimer());
      }
    },
    // ...
  }  
});

This code gives me the following error on the console: Uncaught Error: You may not call store.getState() while the reducer is executing. The reducer has already received the state as an argument. Pass it down from the top reducer instead of reading it from the store.

I tried not to call a reducer from the other as possible, but it had a lot of repeated code and the worst, I should call to another reducer func inside the setInterval callback func anyway. then I tried to convert common-use reducer functions to pure functions:

const toggleStatus = (state: ITimer): ITimer => {
  return {
    ...state,
    status: state.status === "SESSION" ? "BREAK" : "SESSION",
  };
};

const recalculateTimer = (state: ITimer): ITimer => {
  return {
    ...state,
    timer: state[state.status.toLowerCase() as "session" | "break"] * 60,
  };
};

toggleSwitch: (state) => {
      if (state.intervalId) {
        // ...
      } else {
        const intervalId = setInterval(() => {
          if (state.timer === 0) {
            const audio = document.getElementById("beep") as HTMLAudioElement;
            playAudio(audio);
            // HERE IS THE NEW CODE
            const toggledStatusState = toggleStatus(state);
            const recalculatedTimerState = recalculateTimer(toggledStatusState);
            return recalculatedTimerState;
          }
          state.timer = state.timer - 1;
        }, 1000);
        return {
          ...state,
          active: true,
          intervalId,
        };
      }
    },

this also gives me an Error: **Uncaught TypeError: Cannot perform 'get' on a proxy that has been revoked **

0

There are 0 answers