一二三步走,捋清Redux

274 阅读8分钟

首先抛出一个问题。Redux是什么?

百度百科给出的解释是:

Redux对于JavaScript应用而言是一个可预测状态的容器。换言之,它是一个应用数据流框架,而不是传统的像underscore.js或者AngularJs那样的库或者框架。

Redux官方给出的解释是

Redux 是 JavaScript 状态容器,提供可预测化的状态管理。可以让你构建一致化的应用,运行于不同的环境(客户端、服务器、原生应用),并且易于测试。不仅于此,它还提供 超爽的开发体验,比如有一个时间旅行调试器可以编辑后实时预览。

其实说的再多,最后还是一句话,就是负责将状态变得可控。

那么什么是状态呢,在React中State就是用来存储状态,而状态就是一些数据状态和配置参数。每个组件都可以拥有自己的状态,而这些变量的值会因为一些操作而改变,而这些改变又会引起其他组件的改变,而state已经不知道什么时候就脱离了你的控制,而Redux的出现拯救了万千前端工程师于状态迷失的水火之中。

阮一峰老师在介绍Redux时提到:

Redux 是一个有用的架构,但不是非用不可。事实上,大多数情况,你可以不用它,只用 React 就够了。

曾经有人说过这样一句话。

"如果你不知道是否需要 Redux,那就是不需要它。"

Redux 的创造者 Dan Abramov 又补充了一句。

"只有遇到 React 实在解决不了的问题,你才需要 Redux 。"

虽然说了那么多但是我们这篇文章的内容呢,是要捋清Redux中的内容,不能跑题啊!

下面开始介绍Redux

1.Redux三大原则

(1).单一数据源

官方解释:整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。 为了避免状态的混乱,所以在Redux中规定了整个应用的state只存在一棵对象树中,而这棵树只能存在一个Store中。对开发者来说,这样可以更加容易对数据进行调试,并且可以观察到数据的详细变化,在 树状结构中,也可以轻松实现“撤销/重做等以前不宜实现的功能

(2).State是只读的

官方解释:唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。 State是不能直接修改的,于React中的state和setState类似,如果需要修改State中的内容,需要先写一个action对象,通过调用这个action来表明你想要State中的内容进行修改的意图。并且State是不能够修改的,所以修改的实质是返回一个全新的State。

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

官方解释:为了描述 action 如何改变 state tree ,你需要编写 reducers。 Reducers负责根据你给他的action来对State进行操作。Reducers是一个纯函数,也就是一个不会产生副作用的函数,因此他最终返回的,是原来的状态,加上操作的内容产生的新的对象。

2.Redux实现的铺垫


Redux的实现可以讲成一个故事,在一个用玻璃墙围起来屋子里面有一个展示牌--State,所有人都可以看见,但是不能够直接修改展示牌上面的信息,但是不能修改也不行啊,于是找来了一个专门修改展示牌内容的工匠--reducer,只有他可以修改展示牌上面的State内容,但是State是只读的,所以每一次修改都需要工匠重新做一块牌子,将修改信息和原来信息刻在上面,然后展示出来。工匠是住在玻璃墙里面的,外面的人需要修改展示牌内容,但是没有办法进到墙里面去,所以修改意见没有办法传递给工匠。于是就产生了一个可以穿过玻璃墙和工匠传信的信使--action,他可以穿过玻璃墙,传递信息,外面想要修改展示内容的人,只需要将修改意见的暗号--type告诉信使,他便可以告诉工匠,工匠也就按照暗号将信息修改。故事讲完了,下面讲讲里面的知识点吧!


(1).展示牌--State:

在Redux第一,二条原则中说到,State存储在Object tree中,所以在Redux中,所有的State都被保存在一个单一的对象中,State是只读的,所以需要用const来声明

    //定义State
    const initState={
            todos:[
                {content:"HTML",complete:false},
                {content:"CSS",complete:true},
                {content:"JS",complete:false}
            ],
            visibility:"all"
        }

(2).信使--action:

action是一个对象,用来表明想要对State进行的操作。因为State被隔离了起来,所以想要操作State怎么办呢?只好找了一个信使-action,将想要进行的操作告诉信使,由他把操作传递给工匠reducer。action的结构比较简单,分为下面两个部分。

a.必需品

信使的作用就是传信,而这里的信就是type,所以,每个action必须有type的属性,并且是唯一的。

        const decrement = {
            type:"DECREMENT"
        }

b.高阶操作--action creators

初级信使只传递一个修改的type,而修改的方法是工匠已经规定好的,但是这样的规定往往不能满足人们的需求,于是就有了高级信使,他们不再是一个对象,变成了一个方法,他可以接收人们需要增加的其他功能,然后整合成一个初级信使模样即对象,也就是返回一个对象,而这个对象的功能就比初级的信使要厉害多了。

        function addTodo(text){
            return{
                type:"ADD_TODO",
                text
            }
        }

(3).工匠--reducer

reducer是一个纯函数,接收旧的状态和action,返回一个新状态。就行工匠一样,只需要原本的展示牌的内容和信使传递的修改意见,只要他能够识别暗号,就可以做出一个新的展示牌。

        function reducer(state=initState, action){
            switch(action.type){
                case "INCREMENT":
                    return {count:state.count+action.step}
                case "DECREMENT":
                    return {count:state.count-1}
                default:
                    return state;
            }
        }

但是有时候State tree过于庞大的时候,每一次操作的过程太复杂,这时候就产生了工匠联盟。

工匠联盟

所谓的工匠联盟是指将原本一个工匠的活,根据State内容分成几个部分,分别交给不同的工匠(reducer)来完成,每一次操作,工匠们只需要完成自己的部分即可,需要修改的进行修改,不需要修改的,将原本的内容复刻上去,产生一个新的展示牌。

        //定义 reducer
        function todos(state=[],action){
            switch(action.type){
                case "ADD_TODO":
                    return [...state,{content:action.text,complete:false}];
                case "TAGGLE_TODO":
                    return state.map(todo=>{
                        if(todo==action.todo){
                            return Object.assign({},todo,{complete:!todo.complete})
                        }
                        return todo;
                    })
                default:
                    return state;
            }
        }
        // 定义visibility的reducer
        function visibility(state="all",action){
            switch(action.type){
                case "SET_VISIBILITY":
                    return action.filter
                default:
                    return state
            }
        }
        const reducer = Redux.combineReducers({

3.Redux核心--store

Redux的核心是Store,那么Store是什么呢,可以说他就是刚才故事里的那个玻璃屋的管理者,他有三个能力,一个是得到展示栏的内容,一个是订阅展示牌改变,一个是派发改变展示栏信息的功能

(1)获取状态

虽然我们说是把Store比作了玻璃屋,但是在代码世界里面,没有所谓的视听说,所以要想获得展示牌的内容,就需要使用store提供的第一个能力--store.getState()。通过使用这个方法,就可以拿到展示牌的内容了。

        //取值
        console.log(store.getState());

(2)订阅信息

虽然使用第一个方法可以拿到展示牌的内容,但是拿到了的数据不会因为State的改变而改变,所以当其他人改变了展示牌上面的State,就需要重新获取,这无疑是不靠谱的方法,所以这个时候就需要使用Store的第二个能力--store.subscibe()来设置监听,一旦state发生变化,立即可以执行这个监听方法内部的函数。

        //订阅
        store.subscribe(()=>{
            console.log(store.getState());
        })

(3)派发任务

既然能够获取数据了,自然是可以改变的,信使进入玻璃墙就是使用的Store的第三个能力--store.dispatch(),在这个方法里,至少需要传递一个参数-action,就好比使用了这个方法,就在玻璃墙上面打开了一个通道,此时信使就可以通过这个通道,进入到了里面。

        // 通过dispatch派发一个action
        store.dispatch(addTodo("redux"));

通过三步的介绍,相信你已经初步了解了Redux的内容,接下来在玻璃墙这里还有许许多多的内容等待着我们,一步一个脚印的走,我们也一定能够穿过属于你的玻璃墙的,让我们一同加油