Search code examples
javascriptreactjsredux-toolkit

Uncaught TypeError: typeOrActionCreator is undefined


I get an error for second builder and it says: Uncaught TypeError: typeOrActionCreator is undefined. I don't know what's wrong with that builder. And when I remove that builder, it errors about next builder. (Note I dispatch my thunkFunction from last builder)

export const updateSelectedOrNewMovementData = ("myMovements/updateSelectedOrNewMovementData", async(allData) => {
    const {data, type, motion_id} = allData
    try{
        const {receivedData} = await patchRequest(`/coach/motion/${motion_id}`, data)
        return type
    }
    catch (err) {
        console.error("err", err.response.data.message);
    }
})

...here there are codes for my slice.

extraReducers(builder) {
        builder
            .addCase(handleGetMyMovements.fulfilled, (state, action) => {
                const data = action.payload;
                if (data?.length > 0) {
                    state.myMovements = [...state.myMovements, ...data];
                    state.myMovementsTemp = [...state.myMovements, ...data];
                }
                if (data?.length >= 20) {
                    state.status.isNotMoreData = true;
                } else {
                    state.status.isNotMoreData = false;
                }
                state.status.myMovementsLoading = false;
            })
            .addCase(handleGetMyMovements.pending, (state, action) => {
                state.status.myMovementsLoading = true;
            });
        builder
            .addCase(updateSelectedOrNewMovementData.fulfilled, (state, action) => {
                if (action?.payload === "formData") {
                    state.status.selectedOrNewMovementLoading = "sentData"
                    setTimeout(() => {
                        state.status.selectedOrNewMovementLoading = false
                        window.history.back();
                    }, 3000);
                }
            })
            .addCase(updateSelectedOrNewMovementData.pending, (state, action) => {
                if (action?.payload === "formData") {
                    state.status.selectedOrNewMovementLoading = true
                }
            })
            .addCase(updateSelectedOrNewMovementData.rejected, (state, action) => {
                state.status.selectedOrNewMovementLoading = "error"
            });
        builder
            .addCase(createNewMovement.fulfilled, (state, action) => {
                const payload = action?.payload
                const dispatch = payload?.dispatch
                state.status.selectedOrNewMovementLoading = false
                if (payload?.data?.is_successful) {
                    state.motionId = payload?.data?.motion_id
                    dispatch(updateSelectedOrNewMovement({
                        data: payload?.myForm,
                        type: "formData",
                        motion_id: payload?.data?.motion_id
                    }))
                    dispatch(updateSelectedOrNewMovement({
                        data: payload?.textFormBody,
                        type: "rawData",
                        motion_id: payload?.data?.motion_id
                    }))
                }
            })
            .addCase(createNewMovement.pending, (state, action) => {
                state.status.selectedOrNewMovementLoading = true
            })
            .addCase(createNewMovement.rejected, (state, action) => {
                state.status.selectedOrNewMovementLoading = "error"
            })
    },

Solution

  • You are not allowed in Redux, ever, to dispatch from inside a reducer. The same goes for asynchronous logic like doing a setTimeout.

    Reducer logic has to be a pure synchronous function without side effects.

    You might want to do the logic you are currently doing in a thunk or with the listener middleware instead.

    All that said, the problem you are incountering is because one of the actions you are passing to one of your .addCase calls seems to be undefined.

    That's probably caused by your updateSelectedOrNewMovementData being a normal function. It's not an async thunk, so it has no pending, fulfilled or rejected properties. You have to use createAsyncThunk for that.

    - export const updateSelectedOrNewMovementData = ("myMovements/updateSelectedOrNewMovementData", async(allData) => {
    + export const updateSelectedOrNewMovementData = createAsyncThunk("myMovements/updateSelectedOrNewMovementData", async(allData) => {
    

    Frankly, a lot of this code looks kinda right, but then is making a lot of tiny errors that show that your are missing some important basics.

    I would recommend that you go through the Redux Essentials tutorial and following these to get a good grasp of the Redux data flow.