Redux 学习笔记02——Redux 的基本元素

328 阅读6分钟

Redux 的基本元素

想要使用Redux,必须要掌握其中的几个必要元素:Store、State、Action、Reducer。下面我们会依次介绍这几个元素:

我们还是以上一篇博客中提到的图书馆的例子作为基础:一个图书馆中有很多书,图书馆有管理员,我们如果想要找书的时候,可以询问管理员书的具体位置,方便我们快速拿到这本书;我们想要借书或还书的时候,可以将书交给管理员,并且初始自己的借书卡,让管理员帮助我们准确地登记,并将归还的书放在准确地位置上。

大致明白了图书馆的例子,我们开始介绍Redux的这几个基本的元素。

Redux 元素的详细介绍

这一节我们重点是介绍Redux,让大家对Redux有一个形象的认识。如果你对出现的代码不理解的话,先不要纠结,明白各个元素是怎么会是就行了。下一节我们会详细讲解Redux的使用,那里会对代码详细说明。

1. Store

Store 就是保存数据的地方,你可以把它看成一个容器,整个应用只能有一个 Store。Redux 提供createStore这个函数,用来生成 Store。

import { createStore } from 'redux';
const store = createStore(fn);

在图书馆的例子中,整个图书馆就是一个 Store, 里面存放着大量的书籍。

2. State

Store对象包含所有数据。如果想得到某个时刻的数据,就要对 Store 生成快照。这种时刻的数据集合,就叫做 State。

当前时刻的全部 State,可以通过store.getState()拿到。

import { createStore } from 'redux';
const store = createStore(fn);

const state = store.getState();

在图书馆的例子中,图书馆中某一时刻的书籍情况,对应的就是图书馆这一时刻的State。其实这里我们完全可以把State翻译成 状态, 这更便于我们理解。

比如我说:2019年下午14:00的时候,图书馆的状态。那么你就会很清楚地知道我表达地意思是:在2019年下午14:00,图书馆有多少本书籍在馆,在馆的书籍都是放在哪个位置;有多少本书籍已经借出,借出的书籍在哪些人手中等等。

再来看实际项目中的State,Redux管理的数据很多,而且这些数据会发生变化。如果我们想在一个组件渲染的时候,拿到Redux中当前的数据显示在页面上,那么我们就可以使用 store.getState() 获取这个时刻的数据,然后在组件中进行数据的渲染。在另外一个时刻,数据发生了变化,如果我们再次使用 store.getState() 获取数据渲染组件,那么就会得到不同的页面。

Redux 规定, 一个 State 对应一个 View。只要 State 相同,View 就相同。你知道 State,就知道 View 是什么样,反之亦然。

3. Action

State 的变化,会导致 View 的变化。但是,用户接触不到 State,只能接触到 View。所以,State 的变化必须是 View 导致的。Action 就是 View 发出的通知,表示 State 应该要发生变化了。

Action 是一个对象。其中的type属性是必须的,表示 Action 的名称。其他属性可以自由设置,社区有一个规范可以参考。

const action = {
    type: 'borrow_book',
    title: '《明朝那些事儿》'
};

上面代码中,Action 的名称是borrow_book,它携带的信息是字符串《明朝那些事》

可以这样理解,Action 描述当前发生的事情。改变 State 的唯一办法,就是使用 Action。它会运送数据到 Store,然后Store会通过一系列方式对数据进行改变。

回到图书馆的例子中:在图书馆中,我们作为读者没有权限获取和修改图书馆的数据,只能将我们的请求告诉图书馆,然后图书馆中的管理员就会来获取或者修改图书馆的数据,然后告诉我们。

比如我们发出一个请求:我要找书,我要找的书是《明朝那些事儿》,那么图书馆的管理员会很明确地知道我们的意图,然后告诉我们这本书在哪里,你就可以拿到这本书。

拿到这本书之后,你觉得还不错,想借回家慢慢阅读,你可以在发出一个请求:我要借书,我借的这本书是《明朝那些事儿》,我借书卡的卡号是20152135。图书馆管理员又会很明确地知道你的意图,然后再图书馆地登记薄上记上你借走了这本书,然后这一时刻,图书馆的书籍数量会减少一本。

在上面的例子中,你发出的请求对应的就是Redux中的Action,具体的对应关系如下所示:

// 我要找书,我要找的书是《明朝那些事儿》
const action_1 = {
    type: 'search book',
    title: '《明朝那些事儿》'
};

// 我要借书,我借的这本书是《明朝那些事儿》,我借书卡的卡号是20152135
const action_2 = {
    type: 'borrow book',
    title: '《明朝那些事儿》',
    myId: '20152135'
};

4. Reducer

Store 收到 Action 以后,必须给出一个新的 State,这样 View 才会发生变化。这种 State 的计算过程就叫做 Reducer。

Reducer 是一个函数,它接受 Action 和当前 State 作为参数,返回一个新的 State。

const reducer = function (state, action) {
    // ...
    return new_state;
};

回到图书馆地例子中:前面提到过,当我们在图书馆发出找书请求之后,是图书馆管理员帮助我们找到书籍的具体位置;在我们发出借书请求之后,是图书馆管理员帮助我们修改借阅记录。所以在图书馆的例子中,Reducer就是这位辛劳的图书馆管理员,也只有他才有去那先修改图书馆中的数据。

现在想象一下这个场景:你想借阅《明朝那些事儿》,在此之前你可能已经借了其他的书籍,所以图书馆管理员在帮你借阅书籍之后,会告诉你:你现在已经借了哪些书籍,也就是说管理员会返回给你,当前图书馆中你的借阅记录State。

结合这个场景我们可以给出Reducer的具体定义实例,现在看不懂没关系,只要理解Reducer是什么角色,有什么作用就行了。后面会对Reducer做详细的介绍。

// 你发出的action
const action_2 = {
    type: 'borrow book',
    title: '明朝那些事儿',
    myId: '20152135'
};

// 定义你借书之前,图书馆的State
const previousState = {
    allBooks: ["明朝那些事儿", "百年孤独", "盗墓笔记", "红楼梦", "西游记", "三国演义"],	// 在你借书前,图书馆所有藏书
    outBooks: {	// 图书馆的借阅记录
        "20152008": ["法医清明"],// 其他人的借阅书籍
        "20152135": ["水浒传", "鲁迅文集"]		// 你的借阅书籍
    }
}

// reducer的具体定义
const reducer = (state = previousState, action) => {
    if(action.type === "borrow book") {
        let bookIndex = state.allBooks.indexOf(action.title);
        state.allBooks.splice(bookIndex, 1);	// 删除你要借阅的书籍
        outBooks[action.myId].puhs(action.title);	// 把你借阅的书籍添加到你的借阅记录里面
        
        return state;		// 一定要把处理后的state返回
    }
    return state;
}

写在最后

这一篇博客中,以图书馆为例子给大家介绍了Redux中最基本也是最重要的几个元素,了解这几个元素之后,在下篇博客中,给大家介绍如何在React项目中使用Redux。