[英]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.