簡體   English   中英

如何從同一個 Slice 中的 Reducer 方法調用 AsyncThunk 方法

[英]How to call AsyncThunk method from Reducer method in the same Slice

我有一個使用 reduxjs/toolkit 的切片,state 包含一個 ServiceRequest object 和一個 ServiceRequest 數組。

我想要實現的是; 在加載一個組件時,我想向一個 reducer 發送一個調用,它通過 id 檢查 ServiceRequest 是否已經存在於數組中,如果是,用找到的 object 填充 ServiceRequest,如果不存在,則調用同一個 AsyncThunk 方法slice 從 WebAPI 檢索它。

這是我無法弄清楚的從 reducer 或 reducer 方法中調用 AsyncThunk 方法。 也許不應該這樣做,但它似乎是將所有內容放在一起的好地方。

我怎樣才能做到這一點?

這是我到目前為止所擁有的:(你會看到我認為應該調用 AsyncThunk 方法的地方被注釋掉了)

import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit";
import { ServiceRequest } from "./models/ServiceRequest.interface";
import csmRequestDataService from "./services/csmRequestDataService";

interface AsyncState {
  isLoading: boolean;
  isSuccess: boolean;
  isError: boolean;
}

interface CSMState extends AsyncState {
  serviceRequest: ServiceRequest | null;
  serviceRequests: ServiceRequest[];
}

const initialState: CSMState = {
  isLoading: false,
  isSuccess: false,
  isError: false,
  serviceRequest: null,
  serviceRequests: [],
}

export const getServiceRequest = createAsyncThunk(
  'csm/getServiceRequest',
  async (serviceRequestId: number) => {
    try {
      console.log('getServiceRequest');
      return await csmRequestDataService.getServiceRequest(serviceRequestId);
    } catch (error) {
      console.log('Error: ', error);
    }
  });

const getOpenedServiceRequests = (
  serviceRequests: ServiceRequest[],
  serviceRequestId: number
) => {
  const serviceRequest = serviceRequests.find(
    (tsr) => tsr.ServiceRequestId === serviceRequestId
  ) || null;
  /*
  if (serviceRequest == null) {
    console.log('GET REQUEST FROM API');
    getServiceRequest(serviceRequestId);
  } else {
    console.log('GOT REQUEST FROM STORE')
  }
  */
  return serviceRequest;
};

export const csmRequestDataSlice = createSlice({
  name: ' csmRequestData',
  initialState,
  reducers: {
    retrieveServiceRequest: (state, action: PayloadAction<number>) => {
      const serviceRequest = getOpenedServiceRequests(
        state.serviceRequests,
        action.payload
      );
      state.serviceRequest = serviceRequest;
      /*
      if (serviceRequest == null) {
        console.log('GET REQUEST FROM API');
        getServiceRequest(action.payload);
      } else {
        console.log('GOT REQUEST FROM STORE')
      }
      */
    }
  },
  extraReducers(builder) {
    builder
      .addCase(getServiceRequest.pending, (state) => {
        state.isLoading = true;
      })
      .addCase(getServiceRequest.fulfilled, (state, action) => {
        if (action.payload && action.payload.serviceRequest !== null) {
          state.serviceRequests.push({ ...action.payload.serviceRequest });
          state.serviceRequest = action.payload.serviceRequest;
        }

        state.isLoading = false;
        state.isSuccess = true;
        console.log('got request data');
      })
      .addCase(getServiceRequest.rejected, (state) => {

        state.isLoading = false;
        state.isError = true;
      })
  },
});

export const { retrieveServiceRequest } = csmRequestDataSlice.actions;
export default csmRequestDataSlice.reducer;

當在任何一個地方取消對 getServiceRequest 調用的注釋時,它似乎沒有做任何事情,我在想也許可以像從組件那樣進行分派,但不確定如何實現它。

Reducer 函數被認為是純同步函數。 它們是前一個 state 和一個動作的同步函數,並返回下一個 state。你正在尋找或要求的是另一個異步動作,它進行檢查並有條件地分派另一個異步動作。

getOpenedServiceRequests轉換為 Thunk 並將第二個參數thunkAPI訪問到有效負載創建者function。使用getState獲取完整的 state object,並dispatch以分派進一步的操作,如getServiceRequest

import {
  createAsyncThunk,
  createSlice,
  PayloadAction
} from "@reduxjs/toolkit";
import { ServiceRequest } from "./models/ServiceRequest.interface";
import csmRequestDataService from "./services/csmRequestDataService";

...

export const getServiceRequest = createAsyncThunk(
  "csmRequestData/getServiceRequest",
  async (serviceRequestId: number, { rejectWithValue }) => {
    try {
      return await csmRequestDataService.getServiceRequest(serviceRequestId);
    } catch (error) {
      console.warn('Error: ', error);
      rejectWithValue(error);
    }
  },
);

export const getOpenedServiceRequests = createAsyncThunk(
  "csmRequestData/getOpenedServiceRequests",
  (serviceRequestId: number, { dispatch, getState }) => {
    // get the current complete state
    const state = getState();

    // access into state to get the serviceRequests array
    const { serviceRequests } = state.csmRequestData; // <-- * NOTE

    const serviceRequest = serviceRequests.find(
      (tsr) => tsr.ServiceRequestId === serviceRequestId
    );
    
    if (!serviceRequest) {
      // No service request, dispatch action to get it
      return dispatch(getServiceRequest(serviceRequestId));
    }
    
    // Fulfill with found service request
    return { serviceRequest };
  },
);
export const csmRequestDataSlice = createSlice({
  name: 'csmRequestData',
  initialState,
  extraReducers(builder) {
    builder
      .addCase(getOpenedServiceRequests.pending, (state) => {
        state.isLoading = true;
      })
      .addCase(getOpenedServiceRequests.fulfilled, (state, action) => {
        const { serviceRequest } = action.payload;
        if (serviceRequest) {
          state.serviceRequests.push({ ...serviceRequest });
          state.serviceRequest = serviceRequest;
        }

        state.isLoading = false;
        state.isSuccess = true;
      })
      .addCase(getServiceRequest.rejected, (state) => {
        state.isLoading = false;
        state.isError = true;
      });
  },
});

export default csmRequestDataSlice.reducer;

*注意:在這里您需要訪問全局 state object,遵循您如何組合減速器並形成 state 樹所創建的路徑。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM