React useContext + useReducer 实现 Hooks 状态管理功能
App.tsx
import { useReducer } from 'react';
import { BrowserRouter, Switch } from 'react-router-dom';
import { renderRoutes } from 'react-router-config';
import routes from './router';
import { UserContext } from '@/store/user';
import { IUser, IReducerAction } from '@/common/types/interface';
import { UserStoreActionType } from '@/common/types/enum';
function App() {
const myUserReducer = (state: IUser, action: IReducerAction): IUser => {
const { type } = action;
switch (type) {
case UserStoreActionType.SetData:
localStorage.setItem('userInfo', JSON.stringify({ ...state, ...action.params }));
return { ...state, ...action.params };
default:
return state;
}
};
const userStorage = localStorage.getItem('userInfo') || '';
const initialUserState = userStorage ? JSON.parse(userStorage) : null;
const [store, dispatch] = useReducer(myUserReducer, initialUserState);
return (
<UserContext.Provider value={{ store, dispatch }}>
<BrowserRouter>
<Switch>{renderRoutes(routes)}</Switch>
</BrowserRouter>
</UserContext.Provider>
);
}
export default App;
创建 createContext (@/store/user)
import { createContext } from 'react';
import { IUser, IReducerAction } from '@/common/types/interface';
// import { UserStoreActionType } from '@/common/types/enum';
interface ICreateContext {
store: IUser;
dispatch: (params: IReducerAction) => void;
}
export const UserContext = createContext<ICreateContext>({
store: {
userName: '',
sex: '',
age: '',
mobile: '',
mailbox: '',
password: ''
},
dispatch: () => {},
});
在登录时获取接口返回的数据,并更新到 store 中
import React, { useContext, useEffect } from 'react';
import { useHistory } from 'react-router-dom';
import { LoginWrapper, LoginContainer } from './styled';
import { Form, Input, Button, message } from 'antd';
import { login } from '@/api/login';
import { UserContext } from '@/store/user';
import { UserStoreActionType } from '@/common/types/enum';
import { useRequest } from 'ahooks';
import { useForm } from 'antd/lib/form/Form';
interface ILogin {
userName: string;
password: string;
}
const Login: React.FC = () => {
const history = useHistory();
const { dispatch } = useContext(UserContext);
const [form] = useForm<ILogin>();
useEffect(() => {
// 设置默认参数
form.setFieldsValue({ userName: 'Fengchengzhi', password: '123456' });
}, []);
const { loading, run } = useRequest((formVal: ILogin) => login(formVal), {
manual: true,
onSuccess: (res) => {
message.success((res as any).message);
dispatch({
type: UserStoreActionType.SetData,
params: res.data,
});
setTimeout(() => {
history.push('/home');
}, 1000);
}
});
const onFinish = (formData: ILogin) => {
run(formData);
};
const onFinishFailed = () => {
// throw new Error('请填写完整信息!');
};
// 注册
const onRegister = () => {
history.push('/register');
};
return (
<LoginWrapper>
<LoginContainer>
<h2>登录</h2>
<Form
name="basic"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
form={form}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
>
<Form.Item
label="Username"
name="userName"
rules={[{ required: true, message: 'Please input your username!' }]}
>
<Input />
</Form.Item>
<Form.Item
label="Password"
name="password"
rules={[{ required: true, message: 'Please input your password!' }]}
>
<Input.Password />
</Form.Item>
<Form.Item wrapperCol={{ offset: 10, span: 14 }}>
<Button
type="primary"
loading={loading}
htmlType="submit"
>
登录
</Button>
</Form.Item>
<Form.Item wrapperCol={{ offset: 10, span: 14 }}>
<Button type="link" onClick={onRegister}>
注册
</Button>
</Form.Item>
</Form>
</LoginContainer>
</LoginWrapper>
);
};
export default Login;
UserStoreActionType
export enum UserStoreActionType { SetData = 'SET_DATA', }
获取 store 数据并展示
import React, { useContext } from "react"; import { HeaderWrapper } from './styled' import { UserContext } from '../../store/user' const HeaderComps: React.FC = () => { const { store: userInfo } = useContext(UserContext) return ( <HeaderWrapper className="header-wrapper"> 用户姓名:{ userInfo.userName } </HeaderWrapper> ) } export default HeaderComps