前言

在踏入 React(或 ReactJS)的大门时,我们要做的第一件事就是正视那些吹捧它的说法。大多数 React 专家、老手甚至核心团队开发人员都喜欢从很高大上的层面来介绍这个“用于构建用户界面的 JavaScript 库”(不是框架)。为了了解其中的概念和原理,人们好像还要把自己的编程思维再提升一个层次才行。

请注意,React 不是一个框架,而是一个库,因为它依赖一些第三方库来提供一些核心功能(如路由),不像 Angular 或 Vue.js 等框架那样会内置这些功能。就是说它不是一个完整的框架。但因为它很简洁地融入了很多高级编程理念,所以成为了前端库和框架中的佼佼者。在今天这个低耦合和微服务的时代中,这个前端库(与 Angular 和 Vuejs 等 JavaScript 框架不分伯仲)使用了和人们习惯的 JavaScript 最接近的哲学来构建复杂的前端。它不像 Angular 那样困在 TypeScript/MVC 架构中,或者像 Vue.js 那样耦合到 HTML 上。

更重要的是,React 是一个由 Jordan Walke 创建的 Facebook 开源项目,这个项目由一些颇具野心的年轻开发人员主导——其中包括 Dan Abramov,他经常会隐晦地解释这个库背后的理念,(社交)媒体上关于 React 的话题几乎都能找到他的身影;还有 Brain Vaughn,他从图形设计领域转向了编程工作,构建了 react-virtualized,并加入了 React 核心团队。

React 的风格

初次接触 React 的人们都应该从一个高层视角了解下述事实,那就是 React 既非框架也非编程语言,而是一个遵循某些原则的库;它的开发人员选择这些原则,是因为他们认为这些原则更适合用来构建响应式和函数式用户界面。具体的原则包括基于组件的设计、组合优于继承和自上而下的单向数据流,以在函数响应式编程中保持一致性。

它基于 声明式范式,而非命令式范式。此外,React 采用了面向对象编程(OOP)的一些主要范式,并最好使用现代 JavaScript、ES6 和更高的版本来实现(虽说它也向后兼容 ES5)。

因为 React 推崇组合而非继承,所以你不用实现任何接口,在 React 团队拒绝使用 Mixins(这是接口的高阶结构)后,它们就出局了。对于 Java 家族来说,接口是语言的固有组成部分,Java 8 接口中就采用了 Mixins。因此,如果你以前熟悉的是基于类的继承范式,那么为了精通 JavaScript,学习动态类型和其他 JavaScript 语言的优秀特性,你应该知道所有东西都是变量之外的函数。你可以将函数传递给方法或 JSON 对象,并做回调等很多事情。

一切都是组件

如果你是一位经验丰富的程序员,之前用的是 Java 和 C# 等基于类的继承语言,也了解 SpringBoot 之类的框架,那么现在你会发现 React 的主要构建块是 React.Component 类。这个类定义了你要实现的方法,其中之一就是 render();如果一个组件需要在网页上渲染自己和自己包含的其他组件,那就会用到 render 方法。组件可能不会声明 render 方法,只有那些将组件渲染(读取插入)到 DOM,并使用生命周期方法和内部状态的组件才会声明它,而其他组件可以将其状态作为 props。它们可以像普通的 JavaScript 变量一样声明,并且必须初始化为 JSX、JavaScript XML 或返回为它们的函数,并包括在另一个包含 render 方法的组件中。因此,你很容易就能理解这些方法,并通过它们获得父 Component 类中具有的一些功能。

如果你刚开始学习编程,那么你必须知道两件事,那就是基于类的继承和 OOP 基于原型的继承。例如,如果有人还在 React 中使用类,他们就需要了解将对象建模为类(OOP),以及某些概念(如 static 关键字)。一个典型的例子是 React Component 中的 static getderivedstatefromprops,其中引用该类的 this 关键字是无法访问的(因为静态方法不是要调用它的对象的成员),但是可以在类级别访问。同样,当你编写 ReactDOM.render() 作为启动 React 应用程序的引导时,将调用 ReactDOM 函数的 render 方法。完全没接触过编程的新人更难理解这些概念。

现在有三种编写 React 组件的可行方法,这会让新人困惑不已。(在 Angular[不是 AngularJS] 中就是 TypeScript。)它们分别是:

  1. 基于类的组件

  2. 函数式组件

  3. TypeScript 函数式组件

ES5 之后引入了 基于类的组件,其中每个组件都可以是一个类,并且具有使用 this.state{}声明的类变量。该类在其构造器中采用 props(属性),该构造器必须调用从父组件传递给它的 super(props)。

比如你要开发一个待办事项应用,并且在一个页面上有两三个待办事项卡;你创建了一个包含待办事项的 todoparent 组件,你的父组件将进行数据库调用并获取所有待办事项数据显示出来,然后每个 todo 组件更新自己的内容并保存到数据库。因此,你传递给 todo 的初始数据是 props,每个 todo 的数据就是其状态。你要学习如何使用 PureComponentsHigherOrderComponents(HOC) 和帮助程序库(如 Redux)来管理状态。

如今,函数式组件 是编写 React 组件的首选方式。它们是 React v16 的新特性,是符合习惯的 JavaScript。为了操作它们的状态,React 引入了 Hooks。Hooks 是用来“挂”到函数式组件状态的函数,因为它们是无状态的,所以没有 this,也就没有像类这样的状态。一个 hook 以“use”作为前缀来声明,比如 useState。它返回状态和一个 setter(如果需要),或仅返回状态。

示例:

const [count, setCount] = useState(0)

我们初始化了 count = 0。我们包含了一个用于更新状态的 setter。我们不应该在组件中执行 count +=1,因为它们会引入错误。相反,我们执行 setCount(count+1)。Hooks 非常符合人们的习惯,它是纯 JavaScript,因此我们用不着再深入了解类了。如果你是 JavaScript 专业人士,请相信我,你用一个月就能学会 React。一切都可以用 hooks 操作。可以使用具有以下变体的 useEffect Hooks 来模仿 React.Component 提供的 React Lifecycle 方法:

// (1) On Mount and every render
useEffect (() => { 
  dosomething()
});
// (2) Only on Mount
useEffect (() => {
  dosomething()
}, []);
// (3) On Mount/every time state of count changes
useEffect (() => {
  dosomething()
}, [count]);
// (4) UseEffect with cleanup
useEffect (() => {
  dosomething();
  return clearSomething(){};
});

注意四个 useEffect hooks 的区别。第一个 hook 没有第二个参数(在挂载和每次重渲染时运行),另一个有一个空数组(仅在挂载时运行),第三个在一个数组中有 count(在挂载和 count 的状态改变时运行),最后一个返回一个函数,用来在卸载组件时做清理。它们用于模拟生命周期方法——componentDidMount、componentDidUpdate 和 componentWillUnmount——我们需要在类中管理组件的挂载,更新和卸载。第四个 hook 用于卸载,注意返回的函数。其他生命周期方法也可以使用 Hooks 来实现——getDerivedStateFromProps 可以通过对比组件状态和 props 来实现。可以使用 React.Memo 来实现 shouldComponentUpdate,以防止重新渲染,并且它使用 memoization。

关于函数式组件和类的争论在 React 生态系统中很常见。尽管函数式组件无处不在,但某些功能尚没有函数式实现,比如用来显式捕获组件中错误的 Error Boundaries。有人认为函数式组件比类组件快的说法是在吹牛。

TypeScript 函数式组件 是函数式组件的增强。使用 TypeScript 可以引入静态类型,其中必须在声明和函数参数中为所有变量和参数赋予类型。为确保类型安全,在 TypeScript 中必须使用函数式组件和类中的 Prototypes 进行类型检查。

反模式

你会经常听到这个流行词“反模式”。React 中的反模式是对一系列书面和非书面原则的偏离,这些原则用来指导我们应如何实现 React 以获得最佳结果。这些偏离会导致不良的编程实践。一个例子是更改子组件中的 props。我们不建议这样做,因为它会破坏自上而下的流。

状态管理

React 绑定了 Redux 这个状态管理库(以后就不一定了)。实际上,尽管我们还有其他状态管理库(例如 Flux 和 Mobx)可选,但如今 React 职位都要求 Redux 技能,Redux 是默认选项。我们知道大多数前端应用程序都可以管理状态,Redux 提供了一个 store,一些 reducer 和 action 来帮助管理。在选择要学习的项目时,请选择使用 Redux 的项目,这样就能学到完整的知识了。

专家

最后,React 是一个很好的前端库(读取框架)。我对 Angular 不像 React 那么了解,但我已经完成了 stackblitz 教程。egghead.io 是学习 React 的最佳去处之一。React 的主要开发人员之一 Dan Abramov 在那里发布了视频教程。然后是拥有自己网站的 Kent C Dodds 和 Tania。你还可以谷歌到其他成千上万的教学内容。你真正需要的是开始学会 JavaScript 和 OOP(基于类和基于原型)的思维方式,还要了解 DOM API 的知识,但用不着太深入。React 在 DOM API 的基础上提供了一个抽象,因此你不必直接操作 DOM(需要时可以通过 ref 操作它),但你需要知道它的基础工作机制。通过 ReactDOM,我们得以将 JSX 插入 Web 浏览器,因此它与平台和浏览器无关。基本上你可以在 React 中做你想做的任何事情。在掌握高级知识并开始构建复杂的用户界面之前,你应该无需操心底层和样板代码。你可以浏览 React GitHub 页面,亲自体验一番。

总结

我不想谈的太深入,因为本文是对 React 世界的概述,这个世界光靠一篇文章或一本书是没法介绍完的——我自己对它的了解还不够深呢。我正在积极学习,希望在 2020 年底之前成为 React Rockstar。本文的内容是我在实践中总结出来的经验,实际上我使用 React 实现了一个计算器,读完了整个顶级 API 并一直在 Stackoverflow 上回答关于 React 的问题。我还参与开发了一个 React Native 应用,它是别人启动的,我做完了它。

相信我,掌握这些概念后,你不用半年就会熟练应用 React 世界中的各种原则和能力了。撰写本文一年前,我对这些东西一无所知。我记得第一次阅读官方的 React 教程时就好像在看天书,但现在我已经非常熟悉它了。

原文链接:
https://medium.com/javascript-in-plain-english/i-read-the-entire-react-api-here-is-my-advice-to-new-developers-d040507e6c23