资讯专栏INFORMATION COLUMN

React学习之Redux高阶运用

supernavy / 2059人阅读

摘要:增强除了解决复用问题,高阶的另一个重要作用就是对原始的进行增强。就是典型的利用高阶来增强的例子,它主要作用是使任意变成可以执行撤销和重做的全新。

在Redux架构中,reducer是一个纯函数,它的职责是根据previousState和action计算出新的state。在复杂应用中,Redux提供的combineReducers让我们可以把顶层的reducer拆分成多个小的reducer,分别独立地操作state树的不同部分。而在一个应用中,很多小粒度的reducer往往有很多重复的逻辑,那么对于这些reducer,如何抽取公共逻辑,减少代码冗余呢?这种情况下,使用高阶reducer是一种较好的解决方案

reducer复用

我们将顶层的reduce拆分成多个小的reducer,肯定会碰到reducer复用问题。例如有A和B两个模块,它们的UI部分相似,此时可以通过配置不同的props来区别它们。那么这种情况下,A和B模块能不能共用一个reducer呢?答案是否定的。我们先来看一个简单reducer:

const LOAD_DATA = "LOAD_DATA";
const initialState = { ... };

function loadData() {
    return {
        type: LOAD_DATA,
        ...
    };
}

function reducer(state = initialState, action) {
    switch(action.type) {
        case LOAD_DATA:
            return {
                ...state,
                data: action.payload
            };
        default:
            return state;
    }
}

如果我们将这个reducer绑定到A和B两个不同模块,造成的问题将会是,当A模块调用loadData来分发相应的action时,A和B的reducer都会处理这个action,然后A和B的内容就完全一致了。

这里我们必需意识到,在一个应用中,不同模块间的actionType必须是全局唯一的。

因此,要解决actionType唯一的问题,还有一个方法就是通过添加前缀的方式来做到:

function generateReducer(prefix, state) {
    const LOAD_DATA = prefix + "LOAD_DATA";
    
    const initialState = { ...state, ...};
    
    return function reducer(state = initialState, action) {
        switch(action.type) {
            case LOAD_DATA:
                return {
                    ...state,
                    data: action.payload
                };
            default:
                return state;
        }
    }
}

这样只要A和B模块分别调用generateReducer来生成相应的reducer,就能解决reducer复用的问题了。而对于prefix,我们可以根据自己的项目结构来决定,例如${页面名称}_${模块名称}。只要能够保证全局唯一性,就可以写成一种前缀。

reducer增强

除了解决复用问题,高阶reducer的另一个重要作用就是对原始的reducer进行增强。redux-undo就是典型的利用高阶reducer来增强reducer的例子,它主要作用是使任意reducer变成可以执行撤销和重做的全新reducer。我们来看看它的核心代码实现:

function undoable(reducer) {
    const initialState = {
        // 记录过去的state
        past: [],
        // 以一个空的action调用reducer来产生当前值的初始值
        present: reducer(undefined, {}),
        // 记录后续的state
        future: []
    };
    
    return function(state = initialState, action) {
        const { past, present, future } = state;
        
        switch(action.type) {
            case "@@redux-undo/UNDO":
                const previous = past[past.length - 1];
                const newPast = past.slice(0, past.length - 1);
                
                return {
                    past: newPast,
                    present: previous,
                    future: [ present, ...future ]
                };
            case "@@redux-undo/REDO":
                const next = future[0];
                const newFuture = future.slice(1);
                
                return {
                    past: [ ...past, present ],
                    present: next,
                    future: newFuture
                };
            default:
                // 将其他action委托给原始的reducer处理
                const newPresent = reducer(present, action);
                
                if(present === newPresent) {
                    return state;
                }
                
                return {
                    past: [ ...past, present ],
                    present: newPresent,
                    future: []
                };
        }
    };
}

有了这高阶reducer,就可以对任意一个reducer进行封装:

import { createStore } from "redux";

function todos(state = [], action) {
    switch(action.type) {
        case: "ADD_TODO":
        // ...
    }
}

const undoableTodos = undoable(todos);
const store = createStore(undoableTodos);

store.dispatch({
    type: "ADD_TODO",
    text: "Use Redux"
});

store.dispatch({
    type: "ADD_TODO",
    text: "Implement Undo"
});

store.dispatch({
    type: "@@redux-undo/UNDO"
});

查看高阶reducer undoable的实现代码可以发现,高阶reducer主要通过下面3点来增强reducer:
能够处理额外的action;
能够维护更多的state;
将不能处理的action委托给原始reducer处理。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/105567.html

相关文章

  • React习之漫谈React

    摘要:事件系统合成事件的绑定方式合成事件的实现机制事件委派和自动绑定。高阶组件如果已经理解高阶函数,那么理解高阶组件也很容易的。例如我们常见的方法等都是高阶函数。对测试群众来说,从质量保证的角度出发,单元测试覆盖率是 事件系统 合成事件的绑定方式 `Test` 合成事件的实现机制:事件委派和自动绑定。 React合成事件系统的委托机制,在合成事件内部仅仅是对最外层的容器进行了绑定,并且依赖...

    darkbug 评论0 收藏0
  • 【抢先领】《React 习之道》我们翻译了一本最简单,且最实用的 React 实战教程……

    摘要:学习之道简体中文版通往实战大师之旅掌握最简单,且最实用的教程。前言学习之道这本书使用路线图中的精华部分用于传授,并将其融入一个独具吸引力的真实世界的具体代码实现。完美展现了的优雅。膜拜的学习之道是必读的一本书。 《React 学习之道》The Road to learn React (简体中文版) 通往 React 实战大师之旅:掌握 React 最简单,且最实用的教程。 showIm...

    oneasp 评论0 收藏0
  • React习之深入Redux应用框架

    摘要:作为大型应用状态管理最常用的工具。它是一个应用数据流框架,与框架类似。这是触发变化的惟一途径。在这个函数内部,被调用,其作用是监测是的。否则的话,认为只是一个普通的,将通过也就是进一步分发。到此源码的主要部分学习结束。 Redux作为大型React应用状态管理最常用的工具。它是一个应用数据流框架,与Flux框架类似。它是零依赖的,可以配合其他框架或者类库一起使用。虽然在平时的工作中很多...

    张汉庆 评论0 收藏0
  • React 328道最全面试题(持续更新)

    摘要:希望大家在这浮夸的前端圈里,保持冷静,坚持每天花分钟来学习与思考。 今天的React题没有太多的故事…… 半个月前出了248个Vue的知识点,受到很多朋友的关注,都强烈要求再出多些React相前的面试题,受到大家的邀请,我又找了20多个React的使用者,他们给出了328道React的面试题,由我整理好发给大家,同时发布在了前端面试每日3+1的React专题,希望对大家有所帮助,同时大...

    kumfo 评论0 收藏0
  • react进阶系列:高阶组件详解(三)

    摘要:在前端基础进阶八深入详解函数的柯里化一文中,我有分享柯里化相关的知识。虽然说高阶组件与柯里化都属于比较难以理解的知识点,但是他们组合在一起使用时并没有新增更多的难点。 可能看过我以前文章的同学应该会猜得到当我用New的方法来举例学习高阶组件时,接下来要分享的就是柯里化了。高阶组件与函数柯里化的运用是非常能够提高代码逼格的技巧,如果你有剩余的精力,完全可以花点时间学习一下。 在前端基础进...

    zhangxiangliang 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<