Javascript React 组件和 React 元素的区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30971395/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 06:01:01  来源:igfitidea点击:

Difference between React Component and React Element

javascriptreactjs

提问by Hoffmann

What is the difference between React Component and React Element? The documentation mentions both but does not go into detail, some methods require components, other elements...

React Component 和 React Element 有什么区别?文档提到了两者但没有详细说明,一些方法需要组件,其他元素......

回答by Mark Amery

There are threerelated kinds of thing involved here, with their own names:

这里涉及三种相关的事物,它们都有自己的名字:

  • Components
  • Component instances
  • Elements
  • 成分
  • 组件实例
  • 元素

This is slightly surprising, since if you're used to other UI frameworks you might expect that there'd only be two kinds of thing, roughly corresponding to classes (like Widget) and instances (like new Widget()). That's not the case in React; component instances are notthe same thing as elements, nor is there a one-to-one relationship between them. To illustrate this, consider this code:

这有点令人惊讶,因为如果您习惯于其他 UI 框架,您可能会认为只有两种东西,大致对应于类(如Widget)和实例(如new Widget())。在 React 中不是这样。组件实例与元素不是一回事,它们之间也没有一一对应的关系。为了说明这一点,请考虑以下代码:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    console.log('This is a component instance:', this);
  }

  render() {
    const another_element = <div>Hello, World!</div>;
    console.log('This is also an element:', another_element);
    return another_element;
  }
}

console.log('This is a component:', MyComponent)

const element = <MyComponent/>;

console.log('This is an element:', element);

ReactDOM.render(
  element,
  document.getElementById('root')
);

In the code above:

在上面的代码中:

  • MyComponent(the class itself) is a Component
  • elementis an Element. It's notan instance of MyComponent; rather, it's simply a description of the component instance to be created. It's an object with key, props, refand typeproperties. Here, keyand refare null, propsis an empty object, and typeis MyComponent.
  • An instanceof MyComponentgets created (and, in the example above, logs itself from its constructor) when elementgets rendered.
  • another_elementis also an element, and has key, ref, propsand typeproperties just like elementdoes - but this time the value of typeis the string "div".
  • MyComponent类本身)是一个组件
  • element是一个元素。这不是一个实例MyComponent; 相反,它只是对要创建的组件实例的描述。这是一个对象keypropsreftype属性。在这里,key并且refnullprops是一个空的对象,typeMyComponent
  • 一个实例MyComponent被创建(并且,在上述例子中,从它的构造记录本身)时element被呈现。
  • another_element也是一个元素,并有keyrefpropstype刚才一样的属性element那样-但这次的值type是字符串"div"

The design reasons why React has these three distinct concepts are explored in detail in the React team's blog post React Components, Elements, and Instances, which I recommend reading.

React 团队的博客文章React Components、Elements 和 Instances中详细探讨了 React 具有这三个不同概念的设计原因,我推荐阅读。

Finally, it should be noted that while the official docs are rigorous about using the term "component" to refer to a function or class and "component instance" to refer to an instance, other sources do not necessarily adhere to this terminology; you should expect to see "component" used (incorrectly) to mean "component instance" when reading Stack Overflow answers or discussions on GitHub.

最后,应该注意的是,虽然官方文档严格使用术语“组件”来指代函数或类,使用“组件实例”来指代实例,但其他来源不一定遵循此术语;在 GitHub 上阅读 Stack Overflow 答案或讨论时,您应该会看到“组件”使用(错误地)表示“组件实例”。

回答by kunl

To further elaborate on the answer, a React Element does not have any methods and nothing on the prototype. This also makes them fast.

为了进一步详细说明答案,React Element 没有任何方法,原型上也没有任何内容。这也使他们快速。

"A ReactElement is a light, stateless, immutable, virtual representation of a DOM Element" - Glossary of React Terms

“ReactElement 是 DOM 元素的轻量级、无状态、不可变的虚拟表示”——React术语表

A react component render()function returns a DOM tree of react elements behind the scenes (This is the virtual DOM btw). There is some complex mapping and diff logic involved, but basically these React elements map to the DOM elements.

反应组件render()函数在幕后返回反应元素的 DOM 树(顺便说一下,这是虚拟 DOM)。涉及到一些复杂的映射和差异逻辑,但基本上这些 React 元素映射到 DOM 元素。

You can also create a Element directly React.createElement(arg)where arg can be a html tag name, or a React Component class.

你也可以直接创建一个 Element ,React.createElement(arg)其中 arg 可以是一个 html 标签名称,或者一个 React Component 类。

回答by kunl

React Elements

反应元素

A React Element is just a plain old JavaScript Objectwithout own methods. It has essentially four properties:

React Element 只是一个Object没有自己方法的普通 JavaScript 。它主要有四个属性:

  • type, a Stringrepresenting an HTML tag or a reference referring to a React Component
  • key, a Stringto uniquely identify an React Element
  • ref, a reference to access either the underlying DOM node or React Component Instance)
  • props(properties Object)
  • type,String表示 HTML 标签或引用 React 组件的引用
  • key, aString唯一标识一个 React 元素
  • ref,访问底层 DOM 节点或 React 组件实例的引用)
  • props(属性Object

A React Element is not an instance of a React Component. It is just a simplified "description" of how the React Component Instance (or depending on the typean HTML tag) to be created should look like.

React Element 不是 React 组件的实例。它只是type对要创建的 React 组件实例(或取决于HTML 标签)的外观的简化“描述” 。

A React Element that describes a React Component doesn't know to which DOM node it is eventually rendered - this association is abstracted and will be resolved while rendering.

描述 React 组件的 React Element 不知道它最终渲染到哪个 DOM 节点 - 这种关联是抽象的,将在渲染时解析。

React Elements may contain child elements and thus are capable of forming element trees, which represent the Virtual DOM tree.

React Elements 可能包含子元素,因此能够形成代表虚拟 DOM 树的元素树。

React Components and React Component Instances

React 组件和 React 组件实例

A custom React Component is either created by React.createClassor by extending React.Component(ES2015). If a React Component is instantiated it expects a propsObjectand returns an instance, which is referred to as a React Component Instance.

自定义 React 组件要么是React.createClass通过扩展React.Component(ES2015)创建的,要么是通过扩展创建的。如果一个 React 组件被实例化,它需要一个propsObject并返回一个实例,它被称为一个 React 组件实例。

A React Component can contain state and has access to the React Lifecycle methods. It must have at least a rendermethod, which returns a React Element(-tree) when invoked. Please note that you never construct React Component Instances yourself but let React create it for you.

React 组件可以包含状态并可以访问 React Lifecycle 方法。它必须至少有一个render方法,该方法在调用时返回一个 React Element(-tree)。请注意,您永远不会自己构建 React 组件实例,而是让 React 为您创建它。

回答by Ian Warburton

A component is a factory for creating elements.

组件是用于创建元素的工厂。

回答by Nitin Tulswani

React Element- It is a simple object that describes a DOM node and its attributes or properties you can say. It is an immutable description object and you can not apply any methods on it.

React Element- 它是一个简单的对象,它描述了一个 DOM 节点及其你可以说的属性或属性。它是一个不可变的描述对象,您不能对其应用任何方法。

Eg -

例如——

<button class="blue"></button>

React Component- It is a function or class that accepts an input and returns a React element. It has to keep references to its DOM nodes and to the instances of the child components.

React Component- 它是一个接受输入并返回 React 元素的函数或类。它必须保持对 DOM 节点和子组件实例的引用。

const SignIn = () => (
  <div>
   <p>Sign In</p>
   <button>Continue</button>
   <button color='blue'>Cancel</button>
  </div>
);

回答by Vipul

An elementis a plain object describing what you want to appear on the screen in terms of the DOM nodes or other components. Elements can contain other elements in their props. Creating a React element is cheap. Once an element is created, it is never mutated. The object representation of React element would be as follows,

一个元素是描述你要在DOM节点或其他部件方面出现在屏幕上什么平原对象。元素可以在它们的道具中包含其他元素。创建一个 React 元素很便宜。一旦一个元素被创建,它就永远不会发生变异。React 元素的对象表示如下,

const element = React.createElement(
  'div',
  {id: 'login-btn'},
  'Login'
)

The above createElement returns as object as below,

上面的 createElement 作为对象返回如下,

{
  type: 'div',
  props: {
    children: 'Login',
    id: 'login-btn'
  }
}

And finally it renders to the DOM using ReactDOM.render as below,

最后它使用 ReactDOM.render 渲染到 DOM,如下所示,

<div id='login-btn'>Login</div>

Whereas a componentcan be declared in several different ways. It can be a class with a render() method. Alternatively, in simple cases, it can be defined as a function. In either case, it takes props as an input, and returns an element tree as the output. JSX transpiled as createElement at the end.

组件可以用几种不同的方式声明。它可以是带有 render() 方法的类。或者,在简单的情况下,它可以定义为一个函数。在任何一种情况下,它都将 props 作为输入,并返回一个元素树作为输出。最后 JSX 转译为 createElement。

function Button ({ onLogin }) {
  return React.createElement(
    'div',
    {id: 'login-btn', onClick: onLogin},
    'Login'
  )
}

回答by killscreen

React Elements vs React Components

React 元素与 React 组件

React Elements

反应元素

  • A React Element is what gets returned from components. It's an object that virtually describes the DOM nodes that a component represents.
  • With a function component, this element is the object that the function returns.
  • With a class component, the element is the object that the component's render function returns. R
  • React elements are not what we see in the browser. They are just objects in memory and we can't change anything about them.
  • React elements can have other typeproperties other than native HTML elements.
  • React Element 是从组件返回的内容。它是一个虚拟地描述组件所代表的 DOM 节点的对象。
  • 对于函数组件,此元素是函数返回的对象。
  • 对于类组件,元素是组件的渲染函数返回的对象。电阻
  • React 元素不是我们在浏览器中看到的。它们只是内存中的对象,我们无法更改它们的任何内容。
  • React 元素可以具有type除原生 HTML 元素之外的其他属性。
我们知道以下几点:
  • A react element describes what we want to see on the screen.
  • react 元素描述了我们希望在屏幕上看到的内容。
更复杂的说法是:
  • A React element is an object representation of a DOM node.
  • React 元素是 DOM 节点的对象表示。

_It's important to make this distinction here because the element is not the actual thing we see on the screen, rather the object representation is what is rendered.

_在这里进行区分很重要,因为元素不是我们在屏幕上看到的实际事物,而是对象表示是呈现的内容。

React is good with this in these ways:

React 在这些方面做得很好:

  • React can create and destroy these element without much overhead. The JS objects are lightweight and low-cost.
  • React can diff an object with the previous object representation to see what has changed.
  • React can update the actual DOM specifically where the changes it detected occurred. This has some performance upsides.
  • React 可以在没有太多开销的情况下创建和销毁这些元素。JS 对象是轻量级和低成本的。
  • React 可以将一个对象与之前的对象表示进行比较,以查看发生了什么变化。
  • React 可以更新实际的 DOM,特别是它检测到的变化发生的地方。这有一些性能优势。
我们可以使用该createElementcreateElement方法创建 DOM 节点(又名 React 元素)的对象表示。
const element = React.createElement(
  'div',
  {id: 'login-btn'},
  'Login'
  )
这里createElementcreateElement接受三个参数
  1. The tag name (eg. div, span, etc)
  2. Any attribuites we want the element to have
  3. The contents of the children of the element (eg. the text that reads Login)
  1. 标签名称(例如 div、span 等)
  2. 我们希望元素具有的任何属性
  3. 元素的子元素的内容(例如读取的文本Login
createElementcreateElement调用返回一个对象
{
  type: 'div',
  props: {
    children: 'Login',
    id: 'login-btn'
  }
}
当它被渲染到 DOM 时(使用ReactDOM.renderReactDOM.render),我们将有一个新的 DOM 节点,如下所示:
<div id='login-btn'>Login</div>

Huzzah!

哈扎!

Huzzah

胡扎

Generally React is taught from a components-first approach, however understanding elements-first makes for a smooth transition to components.

通常,React 是从组件优先的方法中教授的,但是理解元素优先可以平滑过渡到组件。

React Components

反应组件

A component is a function or a Class which optionally accepts input and returns a React element.

组件是一个函数或一个类,它可以选择接受输入并返回一个 React 元素。

  • A React Component is a template. A blueprint. A global definition. This can be either a function or a class (with a render function).

  • If react sees a class or a function as the first argument, it will check to see what element it renders, given the corresponding props and will continue to do this until there are no more createElementinvocations which have a class or a function as their first argument.

  • When React sees an element with a function or class type, it will consult with that component to know which element it should return, given the corresponding props.

  • At the end of this processes, React will have a full object representation of the DOM tree. This whole process is called reconciliation in React and is triggered each time setStateor ReactDOM.renderis called.

  • React 组件是一个模板。一个蓝图。全局定义。这可以是函数或类(带有渲染函数)。

  • 如果 react 将类或函数视为第一个参数,它将检查它呈现的元素,给定相应的 props 并继续执行此操作,直到不再createElement有将类或函数作为第一个参数的调用.

  • 当 React 看到一个具有函数或类类型的元素时,它会咨询该组件以了解它应该返回哪个元素,给定相应的 props。

  • 在此过程结束时,React 将拥有 DOM 树的完整对象表示。这整个过程在 React 中称为 reconciliation,每次触发setStateReactDOM.render调用。

基于类的组件

Class syntax is one of the most common ways to define a React component. While more verbose than the functional syntax, it offers more control in the form of lifecycle hooks.

类语法是定义 React 组件最常见的方法之一。虽然比函数式语法更冗长,但它以生命周期钩子的形式提供了更多的控制。

  • We can render many instances of the same component.
  • The instance is the "this" keyword that is used inside the class-based component.
  • Is not created manually and is somewhere inside React's memory.
  • 我们可以渲染同一组件的多个实例。
  • 实例是在基于类的组件中使用的“this”关键字。
  • 不是手动创建的,而是在 React 内存中的某个地方。

Create a class component

创建类组件

// MyComponent.js
import React, { Component } from 'react';

class MyComponent extends Component {
  render() {
    return (
      <div>This is my component.</div>
    );
  }
}

export default MyComponent;

Use it in any other component

在任何其他组件中使用它

// MyOtherComponent.js
import React, { Component } from 'react';
import MyComponent from './MyComponent';

class MyOtherComponent extends Component {
  render() {
    return (
      <div>
        <div>This is my other component.</div>
        <MyComponent />
      </div>
    );
  }
}

export default MyOtherComponent;

Use props

使用道具

<MyComponent myProp="This is passed as a prop." />

Props can be accessed with this.props

道具可以通过 this.props

class MyComponent extends Component {
  render() {
    const {myProp} = this.props;
    return (
      <div>{myProp}</div>
    );
  }
}

Using state

使用状态

class MyComponent extends Component {
  render() {
    const {myState} = this.state || {};
    const message = `The current state is ${myState}.`;
    return (
      <div>{message}</div>
    );
  }
}

Using lifecycle hooks

使用生命周期钩子

class MyComponent extends Component {
  // Executes after the component is rendered for the first time
  componentDidMount() {
    this.setState({myState: 'Florida'});
  }

  render() {
    const {myState} = this.state || {};
    const message = `The current state is ${myState}.`;
    return (
      <div>{message}</div>
    );
  }
}
基于函数的组件
  • Do not have instances.
  • Can be rendered multiple times but React does not associate a local instance with each render.
  • React uses the invocation of the function to determine what DOM element to render for the function.
  • 没有实例。
  • 可以多次渲染,但 React 不会将本地实例与每个渲染相关联。
  • React 使用函数的调用来确定要为函数呈现什么 DOM 元素。

With createElement

createElement

function Button ({ addFriend }) {
  return React.createElement(
    "button",
    { onClick: addFriend },
    "Add Friend"
  )
}

function User({ name, addFriend }) {
  return React.createElement(
    "div",
    null,
    React.createElement(
      "p",
      null,
      name
    ),
    React.createElement(Button, { addFriend })
  )
}

With what createElementreturns

什么createElement回报

function Button ({ addFriend }) {
  return {
    type: 'button',
    props: {
      onClick: addFriend,
      children: 'Add Friend'
    }
  }
}

function User ({ name, addFriend }) {
  return {
    type: 'div',
    props: {
      children: [
        {
          type: 'p',
          props: {
            children: name
          }
        },
        {
          type: Button,
          props: {
            addFriend
          }
        }
      ]
    }
  }
}

Here we have a Buttoncomponent which accepts an onLogininput and returns a React element.

这里我们有一个Button组件,它接受一个onLogin输入并返回一个 React 元素。

  • The Buttoncomponent receives an onLoginmethod as its property.
  • To pass that along to our object representation of the DOM, we'll pass it along as the second argument to createElement, just as we did with the idattribute.
  • Button组件接收一个onLogin方法作为其属性。
  • 为了将它传递给我们的 DOM 对象表示,我们将它作为第二个参数传递给 createElement,就像我们对id属性所做的一样。

回答by jhegedus

Here is my take :

这是我的看法:

Elementis the thing that describes how to construct the VDOM. It's basically a "frozen" version of the corresponding Component Instance.

Element是描述如何构建 VDOM 的东西。它基本上是相应Component Instance.

If everything would be functional componentthen there would be no need for an extra react Element. The functional componenthierarchy could produce the VDOM tree directly.

如果一切顺利,functional component那么就不需要额外的反应了Element。该functional component层次结构可以直接产生的虚拟域树。

A react Component Instancehierarchy (tree) is a "factory", and that factory is parametrized by the props which are fed to the root react Component Instanceand by all the state "stored" anywhere in the Component Instancetree.

reactComponent Instance层次结构 ( tree) 是一个“工厂”,该工厂由馈送到根 react 的 propsComponent InstanceComponent Instance树中任何位置“存储”的所有状态进行参数化。

So the react Elementis basically an "abstract syntax tree" which gets compiled into the actual VDOM.

所以反应Element基本上是一个“抽象语法树”,它被编译成实际的 VDOM。

So why not generate the VDOM directly by using the react Component Instances? This is the real question here.

那么为什么不直接使用 react 生成 VDOMComponent Instances呢?这是真正的问题。

At the first glance I don't see why it would not be possible to do so. So most likely the answer is that it's a question of performance.

乍一看,我不明白为什么不能这样做。所以最有可能的答案是,这是一个性能问题。

The react Elementis one layer of abstraction between the VDOM and the Component Instance, why this abstraction is needed is not entirely clear to me, most likely it allows optimizations. For example the Elementtree does not get rendered completely if some lifecycle method on the Component Instancesays that there is no need to render that subtree.

reactElement是 VDOM 和 之间的一层抽象Component Instance,为什么需要这种抽象对我来说并不完全清楚,很可能它允许优化。例如,Element如果某些生命周期方法Component Instance说不需要渲染该子树,则树不会完全渲染。

Now, in this case, the logic which handles this optimization "needs" this extra layer of indirection - because the information needs to be stored somewhere that some part of the VDOM should not be compared with the new VDOM, even more, maybe the new VDOM should not be even calculated at all. So using an extra layer of indirection makes the rendering logic simpler and leads to a cleaner, more maintainable implementation - I imagine.

现在,在这种情况下,处理这种优化的逻辑“需要”这个额外的间接层——因为信息需要存储在某个地方,VDOM 的某些部分不应该与新的 VDOM 进行比较,甚至更多,也许是新的甚至根本不应该计算 VDOM。所以使用额外的间接层使渲染逻辑更简单,并导致更清晰、更易于维护的实现 - 我想。

This concept in Haskell is called "lifting" :

Haskell 中的这个概念称为“提升”:

For example monads in Haskell are perfect examples of such liftings.

例如 Haskell 中的 monad 就是这种提升的完美例子。

A monad is sort of a description of a computation that can be stored as a value, like 42. Similarly, react Elementsare elments of a description on how to compute the "new" VDOM. If somebody wants to compute it.

monad 是一种可以存储为值的计算的描述,例如42. 同样,reactElements是关于如何计算“新”VDOM 的描述元素。如果有人想计算它。

This talk describes this concept of an "extra" indirection with some simple examples:

这个演讲通过一些简单的例子描述了“额外”间接的概念:

In other words : premature optimization is the root of all evil.

换句话说:过早优化是万恶之源。

Or :Fundamental theorem of software engineering

或:软件工程基本定理

The fundamental theorem of software engineering (FTSE) is a term originated by Andrew Koenig to describe a remark by Butler Lampson1attributed to the late David J. Wheeler:2

We can solve any problem by introducing an extra level of indirection.

软件工程基本定理 (FTSE) 是由 Andrew Koenig 提出的一个术语,用于描述巴特勒兰普森的评论1归功于已故的 David J. Wheeler:2

我们可以通过引入额外的间接级别来解决任何问题。

So, in my understanding react Elementsare an implementation detail to handle complexity gracefully and allow some optimization (performance). I don't see why one could not get rid of this extra indirection - in principle - react would still work "just as well" - but it might be super slow, implementing and maintaining the react "engine" itself would be probably a nightmare.

因此,在我的理解中,reactElements是一个实现细节,可以优雅地处理复杂性并允许进行一些优化(性能)。我不明白为什么不能摆脱这种额外的间接性 - 原则上 - react 仍然可以“同样好”地工作 - 但它可能超级慢,实现和维护 react“引擎”本身可能是一场噩梦.

Please correct me if I am missing here something.

如果我在这里遗漏了什么,请纠正我。

Quoting an IMPORTANT part of user6445533's answer :

引用 user6445533 回答的重要部分:

type, a String representing an HTML tag or a reference referring to a React Component

type, 表示 HTML 标签的字符串或引用 React 组件的引用

THIS IS THE KEY ^^^^

这是关键^^^^

Element IS NOT VDOM.

元素不是 VDOM。

回答by Michael Gummelt

Elements are thunks.

元素是 thunk。

React lets you define UIs as pure functions defined on application state. It could implement this by computing the entire UI during each state change, but this would be expensive. Elements are computational descriptions (thunks), and if they don't change, and you're using PureComponents, React won't bother recomputing that subtree.

React 允许您将 UI 定义为在应用程序状态上定义的纯函数。它可以通过在每次状态更改期间计算整个 UI 来实现这一点,但这会很昂贵。元素是计算描述(thunks),如果它们没有改变,而你使用PureComponent的是s,React 就不会费心重新计算那个子树。

回答by thedarkone

A React Elementis what you would consider to be a basic html(dom to be precise) element. It is just a way of creating element without using the much controversial jsx format.

AReact Element是您认为是基本 html(准确地说是 dom)元素的元素。这只是一种无需使用备受争议的 jsx 格式即可创建元素的方法。

A React Componentis what you can consider as an object. It has its methods, supports React lifecyclesand is generally unreusable (at least haven't found any reuse yet, welcome to examples). It necessarily needs to have a render function.

AReact Component是您可以将其视为对象的对象。它有它的方法,支持React lifecycles,并且通常是不可重用的(至少还没有发现任何重用,欢迎示例)。它必然需要具有渲染功能。

A React Classis what you call a class. Functionality wise React Classand React Componentare same. Only syntax is the real change, as React Componentis based on ES6 syntax. Another major change is the default binding of functions to this is no longer supported unless using arrow functions. Mixinsalso are no longer supported as of ES6.

AReact Class就是你所说的类。功能明智React ClassReact Component相同。只有语法才是真正的变化,因为React Component基于ES6 syntax. 另一个主要变化是不再支持函数的默认绑定,除非使用箭头函数。Mixins也不再受支持ES6