在使用React
开发项目的时候,一般对于一些全局数据咱们都会选择使用redux
来进行管理,可是在有些场景却不必定非要使用redux
,好比下面的几个场景react
对于这两个 场景就能够使用useReducer
+ useContext
来模拟一个redux
来进行状态管理redux
useReducer
+useContext
组件import React, {
Dispatch,
useReducer,
createContext,
useContext,
useEffect,
Reducer,
} from 'react';
export interface ReducerContextResult<T, A> {
useStore: () => T;
useDispatch: () => Dispatch<A>;
StoreProvider: React.FC<any>;
}
function createReducerContext<T, A>( initState: T, reducer: Reducer<T, A>, initData?: (state: T, dispatch: Dispatch<A>) => void, ): ReducerContextResult<T, A> {
const StateContext = createContext(initState);
const DispatchContext = createContext({} as Dispatch<A>);
function useStore(): T {
return useContext(StateContext);
}
function useDispatch(): Dispatch<A> {
return useContext(DispatchContext);
}
function StoreProvider({ children }: { children: React.ReactNode }) {
const [state, dispatch] = useReducer<Reducer<T, A>>(reducer, initState);
useEffect(() => {
/*eslint-disable*/
initData && initData(initState, dispatch);
}, []);
return (
<StateContext.Provider value={state}> <DispatchContext.Provider value={dispatch}> {children} </DispatchContext.Provider> </StateContext.Provider>
);
}
return {
useStore,
useDispatch,
StoreProvider,
};
}
export default createReducerContext;
复制代码
如上代码,咱们封装了一个通用的createReducerContext
,接下来看一下如何使用这个组件呢markdown
// 声明一个action_type
export enum ACTION_TYPE {
INIT = 'init',
UPDATE = 'update'
// 添加其余TYPE
}
export interface IUser{
name: string;
sex: number;
}
export interface IState {
userInfo: IUser[];
// 其余state
}
export default IAction{
type: ACTION_TYPE;
data: any;
}
const initState: IState {
userInfo: [];
}
function reducer(state: IState, action: IAction): IState {
switch (action.type) {
case ACTION_TYPE.INIT:
return { ...action.data };
default:
return state;
}
}
const contextResult: ReducerContextResult<IState, IAction> = createReducerContext<
IState,
IAction
>(initState, reducer, (state: IState, dispatch: Dispatch<IAction>) => {
// 在这里能够初始化数据
loadData().then(data => {
dispatch({
type: ACTION_TYPE.INIT,
data
})
})
});
export const { useStore, useDispatch, StoreProvider } = contextResult;
复制代码
在容器页面使用StoreProvider
ide
import {StoreProvider} from './context'
export default function() {
return <StoreProvider> <!--容器内容--> </StoreProvider>
}
复制代码
在子组件使用useStore
和useDispatch
ui
import {useStore, useDispatch, ACTION_TYPE} from './context'
const UserList = (props) => {
// 数据
const {data} = useStore()
// 经过dispatch 更新数据
const dispatch = useDispatch()
// 使用dispatch更新数据
function updateData(result) {
dispatch({
type: ACTION_TYPE.UPDATE,
data: result
})
}
}
复制代码