对useReducer的理解

本文详细介绍了React中的useReducer Hook及reducer的概念,解释了reducer如何帮助提高代码的可读性和可维护性,并通过实例展示了reducer的幂等性、state管理以及action的应用。
摘要由CSDN通过智能技术生成

useReducer是React提供的一个高级Hook,它不像useEffect、useState、useRef等必须hook一样,没有它我们也可以正常完成需求的开发,但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;
        }
    }

关于上面这段代码有两个重要的点需要我们记住:

  1. reducer处理的state对象必须是immutable,这意味着永远不要直接修改参数中的state对象,reducer函数应该每次都返回一个新的state object
  2. 既然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在比较oldStatenewState的时候是使用Object.is函数,如果是同一个对象则不会出发组件的rerender。 可以参考官方文档bailing-out-of-a-dispatch

action 理解

action:用来表示触发的行为。

  1. 用type来表示具体的行为类型(登录、登出、添加用户、删除用户等)
  2. 用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: 提供操作附带的数据信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北海屿鹿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值