NX应用向共享库传props时,如何设置useAppDispatch的类型?
NX共享库通用登录组件:Redux解耦与类型处理方案
一、组件传参的优化方向
你不想让共享组件依赖全局store的思路完全正确,直接传递loginData确实不是最优解。更合理的做法是把共享组件做成纯UI受控组件:
- 共享库的
LoginForm只负责渲染表单、处理输入交互,对外暴露onSubmit(提交回调)、onInputChange(可选,输入变化回调),以及loading、error这类状态props - 应用层的
Login组件专门对接Redux:从store读取状态、调用dispatch,把这些逻辑封装成回调传给LoginForm
这种模式下组件职责清晰,完全和Redux解耦,换项目复用的时候只需要替换回调逻辑就行,灵活性更强。
二、解决dispatch的类型问题(不用any,不依赖AppDispatch)
方案1:用Redux Toolkit的通用Dispatch类型
直接从@reduxjs/toolkit导入基础Dispatch类型,结合切片的action类型做限定:
// 共享库的LoginForm组件 import { Dispatch } from '@reduxjs/toolkit'; import { login } from './loginSlice'; // 你的登录切片action type LoginFormProps = { // 推荐:只传提交回调,完全隐藏Redux细节 onSubmit: (credentials: { username: string; password: string }) => void; // 如果一定要传dispatch,限定只能触发当前切片的action dispatch?: Dispatch<ReturnType<typeof login>>; };
方案2:给切片专属定义Dispatch类型
如果你的登录切片有多个action(比如请求中、成功、失败),可以在切片文件里导出专属的Dispatch类型:
// 共享库/loginSlice.ts import { createSlice, Dispatch, PayloadAction } from '@reduxjs/toolkit'; const loginSlice = createSlice({ name: 'login', initialState: { loading: false, error: null }, reducers: { loginRequest: (state, action: PayloadAction<{ username: string; password: string }>) => { state.loading = true; }, loginSuccess: (state) => { state.loading = false; }, loginFailure: (state, action: PayloadAction<string>) => { state.loading = false; state.error = action.payload; }, }, }); export const { loginRequest, loginSuccess, loginFailure } = loginSlice.actions; // 定义该切片所有action的类型 type LoginAction = ReturnType<typeof loginRequest | typeof loginSuccess | typeof loginFailure>; // 导出专属的Dispatch类型 export type LoginDispatch = Dispatch<LoginAction>;
然后在共享组件里直接使用LoginDispatch:
import { LoginDispatch } from './loginSlice'; type LoginFormProps = { dispatch: LoginDispatch; loading: boolean; error: string | null; };
这样组件只依赖自己切片的类型,完全不牵扯应用层的AppDispatch。
三、最推荐的使用方式(完全解耦)
在应用层的Login组件里把Redux逻辑封装成回调传给共享组件:
// 应用层/Login.tsx import { useDispatch, useSelector } from 'react-redux'; import { LoginForm } from '@your-org/shared-ui'; import { loginRequest } from '@your-org/shared-features/login'; import { RootState } from './store'; export const Login = () => { const dispatch = useDispatch(); const { loading, error } = useSelector((state: RootState) => state.login); const handleSubmit = (credentials: { username: string; password: string }) => { dispatch(loginRequest(credentials)); }; return ( <LoginForm onSubmit={handleSubmit} loading={loading} error={error} /> ); };
这种模式下,LoginForm完全不知道Redux的存在,只负责UI渲染和触发回调,复用性拉满,也符合前端组件设计的最佳实践。
内容的提问来源于stack exchange,提问作者Zahin
相关产品推荐
相关产品推荐

