Typescript + useContext + useReducer实现全局状态存储及更新
场景:
React应用需要实现登录界面与Dashboard界面的切换。
使用一个全局变量存储用户信息,如果为空,则进入登录界面;否则进入Dashboard界面。
实现方法:
通过useContext保存全局用户信息,如果全局user对象的email字段为空,就说明退出登录,否则为登录状态。
UserContext
import React, { useContext } from "react";
export type User = {
email: string
}
export type Action =
| { type: 'login', payload: User }
| { type: 'logout', payload: User }
export const initState: User = {
email: ''
}
export function userReducer(state:User, action: Action){
switch (action.type) {
case 'login': //login with user info
return {
...state,
email: action.payload.email
}
case 'logout': //logout return true
return initState;
default:
return state;
}
}
const UserContext = React.createContext<{
state: User;
dispatch: React.Dispatch<Action>;
}>({
state: initState,
dispatch: () => undefined,
});
export default UserContext;
index.tsx
import React, { useEffect, useState, useReducer } from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import LoginForm from './Login';
import UserContext, { User, Action, userReducer, initState } from './context/UserContext';
import styled from 'styled-components';
const LoginBox = styled.div`
position: absolute;
top: 25%;
left: calc(50% - 100px);
padding: 25px;
border: none;
box-shadow: 0 2px 4px rgb(0 0 0 / 10%), 0 8px 16px rgb(0 0 0 / 10%);
`
function Root() {
const [state, dispatch] = useReducer(userReducer, initState);
return(
<UserContext.Provider value={{ state, dispatch: dispatch }}>
{!state.email? <LoginBox><LoginForm /></LoginBox>
:<App></App> }
</UserContext.Provider>
)
}
ReactDOM.render(
<React.StrictMode>
<Root />
</React.StrictMode>,
document.getElementById('root')
);
Login.tsx
此处在点击login button时调用dispath,type为"login"
import React, { useContext } from 'react';
import { Form, Input, Button, Checkbox } from 'antd';
import { UserOutlined, LockOutlined } from '@ant-design/icons';
import "antd/dist/antd.css";
import styled from 'styled-components';
import UserContext from './context/UserContext';
const responseGoogle = (response: any) => {
console.log(response);
}
const LoginBtn = styled(Button)`
width: 100%;
`
const NormalLoginForm = () => {
const userContext = useContext(UserContext);
const onFinish = (values: any) => {
console.log('Received values of form: ', values);
userContext.dispatch({
type: 'login',
payload: { email: values.username }
});
};
return (
<Form
name="normal_login"
className="login-form"
initialValues={{ remember: true }}
onFinish={onFinish}
>
<Form.Item
name="username"
rules={[{ required: true, message: 'Please input your Username!' }]}
>
<Input prefix={<UserOutlined className="site-form-item-icon" />} placeholder="Username" />
</Form.Item>
<Form.Item
name="password"
rules={[{ required: true, message: 'Please input your Password!' }]}
>
<Input
prefix={<LockOutlined className="site-form-item-icon" />}
type="password"
placeholder="Password"
/>
</Form.Item>
<Form.Item>
<Form.Item name="remember" valuePropName="checked" noStyle>
<Checkbox>Remember me</Checkbox>
</Form.Item>
</Form.Item>
<Form.Item>
<LoginBtn type="primary" htmlType="submit" className="login-form-button">
Log in
</LoginBtn>
</Form.Item>
</Form>
);
};
export default NormalLoginForm;
同样的,如果要退出登录,可以通过以下代码实现
const userContext = useContext(UserContext);
const onLogout = () => {
userContext.dispatch({
type: 'logout',
payload: { email: '' }
});
}
分类:
React
, TypeScript
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具