对于那些在使用 thunk 和 hooks 时难以处理调度功能的人来说,这只是一个建议。
这是一个我正在做什么来管理身份验证状态的示例,从 graphql 服务器获取数据。定义调度类型type IAppDispatch = ThunkDispatch<IAppState, any, IAppActions>;时神奇来了
store.ts
import { applyMiddleware, combineReducers, compose, createStore } from "redux";
import thunkMiddleware, { ThunkDispatch, ThunkMiddleware } from "redux-thunk";
import { authReducer } from "./reducers/authReducers";
import { IAuthActions } from "./types/authTypes";
const composeEnhancers =
process.env.NODE_ENV === "development"
? (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
: compose;
const rootReducer = combineReducers({
authReducer,
});
type IAppActions = IAuthActions; <-- merge here other actions
type IAppState = ReturnType<typeof rootReducer>;
type IAppDispatch = ThunkDispatch<IAppState, any, IAppActions>; <--here is the magic
const reduxStore = createStore(
rootReducer,
composeEnhancers(
applyMiddleware<IAppDispatch, any>(
thunkMiddleware as ThunkMiddleware<IAppState, IAppActions, any>
)
)
);
export { reduxStore, IAppState, IAppDispatch, IAppActions };
authActions(动作创建者和调度 thunk 动作)
import { Dispatch } from "redux";
import {
loginMutation,
logoutMutation,
} from "../../components/DataComponents/Authentification/fetchAuthentification";
import { GqlSessionUser } from "../../components/DataComponents/generatedTypes";
import {
IAuthActions,
IAuthErrorAction,
IAuthLoadingAction,
IAuthLoginAction,
IAuthLogoutAction,
} from "../types/authTypes";
const authLogin = (appUserId: GqlSessionUser): IAuthLoginAction => {
return {
type: "AUTH_LOGIN",
payload: {
appUserId,
},
};
};
const authLogout = (): IAuthLogoutAction => {
return {
type: "AUTH_LOGOUT",
};
};
const authLoadingAction = (isLoading: boolean): IAuthLoadingAction => {
return {
type: "AUTH_LOADING",
payload: {
isLoading,
},
};
};
const authErrorAction = (errorMessage: string): IAuthErrorAction => {
return {
type: "AUTH_ERROR",
payload: {
errorMessage,
},
};
};
const authLoginAction = (idOrEmail: string) => {
return async (dispatch: Dispatch<IAuthActions>) => {
dispatch(authLoadingAction(true));
const { data, errors } = await loginMutation(idOrEmail); <--fetch data from GraphQl
if (data) {
dispatch(authLogin(data.login.data[0]));
}
if (errors) {
dispatch(authErrorAction(errors[0].message));
}
dispatch(authLoadingAction(false));
return true;
};
};
const authLogoutAction = () => {
return async (dispatch: Dispatch<IAuthActions>) => {
dispatch(authLoadingAction(true));
await logoutMutation(); <--fetch data from GraphQl
dispatch(authLogout());
dispatch(authLoadingAction(false));
return true;
};
};
export {
authLoginAction,
authLogoutAction,
authLoadingAction,
authErrorAction,
};
使用状态并通过 useDispatch 分派异步操作的组件示例
请不要将 dispatch 键入为 IAppDispatch,尽管它是从 react-redux 导入的
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import {
authLoginAction,
authLogoutAction,
} from "../../../stateManagement/actions/authActions";
import { IAppDispatch, IAppState } from "../../../stateManagement/reduxStore";
import Button from "../../Button";
const Authentification: React.FC = (): JSX.Element => {
const dispatch: IAppDispatch = useDispatch(); <--typing here avoid "type missing" error
const isAuth = useSelector<IAppState>((state) => state.authReducer.isAuth);
const authenticate = async (idOrEmail: string): Promise<void> => {
if (!isAuth) {
dispatch(authLoginAction(idOrEmail)); <--dispatch async action through thunk
} else {
dispatch(authLogoutAction()); <--dispatch async action through thunk
}
};
return (
<Button
style={{
backgroundColor: "inherit",
color: "#FFFF",
}}
onClick={() => authenticate("jerome_altariba@carrefour.com")}
>
{isAuth && <p>Logout</p>}
{!isAuth && <p>Login</p>}
</Button>
);
};
export { Authentification };