写点什么

React.js 在 Codecademy 中的实际应用

  • 2015-03-24
  • 本文字数:5621 字

    阅读完需:约 18 分钟

自从 HTML5__ 变得流行以来,整个 Web__ 平台取得了长足的进步,人们也开始将 JavaScript__ 视为一门能够创建复杂应用的语言。许多新的 API__ 纷纷浮现,而关于浏览器如何应用这些技术的文章也大量涌现。

这一系列文章的视角更进一步,它们将关注于如何在实践中应用这些强大的技术,这并不是指创建多么酷炫的示例和原型,而是在第一线进行实际应用。在这个(后)HTML5__ 系列文章中,我们不需要响亮的口号,而是基于行业专家的实际经验,获得实践性的见解。我们也将讨论那些更进一步的技术(例如AngularJS _),并对 web__ 标准和 web__ 开发的未来进行定义。_

发布在 InfoQ__ 上的这篇文章是“下个时代的HTML5 和JavaScript __”系列文章其中的一篇。你可以订阅本系列文章,通过RSS__ 获取文章更新的通知。

2014 年八月,Codecademy 为了更新用户的学习体验,决定采用 Facebook 的 React.js 库,这是一个用于编写 JavaScript UI 的类库。在开始阶段,我们的问题是很难找到 React 在复杂应用中应用的示例,例如像 Codecademy 这样复杂的应用。因为大多数的教程都是针对小型示例应用上的特性,而不是针对在开发大型应用中更常见的问题。在本文中,我不仅会对 React 的使用进行一番概述,还会特别说明在大型 web 应用程序中使用 React 的某些特别注意事项。

React 是什么?

简单来说:React 是一个使用 JavaScript 创建用户界面的代码库。与编写用户界面常见的方式不同,React 将每个 UI 元素视为一个抑制的状态机。它并不是类似于 AngularJS 这样的“框架”。虽然 Facebook 有时会将 React 描述为“MVC 中的 V”,但我发觉这一描述并没有什么帮助,因为 React 应用并不需要遵守 MVC 模型。React 能够帮助你创建快速的用户界面,处理复杂的交互,而无需编写大量糟糕的代码。

如果你打算在工作中使用 React,你需要了解以下特性:

  • React会为你处理 DOM

DOM 操作的开销很大,而 React 的吸引力很大程度上来自于它对这一问题的处理方式。React 通过对自身虚拟 DOM 的维护,只在需要时进行重新渲染,将 DOM 操作的数量降至了最低,这要归功于 React 中高性能的比较操作的实现。

这就意味着你很少会需要直接与 DOM 打交道,与之相反,React 会替你处理 DOM 的操作。这一特性也是诸多 React 设计的基础。如果你打算滥用 React 的 API,或是打算按照自己的方式进行改动,那有可能会影响到 React 对 DOM 的理解。

该特性也使得使用 Node.js 进行内置的服务端渲染成为可能,这一点就使你能够轻易地创建对于 SEO 友好的页面。

  • React**** 使用声明式风格以及组件。

在 React 中,所有的组件都必须继承自 Component 类。组件中包含了属性(由父类决定)和状态(能够自行改变,通常是基于用户行为进行改变),组件的渲染和行为应当完全由它们的状态和属性所决定(而不依赖于任何其它值),因此组件就是状态机。这一模型鼓励使用者创建模块化的 UI,并且在实践中能够简化 UI 的操作与创建工作。

  • React将标记紧密地结合在 JavaScript中。

虽然在 JavaScript 中编写 HTML 代码听起来很奇怪,但在 React 中这是一种自然的选择。JSX 是原生的 JS 与 HTML 标记相结合的一种语言,对于它的使用是可选的,但我强烈建议你选择这种方式。React 认为,由于你的标记已经紧密地结合在控制这些标记的 JavaScript 中,因此可以将它们安置在同一个文件中,我也同意这一看法。

  • 单向信息流动。

这一点更多的是一种通用的 React 模式,而不是一种严格的规则。信息的流动在 React 中倾向于单向流动。在本文的稍后部分中,当我们开始考虑在大型应用程序中如何处理信息流动时,会再次提及这一模式。

解析 React 应用程序

为了让这些原则显得更为清晰,让我们看看 Codecademy 的学习环境是如何使用 React 进行构建的。

(单击图片以放大)

1:学习环境。

正如你在这个屏幕截图中所看到的一样,主要的学习环境由多个不同的 UI 元素所组成。某些元素是始终展现在页面上的,例如 header、menu 和 navigation。而有些组件会根据当前的练习的不同,处于显示或是不显示的状态。比方如,根据课程的不同,web 浏览器、命令行和代码编辑器可能会进行混合或是匹配。

创建该界面的逻辑解决方案是为各个部分创建 React 组件。在下面的屏幕截图中,我将特别指出主要的 React 组件:

(单击图片以放大)

2:学习环境以及对应的组件。

每个组件都有可能包含多个子组件:比方如,屏幕左方的 Lesson 面板实际上就包含了多个组件:

(单击图片以放大)

3:组成Lesson组件的各个子组件。

在这个示例中,我们将使用 React 以决定哪些组件应该显示在该 lesson 面板中。举例来说:

  • 只有在用户已登录的前提下,才会显示“Report a Problem”按钮
  • 只有在该练习中包括测试的情况下,才会显示 Instructions 部分

此外,React 会处理该组件与其它组件之间的信息流动。整个学习环境对应着一个父组件,该组件会持续跟踪多个状态,例如当前用户处于哪个练习中。父组件会为子组件的属性进行相应的赋值,以决定这些子组件如何显示。

现在,让我们来看一个组件通信的示例,以下组件来自经过大量简化后的组件树结构:

  • LearningEnvironment
  • CodeEditor
  • RunButton
  • ErrorDisplayer
  • Navigation

(单击图片以放大)

4:与代码提交相关的某些组件。

如果某个用户打算运行他的代码,我们该如何处理这一工作流?我们将尝试对他们提交的代码进行测试,然后显示错误信息,或是允许用户继续下一题。以下是某个可能发生的工作流:

  • 当用户单击 RunButton 之后,该组件会在事件的调用中,通过回调方式通知它的父组件 CodeEditor。
  • CodeEditor 组件会通过另一个回调函数通知它的父组件,即 Learning Environment 组件,并将用户的当前代码传递给父组件。
  • LearningEnvironment 组件将针对用户的代码进行测试。

根据结果的不同……

  • LearningEnvironment 组件会对 CodeEditor 中的属性 ****errorMessage赋值,CodeEditor 则会依次为它的子组件 ErrorDisplayer 中的属性 errorMessage 赋值。
  • 如果用户已经完成了该练习的所有测试,LearningEnvironment 组件就会为 Navigation 组件中的属性 progress 赋值。

如果我们的组件都能够像在 LearningEnvironment 组件中的 render 方法一样进行声明(同样进行了大量简化),那么就可以通过一个单一的函数调用实现整个 UI 的更新:

复制代码
render: function() {
return(
<div>
<CodeEditor
error={this.state.error}
/>
<Navigation
mayProceed={this.state.mayProceed}
/>
</div>);
}

请记住,React 中混合了 JavaScript 和 HTML 标记。在这个例子中,render方法定义了一个LearningEnvironment组件,其中包括了一个CodeEditor组件和一个Navigation组件。

我们可以更新 LearningEnvironment 组件的状态,它会触发组件的重绘,并在必要时更新子组件。

复制代码
handleTestResult: function(currentIndex, passing, error) {
this.setState({
error: error,
mayProceed: passing && currentIndex === this.state.currentExercise.tests.length-1
});
}

这就是全部的代码了。React 以一种优雅而简单的方式替我们处理 UI 的更新操作。

大型应用程序中的考虑因素

信息流动

正如我之前所说的一样,React 不一定要遵循 MVC 模型,实际上,你可以按照任何你喜欢的方式处理信息流动,但你需要一种确切的信息策略。为了让属性的变化传递给子 - 子 - 子 - 子 - 子组件,你是否需要将该属性一路传递下去,哪怕中间的那些子组件完全不需要了解该属性?如果该叶子节点接受用户输入,它又该如何将这一变更通知它的父 - 父 - 父 - 父组件呢?

在大型应用程序中,这种处理方式是很令人受挫的。即使是在以上那个简单的示例中,Run 按钮该如何与 LearningEnvironment 组件之间传递用户的行为呢?我们需要传递回调函数,但这种方式很难写出真正模块化、可重用的组件。

Codecademy 的解决方案是通过创建通信适配器(Adapter),以管理各别组件间的信息流动。与传递回调函数的方式不同,高层次的组件,例如 CodeEditor 会接收到一个 Adapter,它为重要的通信任务提供了一种单一的接口。举例来说,当 CodeEditor 处于显示状态时,LearningEnvironment 会创建一个 Adapter,它能够生成和处理与用户提交代码相关的事件。

这种方式也不是完全没有缺陷的,我也在 React 大会的演讲中针对这一点进行了详细的论述。我的主要观点在于,无论你 _ 如何 _ 处理组件树中的信息流动,你的团队都应该坚持一种一致的策略。

整合

React 的上手非常简单,但要在你的工作流中高效地使用它,你需要一些工具的支持。举例来说,我们使用了以下工具:

  • 用一段脚本对.jsx 文件的本地文化进行监控,并在必要时对它们进行重新编译
  • 一个独立的 node.js 服务器,用于处理服务端的展示
  • 用于在需要时自动生成新组件文件的开发者工具

以上这些工具都不是非常复杂。对于.jsx 的监控来说,Gulp 是一个很好的选择,不过我们选择了使用 Go 语言自行编写脚本。我们使用了一个简单的批处理脚本负责生成新的组件文件,这种方式也能够确保命名规范。如果你打算使用一个 node.js 服务器以负责服务端展示,你需要当心的是,要强制 require.js 能够获取到 React 代码中的变更可能会有些困难,因此我们创建了一个监控器,让它在必要时重启 node 服务器。

为什么使用 React?

在我们重新设计整个学习环境时,我们需要决定选择使用哪一套工具或框架。我们最终选择了 React,对这一决定我们感到非常满意。(关于我们如何选择一套 JavaScript 框架的详细过程,可以在以下演讲视频中找到: https://www.youtube.com/watch?v=U5yjPG5mHZ8

我们对于 React 的欣赏之处主要在于以下几个方面:

它经过了实战检验

React 已经在 Facebook 和 Instagram 的生产环境中得到应用,因此我们对于它的性能和可靠性很有信心。目前为止,它在我们的平台上同样表现良好,我们也没有遇到过任何严重的问题。

组件化的方式便于理解。

React 对每个独立的组件进行单独处理,这些组件会按照它内部的状态进行展现,因此对于某一时刻应该发生什么事,很容易形成概念化的理解。你的应用程序会有效地成为一个大型状态机。这意味着你可以单独测试 UI 中的每个片段,同样可以自由地添加新组件,而无需担心会影响整个应用程序中其它部分的代码。

SEO 非常容易实现。

因为 React 本身就支持服务端展现,因此在搜索引擎看来,你提供的是一个基本已完成的页面,这对于 SEO 来说是一个极大的优势,而所需的工作量非常小。的确,这一点必需由 Node 完成。由于 Codecademy 的主应用是由 Rails 编写的,因此我们搭建了一个独立的 Node 服务器,专门用于处理 React 的展现。

React 能够兼容遗留代码,并且它的灵活性足以应对未来。

虽然采用一整套框架的确是一件大事,但你也可以慢慢地尝试将 React 添加到现有的代码库中。与之类似,如果将来我们需要移除 React,我们也可以轻易地实现这一点。在 Codecademy,我们首先决定完全使用 React 来编写一个全新的项目,以便尝试它的功能,并学习如何以最佳的方式使用它。这个项目很成功,因此我们现在基本上在所有的新 UI 元素中都使用 React 了。我建议你首先做些功课,创建一些实验项目,然后再考虑怎样让 React 适应于你的现有代码库。

不必担心编写样板代码了。

在编写样板代码上所花的时间越少,就意味着你可以将更多的时间花在更有意义的问题上了。从这个角度上来说,React 是个既简洁又轻量级的类库。以下代码是创建一个新的组件所需的最少代码:

复制代码
var dummyComponent = React.createClass({
render: function() {
return (<div>HTML markup in JS, what fun!</div>);
}
});

简短且切题,还有什么不满意的?

我们的社区正在成长

React 社区的发展非常迅速。当你遇到各种问题时,你可以和许多社区成员讨论这一问题。并且,由于许多公司都已经在生产环境中使用了 React(仅举几例,Facebook、Instagram、Yahoo!、Github 和 Netflix),因此我们并不独孤。

总结

React 是一个轻量级、强大,并且经过实战检验的使用 JavaScript 创建用户界面的类库。它不是一个框架,而是一个强大的工具,或许会改变你进行前端开发的方式。我们认为它对于我们的前端开发来说,作用之大是难以置信的,而我们对于自己的选择也感到相当满意。对我自己来说,使用 React 进行工作至少是极大地影响了我思考编写用户界面的方式。我也乐于看到 React 的不断成长:现在 Facebook 已经通过 React Native 将 React 的功能带到移动开发上了,我想它的未来一定会是一片光明。

如果你打算上手使用 React,它的教程是一个不错的逻辑起点。互联网上也有着大量介绍React 中的关键概念的帖子(这个幻灯片是我最爱的教程之一)。不要停下脚步,学习钻研,尝试着创建些什么,然后看看你对于React 这种前端开发方式是怎么想的。我非常乐于聆听你的想法,请将你的想法发送至我的Twitter 帐号 @brindelle

关于作者

Bonnie Eisenman**** 是一位来自于Codecademy.com 的软件工程师。她最近刚刚从普林斯顿大学的计算机科学专业毕业。她对硬件也有一定兴趣,在业余时间喜欢从事一些 Arduino 方面的工作,以及乐曲编辑。她的 Twitter 帐号是 @brindelle。

自从 HTML5__ 变得流行以来,整个 Web__ 平台取得了长足的进步,人们也开始将 JavaScript__ 视为一门能够创建复杂应用的语言。许多新的 API__ 纷纷浮现,而关于浏览器如何应用这些技术的文章也大量涌现。

这一系列文章的视角更进一步,它们将关注于如何在实践中应用这些强大的技术,这并不是指创建多么酷炫的示例和原型,而是在第一线进行实际应用。在这个(后)HTML5__ 系列文章中,我们不需要响亮的口号,而是基于行业专家的实际经验,获得实践性的见解。我们也将讨论那些更进一步的技术(例如AngularJS _),并对 web__ 标准和 web__ 开发的未来进行定义。_

发布在 InfoQ__ 上的这篇文章是“下个时代的HTML5__ 和JavaScript”系列文章其中的一篇。你可以订阅本系列文章,通过RSS__ 获取文章更新的通知。

查看英文原文: React.js in Real Life at Codecademy

2015-03-24 11:146539
用户头像

发布了 428 篇内容, 共 178.8 次阅读, 收获喜欢 38 次。

关注

评论

发布
暂无评论
发现更多内容

Gartner 2021年主要战略技术趋势

车骑

组织转型 行业资讯 数字化 技术趋势 后新冠

去中心化、P2P、NAT浅析

IT酷盖

音视频 WebRTC 去中心化

Java开发项目模板16步快速搭建,拒绝重复性工作!

北游学Java

Java 项目 模板

GitHub首次上线!华为顶级工程师手写的这份网络协议手册全面开源

Java架构之路

Java 程序员 面试 编程语言 计算机

自研消息队列架构设计文档

贯通

#架构实战营

【LeetCode】搜索二维矩阵Java题解

Albert

算法 LeetCode 5月日更

微信朋友圈的高性能复杂度

王华

架构实战营

MySQL-技术专题-主从复制

洛神灬殇

MySQL MySQL 高可用 高可用架构 5月日更

封神总结!蚂蚁金服+滴滴+美团+拼多多+腾讯15万字Java面试题

Java架构之路

Java 程序员 架构 面试 编程语言

架构设计模块3 - 消息队列架构设计文档

Presley

架构实战营

Boss直聘超90W次转发的Java面试题库!已超神

Java架构师迁哥

什么是线程安全?并发问题的源头

wzh

Java 并发编程 线程安全

常量之所想

顿晓

常量 5月日更

SpringBoot-技术专题-教你使用Cache缓存组件

洛神灬殇

spring springboot cache 5月日更

出游时,请继续戴好口罩

石云升

新冠疫苗 5月日更

Dubbo 动态配置中心

青年IT男

dubbo

Vue Router 10 条高级技巧

Thrash

技巧

架构实战营 模块二 作业

Pitt

架构实战营

架构实战营-模块3学习分享

En wei

架构实战营

GreenPlum资源管理

数据社

greenplum 5月日更

架构实战营模块3作业-架构设计文档

En wei

架构实战营

【LeetCode】删除并获得点数Java题解

Albert

算法 LeetCode 5月日更

【死磕JVM】看完这篇我也会排查JVM内存过高了 就是玩儿!

牧小农

JVM;

新人小白福利!五一假期怒肝一天整理Java类,不简单不全你打我

牛哄哄的java大师

Java

深入理解spring框架之事务管理

邱学喆

mysql事务 spring事务管理 TransactionInterceptor Savepoint 事务传播行为

天时地利人和—一个传奇操作系统的诞生记

兆熊

unix 历史

从简历被拒到收割8个大厂offer,我用了3个月成功破茧成蝶

Java架构之路

Java 程序员 架构 面试 编程语言

不要轻言放弃,阿里P8架构师分享十年学习生涯

Java架构师迁哥

音视频编解码流程与如何使用FFMPEG命令进行音视频处理

张音乐

音视频 ffmpeg

字节一二三面,面经(已经OC)四月底真实面试经历!

Java大蜗牛

Java 程序员 面试 算法 后端

新手学习微服务,得先看看这篇文章

Java架构师迁哥

React.js在Codecademy中的实际应用_JavaScript_Bonnie Eisenman_InfoQ精选文章