React & Redux 入门教程 - 第二篇:从 jQuery 到 React

在上一篇中,我们学习了 React 的各种术语。其中 compoment 是 React 的核心概念,它是界面封装和重用的单元。如果把 component 类比为 function, 那么 props 就是它的参数,state 就是它的内部变量,它返回的结果是一个 element。此外我们推荐用 JSX 来提升 React 代码的可读性。如果您对前面提到几个概念感到陌生,请先阅读本教程的前一篇: React & Redux 入门教程 - 第一篇:React 术语浅析

在这一篇中,我们主要以实践为主。我们来动手把一个传统的基于 jQuery 的程序迁移到 React。首先我们会看一个 jQuery 程序的实现方式,接下来我们分析 jQuery 的优缺点,然后我们会指出为什么 React 在程序复杂的情况下比 jQuery 更合适,最后我们会动手用 React 将程序重新实现一遍,并比较两种不同实现的细节。

一个 jQuery 程序

这是一个简单的 markdown editor. 用户在上面的 textarea 输入 markdown 代码,程序会自动在下面显示出 HTML 版本的预览。程序的功能非常简单,我们重点看它的编码实现。

通过阅读代码,可以看出这是一个比较典型的 jQuery 程序。它通过 jQuery selector 来引用 DOM 元素:$('#markdown-textarea'), 通过 $('#markdown-textarea').on 来监听用户输入文字的事件,通过 $(this).val 来获取用户的输入,最后通过命令式的指令来修改 DOM 元素的值:$('.markdown-body').html(html);

jQuery 有什么问题?

我们来分析下 jQuery 编程的特点:首先 jQuery 编程是围绕着事件展开的。通过监听感兴趣的事件(比如用户输入、按钮被点击等等),并为各种事件指定明确的 callback 函数,来构成整个程序的逻辑。其次,jQuery 编程是通过一条条的指令来直接改变 DOM 的(后来诞生的很多框架是通过数据绑定来间接改变 DOM的)。用一句话概括:jQuery 程序在 event 的驱动下去修改页面的 element。请看下图:

到这里,其实我们没有发现任何问题。jQuery 解决问题的思路非常清晰,并且非常直截了当。这也是为什么那么多人(包括我)都非常喜欢 jQuery。jQuery 在处理大部分(简单的)场景的时候都非常得心应手。这一点从上面的 jQuery 程序中也体现出来了:代码非常简短,可读性也很好。

当程序变复杂的时候,情况就不一样了。一个复杂的 jQuery 程序,可能会有几十甚至上百种 event,同时有几十上百种页面 element。更加糟糕的是: 每一个 event,可能会更新不止一个 element;同样的道理,一个 element,也会被不止一个 event 所更新。最终情况就会像下面这样子失去控制:

React 有什么不同?

React 在 event 和 element 之间加了一层抽象,叫做 state。也就是 event 不再直接修改 DOM 的 element,而是只负责更新程序的 state。然后 state 和 element 之间又存在着数据绑定的关系。每当 state 更新,element 会自动更新从而和 state 保持同步。请看下图:

当程序变复杂的时候,也就是 event 和 element 的数量都很大的时候,情况是这样:

明显要比 jQuery 的版本更加清晰,更容易维护。有人可能会说:似乎并没有简单太多。这个我们就要靠数据说话了。假设有 N 个 event,M 个 element, 那么 jQuery 版本的复杂度是 O(N*M), React 版本的复杂度是 O(N+M)。

上图还有非常重要的一点需要说明:从 state 到 element 的数据绑定和状态同步,大部分工作是由 React 本身提供的,并不需要编写复杂的代码。我们只要把数据绑定声明好,React 就会确保 element 和 state 之间是保持同步的。它甚至在后台引入了 Virtual DOM 的机制,减少对浏览器 DOM 的修改从而提升性能,这并不需要我们做额外工作。

React 版本的程序

代码其实比 jQuery 版本多了不少。我们在上一篇的时候也有提到:对于简单的程序,React 的优势体现不出来。React 是为大规模的、数据变化频繁的项目而生的。我们选择这样一个简单的程序,是为了降低学习的难度。

通过阅读代码,我们看到大部分代码是为了创建一个叫做 MarkdownEditor 的 component。在它的构造函数中,我们初始化了程序的 state。render 方法中,我们写了一些 JSX 来构建界面。我们通过 value={this.state.markdown} 完成了从 state 到 element 的数据绑定。 我们通过 onChange={(e) => this.setState({ markdown: e.target.value })} 注册了一个 event 来更新 state。这样整个逻辑就能连贯起来了:event 更新 state,state 更新 element。

最后一行代码展示了如何将一个 React 的 component 嵌入到浏览器的 DOM 中:ReactDOM.render(<MarkdownEditor />, document.getElementById('root'));

值得一提的是:虽然上面的例子中是有 state 的,一个 React component 并不一定会有 state。一个没有 state 的 component 被称为是 presentational component。事实上,如果 state 对程序的全局有影响,并且会有复杂的变化形式,一般不推荐通过 React 来管理它。一个比较流行的选择是通过 Redux 来管理 state。本教程接下来的系列会深入介绍 Redux。

您可能会喜欢

发表评论

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

在这输入验证码 : *

Reload Image