我们使用 React 来编写用户界面。在这里,您可以找到我们选择 React 的原因以及简要介绍。此外,我们列出了所有 DevTools 代码在编写 React 时应遵循的最佳实践。

快速入门

这是一个关于如何使用 React 的非常简短的介绍,但没有深入解释其背后的概念。如果您想了解更多深入的文章,我推荐以下链接

  • http://facebook.github.io/react/docs/tutorial.html - 官方教程

  • https://github.com/petehunt/react-howto - 如何学习 React

  • http://jlongster.com/Removing-User-Interface-Complexity,-or-Why-React-is-Awesome - 阅读量很大,但深入解释了概念

React 将组件作为思考 UI 的一种方式。组件是所有事物的中心:它们像函数一样可组合,像 JSON 数据一样可测试,并为更复杂的情况提供生命周期 API。

一个组件可以代表任何东西,从列表中的单个项目到由子组件组成的完整虚拟网格。它们可以用来抽象出“行为”而不是 UI 元素(想想 Selectable 组件)。React 的 API 使您能够轻松地将 UI 分解成您需要的任何抽象。

组件的核心思想很简单:它接收属性并返回类似 DOM 的结构。

function Item({ name, iconURL }) {
  return div({ className: "item" },
             img({ className: "icon", href: iconURL }),
             name);
}

divspan 函数分别指代 React.DOM.divReact.DOM.span。React 在 React.DOM 上为所有 DOM 元素提供了构造函数。这些符合创建元素的标准 API:第一个参数接收属性,其余的是子元素。

您可以看到在使用 Item 时组件组合开始发挥作用。

const Item = React.createFactory(require('./Item'));

function List({ items }) {
  return div({ className: "list" },
             items.map(item => Item({ name: item.name, icon: item.iconURL)));
}

您可以像使用原生组件一样使用自定义组件!唯一的区别是我们在导入时将其包装在一个工厂中,而不是使用 React.DOM 函数。工厂只是将组件转换为便捷函数的一种方式。如果没有工厂,您需要执行 React.createElement(Item, { ... }),这与使用工厂时的 Item({ ... }) 完全相同。

渲染和更新组件

现在我们有一些组件了,我们如何渲染它们?您可以使用 React.render 来实现。

let items = [{ name: "Dubois", iconURL: "dubois.png" },
             { name: "Ivy", iconURL: "ivy.png" }];

React.render(List({ items: items }),
             document.querySelector("#mount"));

这将渲染一个 List 组件(给定 items)到 ID 为 mount 的 DOM 节点。通常,您有一个作为所有内容根的顶级 App 组件,您可以像这样渲染它。

更新怎么办?首先,让我们谈谈数据。上面的组件从上面获取数据并渲染出 DOM 结构。如果涉及任何用户事件,组件将调用作为 props 传递的回调函数,因此事件会向上回溯层次结构。概念模型是数据向下传递,事件向上回溯。

您通常希望响应事件更改数据,并使用新数据重新渲染 UI。那是什么样子?React 将在两个地方重新渲染组件

1. 任何额外的 React.render 调用。一旦组件被挂载,您可以再次对相同位置调用 React.render,React 将看到它已经挂载并执行更新而不是完全渲染。例如,此代码响应事件添加一个项目并更新 UI,并将执行最佳增量更新

function addItem(item) {
  render([...items, item]);
}

function render(items) {
  React.render(List({ items: items,
                      onAddItem: addItem }),
               document.querySelector("#mount"));
}

render(items);

2. 更改组件本地状态。这更为常见。React 允许组件具有本地状态,并且只要使用 setState API 更改状态,它就会重新渲染该特定组件。如果您使用组件本地状态,则需要使用 createClass 创建组件。

const App = React.createClass({
  getInitialState: function() {
    return { items: [] };
  },

  handleAddItem: function(item) {
    const items = [...this.props.items, item];
    this.setState({ items: items });
  },

  render: function() {
    return List({ items: this.state.items,
                  onAddItem: this.handleAddItem });
  }
});

如果您使用 Redux 等内容来管理状态,则通过用于将 Redux 与 React 绑定的库自动为您处理。请参阅 Redux 中的更多信息。

DOM Diff

当 React “更新”组件时这意味着什么,它如何知道要更改哪个 DOM?React 通过一种称为 DOM Diff 的技术实现了这一点。这避免了程序员需要担心更新实际上是如何应用于 DOM 的,并且组件可以响应数据以声明方式渲染 DOM 结构。在上面的示例中,当添加项目时,React 知道仅添加一个新的 DOM 节点,而不是每次都重新创建整个列表。

DOM Diff 是可能的,因为我们的组件返回所谓的“虚拟 DOM”:React 可以用来与先前版本进行比较并生成对真实 DOM 的最小更改的轻量级 JSON 结构。

这也使使用真实 DOM 测试组件变得非常容易:只需确保虚拟 DOM 包含它应该包含的内容即可。

下一步

接下来阅读 React 指南,了解如何专门为 DevTools 编写 React 代码。