React & Redux 入门教程 - 第四篇:引入 Redux

本文是《React & Redux 入门教程》系列文章的第四篇。在 React & Redux 入门教程 - 第一篇:React 术语浅析 中,我们学习了 React 的术语。在 React & Redux 入门教程 - 第二篇:从 jQuery 到 React 中,我们将一个传统的基于 jQuery 的项目迁移到了 React。在 React & Redux 入门教程 - 第三篇:Redux 术语浅析 中,我们学习了 Redux 的术语。

本篇是第二篇的后续:在一个 React 项目中引入 Redux。首先我们会回顾在第二篇中完成的 React 程序,然后我们会分析为什么以及什么时候需要用 Redux 来管理 state,最后我们会给出 Redux 版本的程序并分析其实现细节。

一个 React 程序

首先我们来回顾一下在第二篇的时候我们创建的 React 程序:

我们重点看一下 React 是如何管理 state 的。首先,在 component 的构造函数中,我们通过 this.state = { markdown: '' } 初始化了 state。其次,我们通过 {this.state.markdown} 来把 state 中的数据传递给 element。 最后,我们通过 onChange={(e) => this.setState({ markdown: e.target.value })} 来实现 state 的数据更新。

React state vs Redux state

我们之前的内容也有讲,React 仅仅是一个 View 的 library。如果 state 内容太多,变化太复杂,则要引入其它的 library 来协助管理 state。而 Redux 则是为管理 state 而生的, 它是 JS 程序中 state 的容器。所以当程序变得复杂,引入 Redux 来为 React 管理 state 是个非常好的选择。

这里有一个常见的误区:一旦引入了 Redux 来管理 state,React 就不需要自己管理 state 了吗? 答案是:要看情况。React state 和 Redux state 还是有明显的特点区别的:React 的 state 是局部的或临时的,不会有复杂的变化;Redux 的 state 是全局的,可能会有复杂的变化。即使了有了 Redux, 对于某些局部的临时的 state 信息,还是应该放在 React 中。

当然了,我们上面的例子由于太简单,state 中只有一种信息。这种非常简单的情况 state 用 React 来管理和用 Redux 来管理区别并不大。我们接下来为了体验 Redux,将会把 state 挪到 Redux 去管理。

Redux 版本的程序

我们通过注释和空白行将上面的代码分为了三部分,分别对应 React,Redux 和 Bind React and Redux。接下来我们依次分析三个部分。

React

对 React 的主要修改在于把 state 移除了。因为我们把 state 转移到 Redux 中去了。没有了 state,构造函数中就空了,于是把构造函数也移除了。整个 component 就只剩下 render 方法。

那么问题来了:在 state 被移除之前,我们通过 this.state.markdown 来使用 markdown 这个变量。现在 state 被移除了,但是 render 函数中还是需要使用 markdown 变量的,这个变量从哪里来呢?答案是从 props 中来。

我们在本系列教程的第一篇讲到了,React component 中有两种类型的数据,可变的变量放在 state 里面,不可变的常量放在 props 里。如果把 component 类比为 function,不可变的 props 就类似 function 的参数,可变的 state 就类似 function 内部声明的变量。现在既然 state 被移除了,那么所有的数据就只能通过 props 获取了。

对比加入 Redux 之前和之后的代码,我们可以看到 this.state.markdown 都被替换成了 this.props.markdown。同样通过 props 获取的还有事件处理函数 this.props.updateMarkdown。这是因为当前的 React component 已经变成了一个 presentational component。它没有 state,同样也不应该有业务逻辑,故而事件处理函数也要通过 props 传递进来。

Redux

Redux 的代码也同样简单:我们先创建了一个 reducer,然后基于它创建了一个 store。关于 reducer 和 store 的定义,请参考本系列教程的上一篇:React & Redux 入门教程 - 第三篇:Redux 术语浅析。同时我们还知道,reducer 接受 state 作为参数,而 store 则是 state 的容器,这足以证明我们已经把 state 从 React 转移到 Redux 了。

我们重点看下 reducer 的实现方式。推荐大家去仔细体会一下上一篇中对各种术语的解释:

Reducer 是一个 function,它接受 state 和 action 作为参数,返回一个新的 state。

State 代表了整个 Redux 程序的状态,它被 store 管理,并且是全局唯一的。

Action 代表了想更改 state 的一个意愿.

把上面的概念理解透了,代码自然而然就看懂了。有几点值得提一下:我们通过 reducer 参数的默认值定义了 state 的初始值:state = { markdown: '' }。我们通过 Object.assign 来生成一个新的 state,这是因为因为 reducer 必须是纯函数式,state 是 immutable 的,不能修改它。如果想对它进行修改,只能创建一个新的 state。

Bind React and Redux

上面的 React 和 Redux 都是各自独立定义的,他们并不知道彼此的存在,也不能协同工作。这就是为什么我们需要把它们 bind 在一起。

Bind 涉及两方面:数据和事件。数据的绑定,我们把 Redux store 中的数据以 props 的方式传递给了 React:markdown={store.getState().markdown}。事件的绑定,一方面我们把事件回调函数 updateMarkdown 以 props 的方式传递给了 React;另一方面,我们利用了 Redux store 的 subscribe 机制,每当 store 中的数据发生变化,render 方法就会被调用,从而刷新 React。

必须指出的是,像上面这样子手工 bind,是可以工作的,但却不是推荐的做法。有一种经过优化的 bind 的方式,我们留到下一章再做介绍。

您可能会喜欢

发表评论

电子邮件地址不会被公开。 必填项已用*标注

在这输入验证码 : *

Reload Image