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相关推荐

  1. 处理 react_【学习教程】React 中阻止事件冒泡的问题

    来源 | https://www.cnblogs.com/Wayou/p/react_event_issue.html 在正式开始前,先来看看 js 中事件的触发与事件处理器的执行. js 中事件的监 ...

  2. react中ref的使用

    在react中获取真实dom的时候就需要用到ref属性,具体使用如下 var MyComponent = React.createClass({handleClick: function() {con ...

  3. react中使用构建缓存_如何在React中构建热图

    react中使用构建缓存 Heat maps are a great way of visualizing correlations among two data sets.  With colors ...

  4. react中使用构建缓存_通过构建海滩度假胜地网站,了解如何使用React,Contentful和Netlify...

    react中使用构建缓存 In this full course from John Smilga you will learn React by building a beach resort we ...

  5. 创建react应用程序_通过创建食谱应用程序来学习在React中使用API

    创建react应用程序 Learn how to use external APIs with React and React Router in a full tutorial from Hamza ...

  6. react中纯函数_如何在纯React中创建电子邮件芯片

    react中纯函数 by Andreas Remdt 由Andreas Remdt 如何在纯React中创建电子邮件芯片 (How to create email chips in pure Reac ...

  7. 如何在React中使用Typescript

    TypeScript can be very helpful to React developers. TypeScript对React开发人员可能非常有帮助. In this video, Ben ...

  8. react中使用scss_我如何将CSS模块和SCSS集成到我的React应用程序中

    react中使用scss by Max Goh 由Max Goh 我如何将CSS模块和SCSS集成到我的React应用程序中 (How I integrated CSS Modules with SC ...

  9. React 中动态的加载组件 ---loadable-components

    loadable-components 用于在react 中动态的加载组件 安装方法: npm i loadable-components 使用: 引入: 代码中使用: 希望对你有所帮助

  10. boost::unorder_map如何插入元素_「React」如何在React中优雅的实现动画

    最简单的动画组件实现 动画的本质,无非就是一个状态样式到另一个状态样式的过渡.最简单的动画组件,我们只需要指定两个状态的样式(进入的样式,离开的样式),以及一个开关(控制状态),即可完成. codep ...

最新文章

  1. c++中把一个函数中的语句复制到另一个语句中报错_从底层看前端(十一)—— JavaScript语法:脚本,模块和函数体。...
  2. java 输入 方程,用java 编写一程序,求解一元二次方程:aX2+bX+c=0.参数a、b及c从命令行做参数输入 java...
  3. CentOS 7 安装配置 NFS
  4. learnpython_LearnPython_week1
  5. 微服务中为什么需要服务发现?
  6. redis的scan命令的源码分析,实现原理
  7. 第四十期:九个对Web开发者最有用的Python包,掌握这些,工资至少能涨涨
  8. windows写文件到ubuntu之samba
  9. vue划入划出事件_基于vue中对鼠标划过事件的处理方式详解
  10. 华为鸿蒙os正在国外小规模测试,华为鸿蒙OS正小规模测试
  11. 图解红黑树和JAVA实现
  12. React 事件处理函数
  13. 组了个视频号的局,汇报下数据!
  14. 屏幕分辨率修改工具SwitchResX for Mac
  15. 【侯捷】C++内存管理机制
  16. python爬虫爬当当网_python爬取当当网图书排行榜
  17. 番茄社区门店系统新增跑腿和空码功能
  18. 投射数据卷Secret、ConfigMap、DownwardAPI
  19. Compiz Fusion 安装后的设置
  20. 国产手机已经用上了 120W 快充技术,苹果还在用20W的原因一

热门文章

  1. 如何将wav文件切成多个子文件
  2. 支付宝转账提现相关问题
  3. HLK 微软驱动签名过程中踩过的坑
  4. DDoS 报告攻击类型占比
  5. 出口退税解决方案丨批量开具出口发票+出口单证归集管理+退税数据一键报送
  6. 坚果云 不在计算机显示图标,在Ubuntu18.04系统顶栏不显示坚果云图标的解决办法...
  7. CentOS 识别NTFS格式U盘
  8. html表单站内搜,网站集成百度、Bing必应搜索引擎,在网页中实现站内全文搜索...
  9. 第三周项目4 穷举法
  10. 显示一个立方体的一点透视投影图;(用数组存放正方体的各顶点坐标)。