基于Hook的React状态管理系列-基础篇
栏目: JavaScript · 发布时间: 5年前
内容简介:下面我们会分三篇文章详细介绍如何在项目中使用
useReducer
是React提供的一个高级Hook,它不像useEffect、useState、useRef等必须hook一样,没有它我们也可以正常完成需求的开发,但useReducer可以使我们的代码具有更好的可读性、可维护性、可预测性。
下面我们会分三篇文章详细介绍如何在项目中使用 useReducer
:
reducer useReducer
什么是reducer
reducer
的概念是伴随着Redux的出现逐渐在JavaScript中流行起来。但我们并不需要学习Redux去了解Reducer。简单来说 reducer是一个函数 (state, action) => newState
:接收当前应用的state和触发的动作action,计算并返回最新的state。下面是一段伪代码:
// 举个栗子 计算器reducer,根据state(当前状态)和action(触发的动作加、减)参数,计算返回newState function countReducer(state, action) { switch(action.type) { case 'add': return state + 1; case 'sub': return state - 1; default: return state; } } 复制代码
上面例子:state是一个number类型的数值,reducer根据action的类型(加、减)对应的修改state,并返回最终的state。为了刚接触到 reducer
概念的小伙伴更容易理解,可以将state改为count,但请始终牢记count仍然是 state
。
function countReducer(count, action) { switch(action.type) { case 'add': return count + 1; case 'sub': return count - 1; default: return count; } } 复制代码
reducer 的幂等性
从上面的示例可以看到 reducer
本质是一个纯函数,没有任何UI和副作用。这意味着相同的输入(state、action),reducer函数无论执行多少遍始终会返回相同的输出(newState)。因此通过reducer函数很容易推测state的变化,并且也更加容易单元测试。
expect(countReducer(1, { type: 'add' })).equal(2); // 成功 expect(countReducer(1, { type: 'add' })).equal(2); // 成功 expect(countReducer(1, { type: 'sub' })).equal(0); // 成功 复制代码
state 和 newState 的理解
state
是当前应用状态对象,可以理解就是我们熟知的React里面的state。
在上面的例子中state是一个基础数据类型,但很多时候state可能会是一个复杂的JavaScript对象,如上例中count有可能只是 state中的一个属性。针对这种场景我们可以使用ES6的结构赋值:
// 返回一个 newState (newObject) function countReducer(state, action) { switch(action.type) { case 'add': return { ...state, count: state.count + 1; } case 'sub': return { ...state, count: state.count - 1; } default: return count; } } 复制代码
关于上面这段代码有两个重要的点需要我们记住:
-
reducer处理的state对象必须是
immutable
,这意味着永远不要直接修改参数中的state对象,reducer函数应该每次都返回一个新的state object -
既然reducer要求每次都返回一个新的对象,我们可以使用ES6中的解构赋值方式去创建一个新对象,并复写我们需要改变的state属性,如上例。
看上去很完美,但如果我们的state是多层嵌套,解构赋值实现就非常复杂:
function bookReducer(state, action) { switch(action.type) { // 添加一本书 case 'addBook': return { ...state, books: { ...state.books, [bookId]: book, } }; case 'sub': // .... default: return state; } } 复制代码
对于这种复杂state的场景推荐使用 immer 等immutable库解决。
state为什么需要immutable?
- reducer的幂等性
我们上文提到过reducer需要保持幂等性,更加可预测、可测试。如果每次返回同一个state,就无法保证无论执行多少次都是相同的结果
- React中的state比较方案
React在比较 oldState
和 newState
的时候是使用Object.is函数,如果是同一个对象则不会出发组件的rerender。
可以参考官方文档 bailing-out-of-a-dispatch
。
action 理解
action:用来表示触发的行为。
- 用type来表示具体的行为类型(登录、登出、添加用户、删除用户等)
- 用payload携带的数据(如增加书籍,可以携带具体的book信息),我们用上面addBook的action为例:
const action = { type: 'addBook', payload: { book: { bookId, bookName, author, } } } function bookReducer(state, action) { switch(action.type) { // 添加一本书 case 'addBook': const { book } = action.payload; return { ...state, books: { ...state.books, [book.bookId]: book, } }; case 'sub': // .... default: return state; } } 复制代码
总结
至此基本介绍完了reducer相关的内容,简单总结一下: reducer
是一个利用 action
提供的信息,将 state
从A转换到B的一个纯函数,具有一下几个特点:
- 语法:(state, action) => newState
- Immutable:每次都返回一个newState, 永远不要直接修改state对象
-
Action:一个常规的Action对象通常有type和payload(可选)组成
- type: 本次操作的类型,也是 reducer 条件判断的依据
- payload: 提供操作附带的数据信息
下篇文章我们会进入正题:如何使用useReducer简化我们的state管理。
最后惯例,欢迎大家star我们的 人人贷大前端团队博客 ,所有的文章还会同步更新到知乎专栏 和掘金账号,我们每周都会分享几篇高质量的大前端技术文章。如果你喜欢这篇文章,希望能动动小手给个赞。
以上所述就是小编给大家介绍的《基于Hook的React状态管理系列-基础篇》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- javascript – 有可能使用angularJs将状态从状态传递到状态吗?
- 前端状态管理与有限状态机
- 如何可视化需求状态和团队状态?
- 给 DSL 开个脑洞:无状态的状态机
- 基于有限状态机的广告状态管理方案及实现
- 基于有限状态机的广告状态管理方案及实现
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。