使用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<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);
posted @     阅读(59)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 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的问题
点击右上角即可分享
微信分享提示