写点什么

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:146596
用户头像

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

关注

评论

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

产品FAQ(常见问题)文档模版

小炮

产品 FAQ

Git教程-帮助开发人员更好的运用Git | 云效

阿里云云效

git 云计算 阿里云 DevOps 开发者

叮咚!参与微服务免费试用,有机会获得腾讯内推资格!

InfoQ写作社区官方

腾讯云 微服务 热门活动

Rust Cell 与RefCell,有啥区别?

非凸科技

明天直播:如何测试硬件设备与龙蜥操作系统的兼容性?

OpenAnolis小助手

硬件 直播 开源社区 sig 兼容性

教你VUE中的filters过滤器2种用法

华为云开发者联盟

Vue 过滤器 filters过滤器 组件过滤器 全局过滤器

下拉推荐在 Shopee Chatbot 中的探索和实践

Shopee技术团队

算法 chatbot 推荐算法

外部数据的合规引入助力银行用户营销系统冷启动

易观分析

隐私计算

Tapdata 肖贝贝:实时数据引擎系列(六)-从 PostgreSQL 实时数据集成看增量数据缓存层的必要性

tapdata

数据库 实时数据

昇思MindSpore行至2022,开源社区成就生态共赢

这不科技

华为 昇思MindSpore

春暖花开,等你而来!4月月更挑战开始啦!

InfoQ写作社区官方

热门活动 4月月更

如何快速实现持续交付

阿里云云效

云计算 阿里云 软件开发 CI/CD 持续交付

向工程腐化开炮 | 治理思路全解

阿里巴巴终端技术

Java android 腐化治理 工程腐化

后端开发—一文详解网络IO模型

Linux服务器开发

reactor 后端开发 Linux服务器开发 网络io 网络模型

汉化版postman

Liam

Jmeter Postman 接口测试 API swagger

华为云GaussDB专家走进课堂,跟莘莘学子聊聊数据库

华为云数据库小助手

GaussDB GaussDB(for openGauss) GaussDB(for MySQL)

Facebook 开源 Golang 实体框架 Ent 现已支持 TiDB

Geek_2d6073

云时代,租电脑还是初创型企业最好的选择吗?

阿里云弹性计算

远程办公 无影云电脑 初创型企业

VuePress 博客搭建系列 33 篇正式完结!

冴羽

JavaScript Vue 前端 vuepress 博客搭建

OpenHarmony标准设备应用开发(三)——分布式数据管理

OpenHarmony开发者

OpenHarmony 分布式数据

软件定义存储厂商大道云行加入龙蜥社区

OpenAnolis小助手

生态 存储技术 龙蜥社区 大道云行 CLA

《LeetCode 刷题报告》题解内容Ⅱ

謓泽

3月月更

异构注册中心机制在中国工商银行的探索实践

SOFAStack

GitHub 开源 分布式架构 注册中心 工商银行

week4作业

Asha

从二十年开源经历出发,70 后大龄程序员谈成长、困境与突围

TDengine

数据库 tdengine 开源

利用 IoTDB 替换 OpenTSDB,服务大唐集团60家电厂,减少95%运维成本

Apache IoTDB

Apache IoTDB

适合 Kubernetes 初学者的一些实战练习 (三)

汪子熙

云原生 集群 Kubernetes 集群 Kubernetes, 云原生, eBPF 3月月更

小程序开发入门教程

CRMEB

墨天轮访谈 | 华为云温云博:从客户视角出发,GaussDB(for Redis)究竟“香”在哪里?

墨天轮

数据库 redis 华为云 国产数据库 键值数据库

深入垂直业务场景,SaaS版供应商业务协同管理系统促进企业与供应商高效协同

数商云

数字化转型 供应链系统

一文带你了解 Python 中的迭代器

踏雪痕

Python 3月程序媛福利 3月月更

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