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
Difference between React Component and React Element
提问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 Componentelement
is an Element. It's notan instance ofMyComponent
; rather, it's simply a description of the component instance to be created. It's an object withkey
,props
,ref
andtype
properties. Here,key
andref
arenull
,props
is an empty object, andtype
isMyComponent
.- An instanceof
MyComponent
gets created (and, in the example above, logs itself from its constructor) whenelement
gets rendered. another_element
is also an element, and haskey
,ref
,props
andtype
properties just likeelement
does - but this time the value oftype
is the string"div"
.
MyComponent
(类本身)是一个组件element
是一个元素。这不是一个实例MyComponent
; 相反,它只是对要创建的组件实例的描述。这是一个对象key
,props
,ref
和type
属性。在这里,key
并且ref
有null
,props
是一个空的对象,type
是MyComponent
。- 一个实例的
MyComponent
被创建(并且,在上述例子中,从它的构造记录本身)时element
被呈现。 another_element
也是一个元素,并有key
,ref
,props
和type
刚才一样的属性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 Object
without own methods. It has essentially four properties:
React Element 只是一个Object
没有自己方法的普通 JavaScript 。它主要有四个属性:
type
, aString
representing an HTML tag or a reference referring to a React Componentkey
, aString
to uniquely identify an React Elementref
, a reference to access either the underlying DOM node or React Component Instance)props
(propertiesObject
)
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 type
an 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.createClass
or by extending React.Component
(ES2015). If a React Component is instantiated it expects a props
Object
and returns an instance, which is referred to as a React Component Instance.
自定义 React 组件要么是React.createClass
通过扩展React.Component
(ES2015)创建的,要么是通过扩展创建的。如果一个 React 组件被实例化,它需要一个props
Object
并返回一个实例,它被称为一个 React 组件实例。
A React Component can contain state and has access to the React Lifecycle methods. It must have at least a render
method, 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
type
properties 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,特别是它检测到的变化发生的地方。这有一些性能优势。
createElement
createElement
方法创建 DOM 节点(又名 React 元素)的对象表示。
const element = React.createElement(
'div',
{id: 'login-btn'},
'Login'
)
这里createElement
createElement
接受三个参数
- The tag name (eg. div, span, etc)
- Any attribuites we want the element to have
- The contents of the children of the element (eg. the text that reads
Login
)
- 标签名称(例如 div、span 等)
- 我们希望元素具有的任何属性
- 元素的子元素的内容(例如读取的文本
Login
)
createElement
createElement
调用返回一个对象
{
type: 'div',
props: {
children: 'Login',
id: 'login-btn'
}
}
当它被渲染到 DOM 时(使用ReactDOM.render
ReactDOM.render
),我们将有一个新的 DOM 节点,如下所示:
<div id='login-btn'>Login</div>
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
createElement
invocations 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
setState
orReactDOM.render
is called.
React 组件是一个模板。一个蓝图。全局定义。这可以是函数或类(带有渲染函数)。
如果 react 将类或函数视为第一个参数,它将检查它呈现的元素,给定相应的 props 并继续执行此操作,直到不再
createElement
有将类或函数作为第一个参数的调用.当 React 看到一个具有函数或类类型的元素时,它会咨询该组件以了解它应该返回哪个元素,给定相应的 props。
在此过程结束时,React 将拥有 DOM 树的完整对象表示。这整个过程在 React 中称为 reconciliation,每次触发
setState
或ReactDOM.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 createElement
returns
什么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 Button
component which accepts an onLogin
input and returns a React element.
这里我们有一个Button
组件,它接受一个onLogin
输入并返回一个 React 元素。
- The
Button
component receives anonLogin
method 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
id
attribute.
- 该
Button
组件接收一个onLogin
方法作为其属性。 - 为了将它传递给我们的 DOM 对象表示,我们将它作为第二个参数传递给 createElement,就像我们对
id
属性所做的一样。
回答by jhegedus
Here is my take :
这是我的看法:
Element
is 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 component
then there would be no need for an extra react Element
. The functional component
hierarchy could produce the VDOM tree directly.
如果一切顺利,functional component
那么就不需要额外的反应了Element
。该functional component
层次结构可以直接产生的虚拟域树。
A react Component Instance
hierarchy (tree
) is a "factory", and that factory is parametrized by the props which are fed to the root react Component Instance
and by all the state "stored" anywhere in the Component Instance
tree.
reactComponent Instance
层次结构 ( tree
) 是一个“工厂”,该工厂由馈送到根 react 的 propsComponent Instance
和Component Instance
树中任何位置“存储”的所有状态进行参数化。
So the react Element
is 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 Element
is 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 Element
tree does not get rendered completely if some lifecycle method on the Component Instance
says 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 Elements
are 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 Elements
are 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 PureComponent
s, React won't bother recomputing that subtree.
React 允许您将 UI 定义为在应用程序状态上定义的纯函数。它可以通过在每次状态更改期间计算整个 UI 来实现这一点,但这会很昂贵。元素是计算描述(thunks),如果它们没有改变,而你使用PureComponent
的是s,React 就不会费心重新计算那个子树。
回答by thedarkone
A React Element
is 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 Component
is what you can consider as an object. It has its methods, supports React lifecycles
and 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 Class
is what you call a class. Functionality wise React Class
and React Component
are same. Only syntax is the real change, as React Component
is based on ES6 syntax
. Another major change is the default binding of functions to this is no longer supported unless using arrow functions. Mixins
also are no longer supported as of ES6
.
AReact Class
就是你所说的类。功能明智React Class
且React Component
相同。只有语法才是真正的变化,因为React Component
基于ES6 syntax
. 另一个主要变化是不再支持函数的默认绑定,除非使用箭头函数。Mixins
也不再受支持ES6
。