useReducer-基础概念篇html
useReducer-配合useContext使用react
useReducer
是React提供的一个高级Hook,它不像useEffect、useState、useRef等必须hook同样,没有它咱们也能够正常完成需求的开发,但useReducer可使咱们的代码具备更好的可读性、可维护性、可预测性。git
下面咱们会分三篇文章详细介绍如何在项目中使用useReducer
:github
reducer
的概念以及它的特色,对reducer、redux等比较熟悉的小伙伴能够跳过本篇useReducer
的使用方式和它的场景,以及useReducer带来的好处reducer
的概念是伴随着Redux的出现逐渐在JavaScript中流行起来。但咱们并不须要学习Redux去了解Reducer。简单来讲 reducer是一个函数(state, action) => newState
:接收当前应用的state和触发的动做action,计算并返回最新的state。下面是一段伪代码:redux
// 举个栗子 计算器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。app
function countReducer(count, action) {
switch(action.type) {
case 'add':
return count + 1;
case 'sub':
return count - 1;
default:
return count;
}
}
复制代码
从上面的示例能够看到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
是当前应用状态对象,能够理解就是咱们熟知的React里面的state。post
在上面的例子中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库解决。
咱们上文提到过reducer须要保持幂等性,更加可预测、可测试。若是每次返回同一个state,就没法保证不管执行多少次都是相同的结果
React在比较oldState
和newState
的时候是使用Object.is函数,若是是同一个对象则不会出发组件的rerender。 能够参考官方文档bailing-out-of-a-dispatch。
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的一个纯函数,具备一下几个特色:
下篇文章咱们会进入正题:如何使用useReducer简化咱们的state管理。
最后惯例,欢迎你们star咱们的人人贷大前端团队博客,全部的文章还会同步更新到知乎专栏 和 掘金帐号,咱们每周都会分享几篇高质量的大前端技术文章。若是你喜欢这篇文章,但愿能动动小手给个赞。