Bas
Bas

Reputation: 1433

How to run async call on a reducer?

import { createSlice, PayloadAction } from "@reduxjs/toolkit"
import { Dispatch } from 'redux';
import axios from "axios"
const API_URL = process.env.REACT_APP_API_HOST_URL || ""

export type projectObj = {
    id?: number
    createdBy?: number,
    title: string,
    description: string,
    endDate: string,
    priority: 'Critical' | 'High' | 'Medium' | 'Low',
    status: 'Not Active' | 'In Progress' | 'Completed',
    progress: number,
    favorite: boolean


}

interface projectState {
    projects: projectObj[],
    projectFetching: boolean
}

const initialState : projectState = {
    projects : [],
    projectFetching: false

}


export const projectSlice = createSlice({
    name: 'projectReducer',
    initialState,
    reducers: {
        /* errors here */
        create: async (state, action : PayloadAction<projectObj>) => {
            const projectObj = action.payload
            state.projects.push(await createProject(projectObj))
        }
    },

})

// CREATE PROJECT

const createProject = async (projectObj : projectObj)  : Promise<projectObj> => {
    try {
        const project : projectObj = await axios.post(`${API_URL}/api/projects`, projectObj)
        return project
    } catch (err : any) {
        return projectObj
    }
}

export const { create } = projectSlice.actions

export default projectSlice.reducer

Create takes in a projectObj with the props list above and my api will create a new project and then return the project object with id in it. I want to push that into my state.

This errors in the create action. The function createProject returns a promise that I need to await on. . What is the proper way to go about this ?

Edit to ask question about answer-

export const projectSlice = createSlice({
    name: 'projectReducer',
    initialState,
    reducers: {
        create: (state, action: PayloadAction<projectObj>) => {
            const projectObj = action.payload
            state.projects.push(projectObj)
        }
    },
})  


export const createProject = (projectObj: projectObj) => async (dispatch: Dispatch) => {
    try {
        const response = await axios.post(`${API_URL}/api/projects`, projectObj)
        const data: projectObj = response.data.project
        dispatch(create(data))
    } catch (err: any) {
        console.log(err)
    }
}

Upvotes: 0

Views: 1705

Answers (1)

A G
A G

Reputation: 22579

Handle Async Requests with the createAsyncThunk.

const createProjectThunk = createAsyncThunk(
  "project/createNew",
  async (projectObj: projectObj) => {
    const response = await createProject(projectObj);
    return response;
  }
);

export const projectSlice = createSlice({
  name: "projectReducer",
  initialState,
  reducers: {
    /* errors here */
  },
  extraReducers: (builder) => {
    // Add reducers for additional action types here, and handle loading state as needed
    builder.addCase(createProjectThunk.fulfilled, (state, action) => {
      // Add user to the state array
      state.projects.push(action.payload);
    });
  }
});

Upvotes: 1

Related Questions