对于 redux 的一些理解-1.基础

最近从 https://github.com/frontend9 上看了下博主对 redux 学习过程的一个分享 , 讲解的非常仔细易懂 , 感兴趣的建议从博主的 https://github.com/brickspert/blog/issues/22 案例中去逐个学习理解(动手敲) , 相信一定能够对 redux的使用有个彻底的理解;

 

我们从中文文档中可以看到这样的话:

 

'随着 JavaScript 单页应用开发日趋复杂,JavaScript 需要管理比任何时候都要多的 state (状态)。 这些 state 可能包括服务器响应、缓存数据、本地生成尚未持久化到服务器的数据,也包括 UI 状态,如激活的路由,被选中的标签,是否显示加载动效或者分页器等等'

Redux 试图让 state 的变化变得可预测。这些限制条件反映在了 redux 的三大原则中

1:单一数据源

2:state 是只读的

3:使用纯函数来执行修改

 

假设你从来没有用过 redux, 抛弃这些名词, 回到原始的开发模式。使用 ajax 从服务器请求数据, 根据数据生成 html片段, 插入到指定的 dom节点。逻辑很简单根本就不需要使用框架, 就可以获得很好的开发和浏览体验。

当单页面模式推崇之后 , 所有的操作都在一个 html文件中去处理, 情况变得复杂起来了。在一个页面中你需要处理各个模块的逻辑 , 你要不断去处理数据的更新, 添加, 删除; 这时候如果不对数据修改加以约束(随处可见的修改, 跨页面的修改等), 会难以追踪到你的数据走向。

尤其是对于引用类型数据, 对某一处不经意的修改, 简直会让人崩溃(你不知道到底在哪里作了修改, 可能就发生在某一个函数的调用中, 比如对形参 param.a = 1 这种操作)。

这时候也有人推出了深复制的解决办法, 每次都是操作一个全新的对象, 对源数据不会造成任何影响, 思路当然没错. 可这距离我们期望的结果: 对于数据的每一次修改都是可监测可控制的。还是有些差距。

 

Redux 的推出可谓是一种很好的解决方案。正如 redux文档自述中所言: Redux 是 JavaScript 状态容器,提供可预测化的状态管理

正因为它坚持的三大原则

1. 单一数据源; 避免了我们在各个模块中去重复复制, 重复定义, 这对于整个应用的数据更新都会带来麻烦; 要么只在模块内部去定义, 要么定义在全局(单一数据源上), 不推荐在内部定义一个, 在全局又定义一个同一用途的数据;

2. state 是只读的, redux提供了唯一改变 state 的方法就是触发 action; 它们只能表达想要修改的意图,

3. 使用纯函数来执行修改;

  我们来看一看执行修改的逻辑就明白了:

function changeCount(state={}, action){
    switch(action.type) {
        case 'INCREMENT':
            return {
                ...state,
                count: state.count + 1
            }
        default:
            return state
    }   
}

我们对原状态 state 没有做任何修改, 只是返回了一个新的 state; 借由此, 在处理逻辑时, 我们可以把应用上一次的 state, 和更新后的 state 都传递出去; 甚至我们可以改写里面的逻辑, 记录下前几次状态值的修改;

始终记住 redux提供可预测化的状态管理, 这就是它所做的工作。

 

 

/***********************    *************************************/

在以前自己去记录应用状态的做法可能是这样的;

function createStore (initData) {
    var APP_DATA = initData || {};

return { get: function (key) { return key ? APP_DATA[key] : APP_DATA; }, set: function (key, data) { APP_DATA[key] = data; } } } var Store = createStore(); function getUserInfo () { setTimeout(function () { var userInfo = { name: '张三', age: '23' }; Store.set('userInfo', userInfo); }, 100) } getUserInfo(); function validate () { return !!Store.get('userInfo'); } function submit () { var userInfo; if (validate()) { userInfo = Store.get('userInfo'); console.log(userInfo); } } setTimeout(submit, 300);

 

换作用 redux 可能得这样

function createStore (reducer, initState) {
    var listeners = [];
    var store = initState;
    
    function getState () {
        return store;
    }
    
    function subscribe (listen) {
        listeners.push(listen)
    }
    
    function dispatch (action) {
        store = reducer(store, action);
        for(var i = 0; i < listeners.length; i++) {
            listeners[i]()
        }
    }
    
    return {
        getState: getState,
        subscribe: subscribe,
        dispatch: dispatch
    }
}

function reducer (state, action) {
    switch (action.type) {
        case 'SET_USERINFO':
            return {
                ...state,
                userInfo: action.data
            }
        default:
            return state;
    }
}

var Store = createStore(reducer, {});

function getUserInfo () {
    setTimeout(function () {
        Store.dispatch({
            type: 'SET_USERINFO',
            data: { name: '张三', age: '23' }
        });
    }, 100)
}
getUserInfo();

function validate () {
    return !!Store.getState().userInfo;
}

function submit () {
    var userInfo;
    if (validate()) {
        userInfo = Store.getState().userInfo;
        
        console.log(userInfo);
    }
}

setTimeout(submit, 300);

应该用什么样的方式去管理应用状态 , 这个问题或许太宽泛无法回答 , 我只能说踩过的一些坑 , 也是对之前的"错误做法"一些总结:

1. 赋值操作时要格外小心 , 尤其是引用; 

2. 避免兀余的数据 , 这时我们常常会定义些 "全局变量" , 来保存多个位置的相同信息。尽量去约束修改的行为

3. 保护好你的应用数据 。不得已 可以通过重置的手段还原到初始状态。

 

 

/***********************  补充  *************************************/

对于 redux 自己也存在些疑惑的地方 , 在下面暂且把它视作 redux 的缺陷吧

1. redux 的 action 分发机制: 在源码中 action 被自顶往下层层传递 , 也就意味所有的下级状态都会接受到消息 , 那也就可能存在 有多个下级状态 同时做出响应 ---- 只要 action.type 不是唯一, 那么就必然会出现这种情况

  这一点可以被利用来做一些特定场景 , 但糟糕的设想是: 一个应用中有 未知数相同的 action.type, 在某一处的修改触发了所有状态的修改 ;

  理想状况下 , 我们应该只修改当前状态的值 , 而不应扩宽它的影响范围 , 因此称它为缺陷。 我们在开发中应该尽量对 action.type 命名唯一。

 

posted @ 2019-07-04 13:23  芋头圆  阅读(228)  评论(0编辑  收藏  举报