useContext和useReducer的联合用法(实现多组件多状态管理)
useReducer(reducer, initialArg, init?)
参数
- reducer:(state:S, action:A)=>newState:S;用于更新 state 的纯函数。参数为 state 和 action,返回值是更新后的 state。state 与 action 可以是任意合法值。
- initialArg:用于初始化 state 的任意值。初始值的计算逻辑取决于接下来的 init 参数。
- 可选参数 init:用于计算初始值的函数。如果存在,使用 init(initialArg) 的执行结果作为初始值,否则使用 initialArg。
返回值
- useReducer 返回一个由两个值组成的数组:
当前的 state。初次渲染时,它是 init(initialArg) 或 initialArg (如果没有 init 函数)。
- dispatch: (action: A)=>void; 函数。用于更新 state 并触发组件的重新渲染。
注意事项
- useReducer 是一个 Hook,所以只能在 组件的顶层作用域 或自定义 Hook 中调用,而不能在循环或条件语句中调用。如果你有这种需求,可以创建一个新的组件,并把 state 移入其中。
- 严格模式下 React 会 调用两次 reducer 和初始化函数,这可以 帮助你发现意外的副作用。这只是开发模式下的行为,并不会影响生产环境。只要 reducer 和初始化函数是纯函数(理应如此)就不会改变你的逻辑。其中一个调用结果会被忽略。
联合用法
定义类型
enum EActionType {
a,b,c,d
}
type State = Record<string, any>;
interface IAction {
type: EActionType;
payload: any;
}
interface IConnectProps {
state?: State;
dispatch?: Dispatch<IAction>;
}
编写reducer函数
function reducer(state: State, action: IAction) {
const { type, payload } = action;
switch(type) {
case EActionType.a:
return { ...state, ...payload };
...
default : return { ...state };
}
}
创建context
const ConnectContext = createContext<IConnectProps>({});
创建 initialState
const initialState: State = {};
初始化useReducer
export function InitConnect<S, A>(props: {children?: JSX.Element, reducer: Reducer<S, A>, initialState: S}) {
const { children, initialState, reducer } = props;
const [state, dispatch] = useReducer<Reducer<S, A>>(reducer, initialState);
return (
<ConnectContext.Provider value={ { state, dispatch } }>
{ children }
</ConnectContext.Provider>
);
}
添加state, dispatch属性
export function Connect(CustomComponent: any){
return (props: Record<string, any>) => {
const initValues = useContext(ConnectContext);
return(
<CustomComponent
state={ initValues?.state || initialState }
dispatch={ initValues?.dispatch }
{ ...props }
/>
);
};
}
使用
父级组件中初始化
<InitConnect<IState, IAction> reducer={ reducer } initialState={ initialState }>
<Target/>
</InitConnect>
子组件中使用
interface IProps extends IConnectProps {}
const demo = (props: IProps)=>{
const {state, dispatch} = props;
return <div onClick = ()=>{
dispatch?.({type: 0, {a:1}});
}>
</div>;
}
export Connect(demo);
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
2021-03-15 数据导入报错:Got a packet bigger than‘max_allowed_packet’bytes的问题