edo*_*edo 3 typescript reactjs redux redux-observable redux-toolkit
我不确定如何使用 Redux Toolkit 和 Typescript 编写 React observable 史诗。
假设我有这个 authSlice:
import { CaseReducer, createSlice, PayloadAction } from "@reduxjs/toolkit";
type AuthState = {
token: string,
loading: boolean,
};
const initialState: AuthState = {
token: "",
loading: false,
};
const loginStart: CaseReducer<AuthState, PayloadAction<{username: string, password: string}>> = (state, action) => ({
...state,
loading: true,
token: "",
});
const loginCompleted: CaseReducer<AuthState, PayloadAction<{token: string}>> = (state, action) => ({
...state,
loading: false,
token: action.payload.token,
});
const authSlice = createSlice({
name: 'auth',
initialState,
reducers: {
loginStart,
loginCompleted,
},
});
export default authSlice;
Run Code Online (Sandbox Code Playgroud)
还有这家店:
import { configureStore } from '@reduxjs/toolkit';
import { combineEpics, createEpicMiddleware } from 'redux-observable';
import authEpic from './epics/authEpic';
import authSlice from './slices/authSlice';
const epicMiddleware = createEpicMiddleware();
export const rootEpic = combineEpics(
authEpic
);
const store = configureStore({
reducer: {
auth: authSlice.reducer,
},
middleware: [epicMiddleware]
});
epicMiddleware.run(rootEpic);
export type RootState = ReturnType<typeof store.getState>;
export default store;
Run Code Online (Sandbox Code Playgroud)
我应该如何写这个 authEpic(我希望目的是不言自明的):
import { Action, Observable } from 'redux';
import { ActionsObservable, ofType } from 'redux-observable';
import { ajax } from 'rxjs/ajax';
import { switchMap } from 'rxjs/operators';
import authSlice from '../slices/authSlice';
export default (action$: ActionsObservable<???>) => action$.pipe(
ofType(???), /* should be of type loginStart */
switchMap<???,???>(action => ajax.post( // should be from a loginStart action to {token: string}
"url", {
username: action.payload.username,
password: action.payload.password
}
)),
...
);
Run Code Online (Sandbox Code Playgroud)
我完全困惑于???这就是应该是什么类型以及 redux observable 应该如何与 redux 工具包链接。
任何提示?
在 redux-toolkit 中,您应该action.match在 afilter而不是ofType类似的工作流程中使用该函数,如文档中所述。
文档中的这个示例适用于所有 RTK 操作,无论是使用createAction,createSlice还是createAsyncThunk.
import { createAction, Action } from '@reduxjs/toolkit'
import { Observable } from 'rxjs'
import { map, filter } from 'rxjs/operators'
const increment = createAction<number>('INCREMENT')
export const epic = (actions$: Observable<Action>) =>
actions$.pipe(
filter(increment.match),
map((action) => {
// action.payload can be safely used as number here (and will also be correctly inferred by TypeScript)
// ...
})
)
Run Code Online (Sandbox Code Playgroud)
问题是 redux-toolkit 掩盖了操作,因此很难知道操作类型是什么。而在传统的 redux 设置中,它们只是一堆常量。
type T = ReturnType<typeof authSlice.actions.loginStart>['type']; // T is string
// have to create an action to find the actual value of the string
const action = authSlice.actions.loginStart({username: "name", password: "pw"});
const type = action.type;
console.log(type);
Run Code Online (Sandbox Code Playgroud)
看来action.type创建的操作authSlice.actions.loginStart是“auth/loginStart”,其类型只是而string不是特定的字符串文字。公式为${sliceName}/${reducerName}。所以就ofType变成了
ofType("auth/loginStart")
Run Code Online (Sandbox Code Playgroud)
现在是通用注释。我们authEpic正在执行登录开始操作并将其转换为登录完成操作。我们可以通过查看以下方式以迂回的方式获得这两种类型authSlice:
type LoginStartAction = ReturnType<typeof authSlice.actions.loginStart>`)
Run Code Online (Sandbox Code Playgroud)
但这很愚蠢,因为我们在创建时就已经知道了动作类型authSlice。动作类型是PayloadAction你的内部CaseReducer。让我们别名并导出它们:
export type LoginStartAction = PayloadAction<{ username: string; password: string }>;
export type LoginCompletedAction = PayloadAction<{ token: string }>;
Run Code Online (Sandbox Code Playgroud)
这些是您将用于大小写缩减器的类型:
const loginStart: CaseReducer<AuthState, LoginStartAction> = ...
const loginCompleted: CaseReducer<AuthState, LoginCompletedAction> = ...
Run Code Online (Sandbox Code Playgroud)
我不太熟悉可观察的和史诗,但我认为你想要的类型authEpic是:
export default (action$: ActionsObservable<LoginStartAction>) => action$.pipe(
ofType("auth/loginStart"),
switchMap<LoginStartAction, ObservableInput<LoginCompletedAction>>(
action => ajax.post(
"url", action.payload
)
)
...
);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2432 次 |
| 最近记录: |