能否将独立文件中的自定义actions传入createAsyncThunk?
关于createAsyncThunk分离action类型的可行性分析
结论:可以实现,但确实属于Redux生态中的反模式
实现步骤
- 先在独立文件中定义action类型常量:
// actionTypes.js export const FETCH_DATA_PENDING = 'FETCH_DATA_PENDING'; export const FETCH_DATA_FULFILLED = 'FETCH_DATA_FULFILLED'; export const FETCH_DATA_REJECTED = 'FETCH_DATA_REJECTED'; - 创建thunk时,手动覆盖自动生成的action类型:
// fetchDataThunk.js import { createAsyncThunk } from '@reduxjs/toolkit'; import { FETCH_DATA_PENDING, FETCH_DATA_FULFILLED, FETCH_DATA_REJECTED } from './actionTypes'; const fetchDataThunk = createAsyncThunk( 'tempPrefix', async (payload) => { // 异步请求逻辑 const res = await fetch('/api/data'); return res.json(); } ); // 替换为自定义的action类型 fetchDataThunk.pending.type = FETCH_DATA_PENDING; fetchDataThunk.fulfilled.type = FETCH_DATA_FULFILLED; fetchDataThunk.rejected.type = FETCH_DATA_REJECTED; export default fetchDataThunk; - 在reducer中仅导入独立的action类型文件,无需引入thunk:
// dataReducer.js import { createSlice } from '@reduxjs/toolkit'; import { FETCH_DATA_PENDING, FETCH_DATA_FULFILLED, FETCH_DATA_REJECTED } from './actionTypes'; const initialState = { data: null, loading: false, error: null }; const dataSlice = createSlice({ name: 'data', initialState, extraReducers: (builder) => { builder .addCase(FETCH_DATA_PENDING, state => { state.loading = true; state.error = null; }) .addCase(FETCH_DATA_FULFILLED, (state, action) => { state.loading = false; state.data = action.payload; }) .addCase(FETCH_DATA_REJECTED, (state, action) => { state.loading = false; state.error = action.error.message; }); } }); export default dataSlice.reducer;
为什么是反模式?
- Redux Toolkit的核心设计目标之一就是自动管理action类型,手动分离会破坏这种封装性,增加代码维护成本——修改thunk逻辑时需要同步更新action类型文件,容易出现不一致问题
- 官方推荐直接使用
fetchDataThunk.fulfilled这类自动生成的action类型配合createSlice,代码更简洁且不易出错
更合理的替代方案
如果只是不想在reducer中导入thunk文件,可以利用typePrefix统一命名,再通过addMatcher匹配action类型:
// fetchDataThunk.js export const fetchDataThunk = createAsyncThunk( 'data/fetchData', async (payload) => { const res = await fetch('/api/data'); return res.json(); } ); // dataReducer.js import { createSlice } from '@reduxjs/toolkit'; const initialState = { /* ... */ }; const dataSlice = createSlice({ name: 'data', initialState, extraReducers: (builder) => { builder .addMatcher( action => action.type.startsWith('data/fetchData/pending'), state => { state.loading = true; } ) .addMatcher( action => action.type.startsWith('data/fetchData/fulfilled'), (state, action) => { state.loading = false; state.data = action.payload; } ) .addMatcher( action => action.type.startsWith('data/fetchData/rejected'), (state, action) => { state.loading = false; state.error = action.error.message; } ); } });
内容的提问来源于stack exchange,提问作者Konstanitnos Schoinas
相关产品推荐
相关产品推荐

