在使用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
})
}
}
複製代碼