react 中的userReducer
useReducer-基础概念篇
useReducer-使用篇
useReducer-配合useContext使用
我们在第一篇文章中介绍了JavaScript中的reducer以及他的一些特点,对reducer不熟悉的小伙伴可以先看看第一篇。
React Hook功能正式发布之后,允许在function component中拥有state和副作用(useEffect)。官方提供了两种state管理的hook:useState、useReducer。下面我们会通过一系列Demo逐步说明如何使用useReducer管理state。
useState版login
我们先看看登录页常规的使用useState的实现方式:
function LoginPage() {const [name, setName] = useState(''); // 用户名const [pwd, setPwd] = useState(''); // 密码const [isLoading, setIsLoading] = useState(false); // 是否展示loading,发送请求中const [error, setError] = useState(''); // 错误信息const [isLoggedIn, setIsLoggedIn] = useState(false); // 是否登录const login = (event) => {event.preventDefault();setError('');setIsLoading(true);login({ name, pwd }).then(() => {setIsLoggedIn(true);setIsLoading(false);}).catch((error) => {// 登录失败: 显示错误信息、清空输入框用户名、密码、清除loading标识setError(error.message);setName('');setPwd('');setIsLoading(false);});}return ( // 返回页面JSX Element)
}
上面Demo我们定义了5个state来描述页面的状态,在login函数中当登录成功、失败时进行了一系列复杂的state设置。可以想象随着需求越来越复杂更多的state加入到页面,更多的setState分散在各处,很容易设置错误或者遗漏,维护这样的老代码更是一个噩梦。
useReducer版login
下面看看如何使用useReducer改造这段代码,先简单介绍下useReducer。
const [state, dispatch] = useReducer(reducer, initState);
useReducer接收两个参数:
第一个参数:reducer函数,没错就是我们上一篇文章介绍的。第二个参数:初始化的state。返回值为最新的state和dispatch函数(用来触发reducer函数,计算对应的state)。按照官方的说法:对于复杂的state操作逻辑,嵌套的state的对象,推荐使用useReducer。
听起来比较抽象,我们先看一个简单的例子:
// 官方 useReducer Demo
// 第一个参数:应用的初始化
const initialState = {count: 0};// 第二个参数:state的reducer处理函数
function reducer(state, action) {switch (action.type) {case 'increment':return {count: state.count + 1};case 'decrement':return {count: state.count - 1};default:throw new Error();}
}function Counter() {// 返回值:最新的state和dispatch函数const [state, dispatch] = useReducer(reducer, initialState);return (<>// useReducer会根据dispatch的action,返回最终的state,并触发rerenderCount: {state.count}// dispatch 用来接收一个 action参数「reducer中的action」,用来触发reducer函数,更新最新的状态<button onClick={() => dispatch({type: 'increment'})}>+</button><button onClick={() => dispatch({type: 'decrement'})}>-</button></>);
}
了解了useReducer基本使用方法后,看看如何使用useReducer改造上面的login demo:
const initState = {name: '',pwd: '',isLoading: false,error: '',isLoggedIn: false,
}
function loginReducer(state, action) {switch(action.type) {case 'login':return {...state,isLoading: true,error: '',}case 'success':return {...state,isLoggedIn: true,isLoading: false,}case 'error':return {...state,error: action.payload.error,name: '',pwd: '',isLoading: false,}default: return state;}
}
function LoginPage() {const [state, dispatch] = useReducer(loginReducer, initState);const { name, pwd, isLoading, error, isLoggedIn } = state;const login = (event) => {event.preventDefault();dispatch({ type: 'login' });login({ name, pwd }).then(() => {dispatch({ type: 'success' });}).catch((error) => {dispatch({type: 'error'payload: { error: error.message }});});}return ( // 返回页面JSX Element)
}
乍一看useReducer改造后的代码反而更长了,但很明显第二版有更好的可读性,我们也能更清晰的了解state的变化逻辑。
可以看到login函数现在更清晰的表达了用户的意图,开始登录login、登录success、登录error。LoginPage不需要关心如何处理这几种行为,那是loginReducer需要关心的,表现和业务分离。
另一个好处是所有的state处理都集中到了一起,使得我们对state的变化更有掌控力,同时也更容易复用state逻辑变化代码,比如在其他函数中也需要触发登录error状态,只需要dispatch({ type: ‘error’ })。
useReducer可以让我们将what和how分开。比如点击了登录按钮,我们要做的就是发起登陆操作dispatch({ type: ‘login’ }),点击退出按钮就发起退出操作dispatch({ type: ‘logout’ }),所有和how相关的代码都在reducer中维护,组件中只需要思考What,让我们的代码可以像用户的行为一样,更加清晰。
除此之外还有一个好处,我们在前文提过Reducer其实一个UI无关的纯函数,useReducer的方案是的我们更容易构建自动化测试用例。
总结
最后我们总结一下这篇文章的一些主要内容:使用reducer的场景
如果你的state是一个数组或者对象
如果你的state变化很复杂,经常一个操作需要修改很多state
如果你希望构建自动化测试用例来保证程序的稳定性
如果你需要在深层子组件里面去修改一些状态(关于这点我们下篇文章会详细介绍)
如果你用应用程序比较大,希望UI和业务能够分开维护
这篇文章我们介绍了使用useReducer,帮助我们集中式的处理复杂的state管理。但如果我们的页面很复杂,拆分成了多层多个组件,我们如果在子组件触发这些state变化呢,比如在LoginButton触发登录操作? 我们将在下篇文章介绍如何处理复杂组件树结构的reducer共享问题。
react 中的userReducer相关推荐
- 处理 react_【学习教程】React 中阻止事件冒泡的问题
来源 | https://www.cnblogs.com/Wayou/p/react_event_issue.html 在正式开始前,先来看看 js 中事件的触发与事件处理器的执行. js 中事件的监 ...
- react中ref的使用
在react中获取真实dom的时候就需要用到ref属性,具体使用如下 var MyComponent = React.createClass({handleClick: function() {con ...
- react中使用构建缓存_如何在React中构建热图
react中使用构建缓存 Heat maps are a great way of visualizing correlations among two data sets. With colors ...
- react中使用构建缓存_通过构建海滩度假胜地网站,了解如何使用React,Contentful和Netlify...
react中使用构建缓存 In this full course from John Smilga you will learn React by building a beach resort we ...
- 创建react应用程序_通过创建食谱应用程序来学习在React中使用API
创建react应用程序 Learn how to use external APIs with React and React Router in a full tutorial from Hamza ...
- react中纯函数_如何在纯React中创建电子邮件芯片
react中纯函数 by Andreas Remdt 由Andreas Remdt 如何在纯React中创建电子邮件芯片 (How to create email chips in pure Reac ...
- 如何在React中使用Typescript
TypeScript can be very helpful to React developers. TypeScript对React开发人员可能非常有帮助. In this video, Ben ...
- react中使用scss_我如何将CSS模块和SCSS集成到我的React应用程序中
react中使用scss by Max Goh 由Max Goh 我如何将CSS模块和SCSS集成到我的React应用程序中 (How I integrated CSS Modules with SC ...
- React 中动态的加载组件 ---loadable-components
loadable-components 用于在react 中动态的加载组件 安装方法: npm i loadable-components 使用: 引入: 代码中使用: 希望对你有所帮助
- boost::unorder_map如何插入元素_「React」如何在React中优雅的实现动画
最简单的动画组件实现 动画的本质,无非就是一个状态样式到另一个状态样式的过渡.最简单的动画组件,我们只需要指定两个状态的样式(进入的样式,离开的样式),以及一个开关(控制状态),即可完成. codep ...
最新文章
- c++中把一个函数中的语句复制到另一个语句中报错_从底层看前端(十一)—— JavaScript语法:脚本,模块和函数体。...
- java 输入 方程,用java 编写一程序,求解一元二次方程:aX2+bX+c=0.参数a、b及c从命令行做参数输入 java...
- CentOS 7 安装配置 NFS
- learnpython_LearnPython_week1
- 微服务中为什么需要服务发现?
- redis的scan命令的源码分析,实现原理
- 第四十期:九个对Web开发者最有用的Python包,掌握这些,工资至少能涨涨
- windows写文件到ubuntu之samba
- vue划入划出事件_基于vue中对鼠标划过事件的处理方式详解
- 华为鸿蒙os正在国外小规模测试,华为鸿蒙OS正小规模测试
- 图解红黑树和JAVA实现
- React 事件处理函数
- 组了个视频号的局,汇报下数据!
- 屏幕分辨率修改工具SwitchResX for Mac
- 【侯捷】C++内存管理机制
- python爬虫爬当当网_python爬取当当网图书排行榜
- 番茄社区门店系统新增跑腿和空码功能
- 投射数据卷Secret、ConfigMap、DownwardAPI
- Compiz Fusion 安装后的设置
- 国产手机已经用上了 120W 快充技术,苹果还在用20W的原因一
热门文章
- 如何将wav文件切成多个子文件
- 支付宝转账提现相关问题
- HLK 微软驱动签名过程中踩过的坑
- DDoS 报告攻击类型占比
- 出口退税解决方案丨批量开具出口发票+出口单证归集管理+退税数据一键报送
- 坚果云 不在计算机显示图标,在Ubuntu18.04系统顶栏不显示坚果云图标的解决办法...
- CentOS 识别NTFS格式U盘
- html表单站内搜,网站集成百度、Bing必应搜索引擎,在网页中实现站内全文搜索...
- 第三周项目4 穷举法
- 显示一个立方体的一点透视投影图;(用数组存放正方体的各顶点坐标)。