[译]React 元素 vs React 组件 vs 组件支撑实例

前端之家收集整理的这篇文章主要介绍了[译]React 元素 vs React 组件 vs 组件支撑实例前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

本篇为译文,原文出处:React Elements vs React Components vs Component Backing Instances

许多人可能听说过 Facebook 的 React 库,并在自己的工作或项目中使用它。React 是非常流行的,使开发用户界面变得简单且符合声明式编程(译者注:声明式编程可以参考声明式编程和命令式编程的比较)。

正如题目所示,React 有几个概念遍及其文档,这(几个概念)可能会让新React用户困惑。例如,你在 GlossaryTop-Level APIExplanation on Refs 这几章中检索 “React Element”、“React Component” 和 “Component Backing Instance”,你会发现这几个术语遍及各处,已经是 React 的绝对的核心。

这篇文章不是一篇 React 的教程,更多的是分享我最近学习 React 而得到的一些(知识)。因此,这篇文章是针对之前已经涉猎过 React 的人们,我会假设你已经熟悉 React 一些核心概念和语法。

React元素是什么?

React 元素这个概念对于 React 来说很重要,但是我坚信一点,因为使用 React 和 JSX 来构建用户界面过于简单,从而导致可能在最初错过这个概念。如果你之前用过 React + JSX,毫无疑问的说,在你的 JS 文件中书写类 HTML 语法更加符合你的习惯(译者注:Habit is second nature. 习惯成自然)。在这种(书写类HTML语法)假象之下,JSX 语法实际上被编译成特殊的函数调用React.createElement()。 猜猜 React.createElement()会产生什么?耶,你猜对了,就是 React 元素。让我们看一个转换过程的例子:

// 使用 JSX 语法
var helloWorld = <div>Hello World!</div>;

// 然后是 JSX 被编译成 JavaScript 后的结果
var helloWorld = React.createElement(
  "div",null,"Hello World!"
);

// 再是处理成 JavaScript 简单对象后看起来类似这样
var helloWorld = {
    key: null,props: {
        children: "Hello World!" // more stuff in here
    },ref: null,type: "div"
    // more stuff in here
};

React 元素是由一些属性(properties)构成的 JavaScript 简单对象(plain old JavaScript objects,译者注:关于更多解释可以看 Plain Old JavaScriptWhat is a plainObject in JavaScript?):

  • key - 属性 key 是用来在一组相同类型的 React 元素构成的 Array 中标识唯一特定 React 元素。你不必提供一个值给它(译者注:在新版 React 中,如果在循环一组相同类型的 React 元素时不指定 key,会报一个 warning 错误,具体可以参考 React 对循环 warning 提示增加 key 的研究),但是如果你给 key 提供一个值,React 将能够进行优化,使重新渲染过程更高效。

  • props - 属性props 恰恰是你所认为的: 它是向下传递给子组件(child components)的所有 props 和 values 的映射(集合)。

  • ref - 属性ref 用来访问与这个 React 元素相关联的经过(浏览器或渲染引擎)渲染处理后的底层 DOM 元素。

  • type - 属性type 将是两种格式之一,表示任何有效的 HTML 元素的(名称)字符串 或 指向 React 组件类的引用。

此时,了解每个属性所有细节并不重要。最大的收获在于,React 元素仅仅是 JavaScript 简单对象(plain old JavaScript objects),用来描述组件的 HTML 应是怎样的结构,这个对象上不包含任何方法(Methods),仅仅只有数据。

通过之前 helloWorld React 元素的例子告诉你,helloWorld表示一个子节点为“Hello World!”文本的 div 标签。即使你创建了一个更复杂的 JSX 例子,生成的 React 元素仍将是一个 JavaScript 对象,配合其他嵌套 React 元素描述 HTML 将是怎样的结构。如果这让你感觉熟悉,是因为这正是虚拟 DOM(Virtual DOM)是什么(的解释) - 它是 DOM 在特定时间段应该是怎样的结构的描述,通过 React 元素声明来表示。

React组件是什么?

不同于 React 元素,你可能对 React 组件更熟悉一些。如果你曾写过类似下面例子的代码,那么你之前已经创建过 React 组件类了:

// 这是一个 React 组件类
class CustomForm extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            inputText: "Willson"
        };

        this.handleInputChange = this.handleInputChange.bind(this);
    }

    handleInputChange(e) {
        const inputText = e.target.value;
        this.setState({ inputText });
    }

    render() {
        return (
            <div className="custom-form">
                <div className="custom-form-header">
                    <p>Hello,{this.state.inputText}</p>
                </div>
                <div className="custom-form-body">
                    <input type="text"
                           value={this.state.inputText}
                           onChange={this.handleInputChange} />
                </div>
            </div>
        );
    }
}

/*
 * 我假设你有可用的 React 和 ReactDom,以及  
 * 一个 id 为 "root" 的 HTML 元素
 * ReactDOM.render() 的返回值是组件实例
 */
var componentInstance = ReactDOM.render(<CustomForm />,document.getElementById("root"));

上面的例子是用 ES2015 新的 Class 语法写的,但它几乎相当于使用 React.createClass()。你也许熟悉编写这些组件类,但重要的是(React文档中所述的)React 组件指代的是一个 React 组件类的实例。

假如你熟悉 JavaScript 的话,当你听到到“实例化一个类”且智商在线时,你可能会考虑使用new操作符。然而,(在 React 中)从不需要你用 new 操作符创建 React 组件。相反的是,你将使用 ReactDOM.render() 把一个 React 元素渲染成一个特定的 DOM 元素,与此同时,ReactDOM.render() 将返回一个 React 组件实例。

ReactDOM.render() 返回的组件实例可以调用在 React 组件类中定义的方法。反过来想一下会让你明白,ReactDOM.render() 是 React 为你实例化一个组件的机制。通常,你不需要访问组件实例本身,但我发现在测试 React 组件时,将组件实例的引用保存下来(对测试)很有帮助。

ReactDOM.render() 有关的最后一个有趣的点是,React 在 ReactDOM.render() 时对虚拟 DOM 执行高效的 diff 算法(译者注: diff 算法延伸阅读)。如果你记得(上面说的),React 元素表示虚拟 DOM(元素),这意味着 ReactDOM.render() 接收一个虚拟 DOM(元素),将其渲染成一个真实 DOM 元素,返回(React 元素 type 指定的)组件实例。在底层,如果你将相同的React元素类型(带有可能不同的 props 值)通过 ReactDOM.render() 渲染成相同的 DOM 元素,React 将执行 diff 算法,对 DOM 元素进行仅必须的最小更改。也许令人惊讶的是,它每次返回相同的组件实例 - 除了更新的 prop 和 state 值

组件支撑实例是什么?

前两节探讨了 React 元素和 React 组件实例,这两个概念都是 DOM 之上的抽象层。 现在我们将讨论术语“组件支撑实例”,以及它们自身如何与真实 DOM 元素相关联。

// 组件类
class CustomForm extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            inputText: "Willson"
        };

        this.handleInputChange = this.handleInputChange.bind(this);
    }

    handleInputChange(e) {
        const inputText = e.target.value;
        this.setState({ inputText });
    }

    render() {
        return (
            <div className="custom-form">
                <div className="custom-form-header">
                    <p>Hello,{this.state.inputText}</p>
                </div>
                <div className="custom-form-body">
                    <input type="text"
                           value={this.state.inputText}
                           onChange={this.handleInputChange} />
                </div>
            </div>
        );
    }
}

// 组件实例
var componentInstance = ReactDOM.render(<CustomForm />,document.getElementById("root"));

// DOM 实例
var domInstance = ReactDOM.findDOMNode(componentInstance);
// 原文作者这里出了个 Bug,多了一个 D

在前面的实例中,ReactDOM.render() 通过将 React 元素渲染到现有的 DOM 元素中来生成一个组件实例。正如我们已经知道的,组件实例不是真实 DOM 节点。然而,访问与组件实例关联的底层 DOM 节点实际上很简单 - 我们使用 ReactDOM.findDOMNode(),并将组件实例作为其参数传递。那么这与“组件支撑实例”术语有什么关系呢?让我们一脸懵逼的是,React 在其文档的各处将引用的真实 DOM 节点称之为组件支撑实例

总结

这3个术语“React 元素”,“React 组件”和“组件支撑实例”是密切相关的。 由于 JSX 语法被转译为 React.createElement()调用(译者注:理解转译这个概念可以参考 Compiling Vs Transpiling),最终返回我们称之为“React 元素”的 JavaScript 简单对象(plain old JavaScript objects),你可以将 React元素视为基础构建单元。React 组件实例表示下一个抽象层 - ReactDOM.render() 接收一个 React 元素、引用一个真实 DOM 节点、返回一个 React 组件实例。该实例可以访问组件类中定义的方法,但是在单元测试之外很少用到这一点。React 元素和 React 组件实例都不表示真实 DOM 元素。渲染组件实例产生的 DOM 元素被称为组件支撑实例,访问它的主要方式是使用ReactDOM.findDOMNode()

我希望这篇文章能够帮助你理清这些术语!

[参考资料]

猜你在找的React相关文章