使用useContext和useReducer实现类似于redux的简单状态管理

useContext和useReducer的联合用法(实现多组件多状态管理)

useReducer

useReducer(reducer, initialArg, init?)

参数

  1. reducer:(state:S, action:A)=>newState:S;用于更新 state 的纯函数。参数为 state 和 action,返回值是更新后的 state。state 与 action 可以是任意合法值。
  2. initialArg:用于初始化 state 的任意值。初始值的计算逻辑取决于接下来的 init 参数。
  3. 可选参数 init:用于计算初始值的函数。如果存在,使用 init(initialArg) 的执行结果作为初始值,否则使用 initialArg。

返回值

  1. useReducer 返回一个由两个值组成的数组:
    当前的 state。初次渲染时,它是 init(initialArg) 或 initialArg (如果没有 init 函数)。
  2. dispatch: (action: A)=>void; 函数。用于更新 state 并触发组件的重新渲染。

注意事项

  1. useReducer 是一个 Hook,所以只能在 组件的顶层作用域 或自定义 Hook 中调用,而不能在循环或条件语句中调用。如果你有这种需求,可以创建一个新的组件,并把 state 移入其中。
  2. 严格模式下 React 会 调用两次 reducer 和初始化函数,这可以 帮助你发现意外的副作用。这只是开发模式下的行为,并不会影响生产环境。只要 reducer 和初始化函数是纯函数(理应如此)就不会改变你的逻辑。其中一个调用结果会被忽略。

useContext

联合用法

定义类型

// EActionType
enum EActionType {
a,b,c,d
}
// state
type State = Record<string, any>;

// action
interface IAction {
type: EActionType;
payload: any;
}

interface IConnectProps {
state?: State;
dispatch?: Dispatch;
}

编写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({});

创建 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 }>

子组件中使用

interface IProps extends IConnectProps {}
const demo = (props: IProps)=>{
const {state, dispatch} = props;
return <div onClick = ()=>{
dispatch?.({type: 0, {a:1}});
}>
;
}
export Connect(demo);

posted @ 2024-03-15 17:35    阅读(118)  评论(0)    收藏  举报