redux懒人教程

对于没有使用过redux的同窗,一来直接打开官网开始撸教程恐怕大多都对里面提到的各类概念一脸懵,而打开论坛上的各类野生教程又会发现,或许是由于redux的源码大概只有三百多行,所以论坛上写的比较优秀的教程都深刻到redux的源码中,须要你花时间理清redux的原理以后你才知道这东西要怎么用。所以我尝试在此写一篇懒人教程,但愿能经过比较通俗易懂的语言,以类比的方式向没有接触过redux的朋友解释一下它是干吗用的,具体要怎么用。java

下面开始个人表演。react

redux要解决什么问题

做为开发者,咱们在选择工具和库时,切忌"为了用而用",而应该清楚咱们要用的工具是用来解决什么问题的,在咱们的开发场景中是否会碰到这样的问题,用了这个工具后能不能帮咱们解决问题。搞清楚这些再去学习对应的工具和库,工具才能称之为工具,不然就变成了工具是开发者的主人了。所以,在学习redux以前,首先应该了解一下为何须要redux。 说起redux的时候,经常跟react联系在一块儿,可是其实redux并不是是为react定制的,首先要明确,redux只是一个架构模式,它要解决的是全局状态很差管理这个问题,你能够在任何有这样的问题的场景下使用它。咱们来看这样一个例子:redux

function showName(name) {
    console.log("user's name: ", name);
}

function showAge(age) {
    console.log("user's age: ", age);
}

window.user = {
    name: 'Bob',
    detail: {
        age: 11,
        gender: 'male'
    }
}

/* ......不少不少模块 */

showName(user.name);
showAge(user.detail.age);
复制代码

假设有这样一个变量user,它存储了一个用户的我的信息,这个信息可能在代码的不少模块中被读写,为了方便, 咱们把这个变量设置为全局变量。然而如今问题来了,这个user是一个在裸奔的变量,任何模块均可以轻易地修改它,假如我指望在showName的时候打印Bob,可是实际上却打印了undefined,那么在这"不少不少个模块中",到底是谁修改了user变量,你根本无法定位,其实这也是老生常谈的尽可能避免全局变量的缘由。然而矛盾在于,虽然我知道定义全局变量可能会带来混乱,可是有些变量确实须要被各类不一样的模块使用,我不得不把它定义成全局变量,在大型应用中,这样的全局变量可能还很多,并且数据结构还可能很是复杂。所以,在这样的场景下,咱们迫切须要一个数据的管理者制定好全局变量使用规范,帮咱们管理全局变量——而这就是redux作的事情。api

redux是怎么解决问题的

俗话说的好,在计算机领域,若是有什么问题是加一层中间层解决不了的,那就加两层。而redux就是这个中间层,再来回顾一下咱们面临的痛点:一个须要被全局共享的很是重要的变量(下文称之为状态),却能够被散落的模块肆意妄为地修改: 数组

如今为了改变这种局面,就必须有一个“我不要你以为,我要我以为”的霸道总裁一把接管对状态的读写权。

首先,乱世用重典,咱们须要先颁布一个《redux共和国状态管理条例》,之后你们谁要修改状态,都得写社会主义法治程序,按照条例规定好的操做来修改状态。在这部《条例》的开头,先昭告天下咱们要管理的状态(state)的初始值是什么,而后,咱们一条一条地列举针对这个状态,你能够进行哪些操做(action.type), 以及这个操做对状态的修改是什么。好比如今咱们须要管理一个数组,它的初始值是一个空数组,咱们规定对这个数组的合法操做有添加一个项,删除一个项和清空整个数组,按照刚才的思路,咱们用代码颁布一个《数组状态管理条例》:bash

const initState = [];
const reducer = (state = initState, action) => {
    switch(action.type) {
        case 'add':
            return [...state, action.addedItem];
        case 'delete':
            return [...state.slice(0, action.deletedIndex), ...state.slice(action.deletedIndex + 1)];
        case 'clear':
            return []
        default:
            return state;
    }
}
复制代码

好了,无需多言了吧,如今你已经知道redux中最重要的两个概念reducer和action是什么了,reducer正是咱们刚才说的《redux共和国状态管理条例》,而action则是条例里的细则。不过或许你已经发现,虽然咱们说在条例的细则中定义好了如何去修改状态, 可是,咱们并无真正地去"修改"状态。听起来彷佛有点绕,拿add这个操做为例,咱们并无用数据结构

...
switch(action.type) {
    case 'add':
        state.push(action.addedItem);
        return state;
    ...
}
复制代码

这种写法,而是架构

...
switch(action.type) {
    case 'add':
        return [...state, action.addedItem];
    ...
}
复制代码

把原数组拷贝了一遍,生成了一个新数组,而后在新数组的末尾添加了一个新的项,最后再把这个新的数组返回做为状态的最新值,也就是说,咱们不是直接去修改状态,而是根据旧状态,返回一个新状态。实际上,按照这种写法,咱们写出的reducer就是一个纯函数,所谓纯函数须要知足两个条件:app

  1. 纯函数返回的结果只取决于它的参数,而不取决于任何外部变量
  2. 纯函数内部不会去修改任何外部变量,也就是说,纯函数不会带来任何反作用

关于reducer为何要写成纯函数,我以为这是一个不得不结合redux源码单独写一篇文章分析的问题,可是既然都说是懒人教程,只但愿你会用,至于原理能够后面又深究,如今你能够暂且把它当作霸道总裁redux的一个奇怪的小癖好。异步

好了,咱们已经有《redux共和国状态管理条例》了,如今还缺一个条例的坚决执行者。因而咱们用createStore函数,传入咱们制定好的法律——reducer,它将返回一个执行法律的检察官——store。如今,对状态的读写都得通过store之手,要读取状态值,就调用store.getState(); 要修改状态,就得先学习一下法律知识,看看reducer中有哪些合法的action,而后调用store.dispatch(action)对状态进行修改; 同时, 你也能够订阅状态的改变,给store.subscribe传入一个回调函数,每一次状态改变时,都会执行一次这个回调函数——这是一个典型的观察者模式。

如今来看下面这段代码,能看懂的话说明你已经掌握redux的核心用法了, 看不懂的话能够再把刚才这个治乱世的过程再品一品

import { createStore } from 'redux';

const initState = [];
const reducer = (state = initState, action) => {
    switch(action.type) {
        case 'add':
            return [...state, action.addedItem];
        case 'delete':
            return [...state.slice(0, action.deletedIndex), ...state.slice(action.deletedIndex + 1)];
        case 'clear':
            return []
        default:
            return state;
    }
};

const store = createStore(reducer);

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

// 添加一个项
store.dispatch({
    type: 'add',
    addedItem: 1
});

// 又添加一个项
store.dispatch({
    type: 'add',
    addedItem: 2
});

删除一个项
// store.dispatch({
    type: 'delete',
    deletedIndex: 0
});

// 清空状态 
store.dispatch({
    type: 'clear'
})
复制代码

或许你已经发现,使用redux一点都不难,其核心思想无非就是制定规则(reducer)和遵照规则(store.dispatch)罢了。 在这个基础上,redux总裁还想再完善一下本身制定的这套机制,以应对更加复杂的状况。试想一下,若是这个redux共和国只有30个国民,可能尚未你高中的班级人多,那么颁布一部像大家班班规同样规模的《管理条例》就绰绰有余了,可是若是这个redux共和国像我泱泱华夏同样地大物博,你就得分别颁布《redux共和国刑法》,《redux共和国婚姻法》,《redux共和国未成年人保护法》.......最终这些法律才完整组成共和国的法律体系。回到程序世界,reudx提供了combineReducer这个api,容许你在管理大型应用的状态时,分别写一些小粒度的reducer,而后用这个api把它们组合成一个总reducer以后又传给createStore。

另外,不一样国家检察官执法时候的花式姿式都不太同样,例如美国警察抓犯人的时候都喜欢先说一句“你有权保持沉默,可是你说的每一句话都将成为呈堂证供”。或许你也但愿在每一次store.dispatch时能在控制台打印一句“xxx状态你有权保持沉默,可是你的值如今将从xxx被改变为xxx”,那么你能够把这个例行程序经过插件机制在createStore的时候告诉你的检察官,只须要使用redux提供的applyMiddleware这个api就行。社区里已经提供了各类这样的执法前的花式姿式插件,好比redux-thunk用于方便处理异步状态变动,redux-logger用于在状态变动时打印日志等。

总结

最后,把redux的使用方式用下面这张图总结一下

很好,如今咱们已经搞清楚如何用redux来把混乱的全局变量管理得层次分明的了,休息一下,或者直接进入下一篇文章 《react-redux懒人教程》咱们就来看看这个霸道总裁是怎么管理你的react帝国的。

相关文章
相关标签/搜索