Redux Toolkit:如何将使用 createAction 创建的操作作为类型引用
Posted
技术标签:
【中文标题】Redux Toolkit:如何将使用 createAction 创建的操作作为类型引用【英文标题】:Redux Toolkit: How to refer action created with createAction as type 【发布时间】:2020-06-08 04:03:15 【问题描述】:Redux 工具包提供了createAction
辅助方法。我在引用使用 createAction
作为类型创建的操作时遇到问题。
例如:
const getData = createAction<PayloadAction<number>>('user/getData')
function* exampleSaga(action: ?)
...
我如何告诉 exampleSaga
action
的类型是 getData
?
要查看我是如何尝试的,请参考以下(示例)代码并查看我面临的问题的 cmets:
reducer.ts
import createAction, PayloadAction from '@reduxjs/toolkit';
export const getData = createAction<PayloadAction<number>>('user/getData');
const userSlice = createSlice(
name: userSliceName,
initialState,
reducers:
getUser(state: IUserState): void
state.loading = true;
state.error = null;
,
getUserSuccess(state: IUserState, action: PayloadAction< user: IUser >): void
const user = action.payload;
state.user = user;
state.loading = false;
state.error = null;
,
getUserFailure(state: IUserState, action: PayloadAction<string>): void
state.loading = false;
state.error = action.payload;
,
,
);
export type UserSaga = Generator<
| CallEffect<IUser>
| PutEffect<typeof getUserSuccess>
| PutEffect<typeof getUserFailure>
| ForkEffect<never>
>;
sagas.ts
import UserSaga, getData from './reducer.ts';
// For the following fetchUser saga arguments, how can I define that 'action' is of type getData, imported from the above 'reducer.ts' file.
function* fetchUser(action: PayloadAction<typeof getData>): UserSaga
try
const userId = action.payload;
// Problem is here
// I expect userId to be of type number, whereas it is:
// ActionCreatorWithPayload<payload: number, type: string>
...
catch (e)
...
function* userSaga(): UserSaga
const pattern: any = getData.type;
yield takeLatest(pattern, fetchUser);
【问题讨论】:
【参考方案1】:这是使用 getData 的返回类型获取它的方式。
function* exampleSaga(action: ReturnType<typeof getData>)
...
【讨论】:
【参考方案2】:我做了更多的挖掘,这就是我解决这个问题的方法。
可以在不将其绑定到 SliceCaseReducer 的情况下创建操作:(请注意,下面创建的 getData
本身不是 Action,而是 ActionCreator )。
common.ts
import createAction from '@reduxjs/toolkit';
export const getData = createAction<number>('getData');
getData
如果给定了正确的有效负载,则已经准备好从 FunctionComponent 分派:
component.tsx
import React, useEffect from 'react';
import useDispatch from 'react-redux';
import useParams from 'react-router';
import getData from './state/common';
const User: React.FC = (): React.ReactElement =>
const userId = useParams();
const dispatch = useDispatch();
useEffect((): void =>
dispatch(getData(Number(userId)));
, []);
return (<>User Component</>);
;
export default UserContainer;
与传奇
让传奇听着行动
Saga Effects 接受字符串类型的动作来做出反应。幸运的是,actionCreator 公开了一个 type 属性,表示操作的已定义字符串名称。
saga.ts(监听器)
import takeLatest from 'redux-saga/effects';
import getData from './common';
function* userSaga()
// getData.type could be input to a Saga Effect
yield takeLatest(getData.type, fetchUser); // fetchUser is a worker saga explained below
将动作指定为 saga 的参数。
将动作指定为 saga 的参数有点棘手,我们必须使用 TypeScript 的 Type Guards。有趣的是,redux-toolkit 的documentation 中也提到了它。简而言之,我们必须使用 actionCreator 的actionCreator.match
方法来将传递的动作区分为所需的类型。因此,经过区分后,我们会收到匹配操作的有效负载所需的静态类型。
saga.ts(工人)
import Action from '@reduxjs/toolkit';
import call, put from 'redux-saga/effects';
import * as userApi from '../../../api/user-api';
import getData from './common';
import getUserSuccess, getUserFailure from './user';
// Note that we can't directly specify that fetchUser only accepts getData action type.
function* fetchUser(action: Action)
try
// getData.match could be used to assert that we are only concerned with getData action type
if (getData.match(action))
// Inside the body of if, we get correct static typing
const userId = action.payload;
const fetchedUser = yield call(userApi.getUser, userId);
yield put(getUserSuccess(user: fetchedUser));
catch (e)
yield put(getUserFailure(e.message));
【讨论】:
以上是关于Redux Toolkit:如何将使用 createAction 创建的操作作为类型引用的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 redux-toolkit 动态更改基本 URL?
如何在 Storybook 中使用 redux-toolkit?
Redux Toolkit RTK Query 发送查询参数
使用 @reduxjs/toolkit 中的 configureStore 时如何重置 Redux Store 的状态?
如何使用 redux-toolkit 中的 createSlice 方法在不同的 reducer 函数中使用单个动作类型