Search code examples
reactjsreduxdispatchtoolkit

dispatch in Redux won't add new data in store


I have an array of incomes that I display in a table. There's a "+" button to add a new income. I want to increment database and redux store with a dispatch.

Increment database works fine, but I have to reload page to see new data.

Why my dispatch does not update the state.data of incomes ?

// AddNewData.tsx
[...]
const onSubmit: SubmitHandler<FieldValues> = async (data) => {
        if (user) {
            const formData = {
                userId: user._id,
                label: data.label,
                amount: data.amountInput,
            };

            dispatch(addUserIncome(formData));
        }
    };
[...]
//incomes_slice.ts

import { IDataState, IEntry } from "../../helpers/Interfaces";
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { deleteData, getData, updateData, addData } from "../../APIs/UserData";
import { Notifier } from "../../helpers/Notifier";

const initialState: IDataState = {
    data: [],
    loading: false,
    error: null,
};

export const getUserIncomes = createAsyncThunk("incomes/getUserIncomes", (userId: string) => {
    return getData("incomes", userId);
});

export const addUserIncome = createAsyncThunk("incomes/addUserIncome", async (data: { userId: string; label: string; amount: number }) => {
    const response = await addData("incomes", data).then((res) => {
        const newEntry: IEntry = {
            _id: res.data.income._id,
            user: data.userId,
            label: data.label,
            amount: data.amount,
        };

        return newEntry;
    });

    return response;
});

export const updateUserIncome = createAsyncThunk("incomes/updateUserIncome", async (data: { id: string; data: IEntry }) => {
    await updateData("incomes", data.id, data.data);
    return data;
});

export const deleteUserIncome = createAsyncThunk("incomes/deleteUserIncome", async (incomeId: string) => {
    await deleteData("incomes", incomeId);
    return incomeId;
});

const incomesSlice = createSlice({
    name: "incomes",
    initialState,
    reducers: {},
    extraReducers: (builder) => {
        builder.addCase(getUserIncomes.pending, (state) => {
            state.loading = true;
        });
        builder.addCase(getUserIncomes.fulfilled, (state, action) => {
            state.loading = false;
            state.data = action.payload;
            state.error = null;
        });
        builder.addCase(getUserIncomes.rejected, (state, action) => {
            state.loading = false;
            state.error = action.error.message;
            action.error.message && Notifier(action.error.message, "error");
        });
        builder.addCase(addUserIncome.fulfilled, (state, action) => {
            state.data.push(action.payload);
        });
        builder.addCase(updateUserIncome.fulfilled, (state, action) => {
            state.data = state.data.map((income) => {
                if (income._id === action.payload.id) {
                    return action.payload.data;
                }
                return income;
            });
        });
        builder.addCase(deleteUserIncome.fulfilled, (state, action) => {
            state.data = state.data.filter((income) => income._id !== action.payload);
        });
    },
});

export const incomesReducer = incomesSlice.reducer;

PS: addData function is just an axios.post that works fine.


Solution

  • Inside addUserIncome you are mixing styles of awaiting a promise.

    Instead of this:

    const response = await addData("incomes", data).then((res) => {
      const newEntry: IEntry = {
        _id: res.data.income._id,
        user: data.userId,
        label: data.label,
        amount: data.amount,
      };
    
      return newEntry;
    });
    

    Either use this:

    try {
      const response = await addData("incomes", data);
      // do stuff
    } catch (e) {
      console.log(e);
    }
    

    Or do this:

    addData("incomes", data).then((res) => {
      // do stuff
    })