Difference between React Component and React Element

前端 未结 11 1865
栀梦
栀梦 2020-12-02 07:29

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 element

相关标签:
11条回答
  • 2020-12-02 07:50

    React Elements

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

    • type, a String representing an HTML tag or a reference referring to a React Component
    • key, a String to uniquely identify an React Element
    • ref, a reference to access either the underlying DOM node or React Component Instance)
    • props (properties 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.

    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 Elements may contain child elements and thus are capable of forming element trees, which represent the Virtual DOM tree.

    React Components and React Component Instances

    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.

    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.

    0 讨论(0)
  • 2020-12-02 07:52

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

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

    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.

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

    0 讨论(0)
  • 2020-12-02 07:57

    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.

    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.

    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.

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

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

    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.

    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.

    This concept in Haskell is called "lifting" :

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

    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.

    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 Lampson1 attributed to the late David J. Wheeler:2

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

    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.

    Please correct me if I am missing here something.

    Quoting an IMPORTANT part of user6445533's answer :

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

    THIS IS THE KEY ^^^^

    Element IS NOT VDOM.

    0 讨论(0)
  • 2020-12-02 07:58

    React Elements vs React Components

    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.
    We know the following:
    • A react element describes what we want to see on the screen.
    A more complex way of saying that is:
    • A React element is an object representation of a DOM node.

    _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 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.
    We can create an object representation of a DOM node (aka React element) using the createElement method.
    const element = React.createElement(
      'div',
      {id: 'login-btn'},
      'Login'
      )
    
    Here createElement takes in three arguments
    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)
    The createElement invocation returns an object
    {
      type: 'div',
      props: {
        children: 'Login',
        id: 'login-btn'
      }
    }
    
    When this is rendered to the DOM (using ReactDOM.render), we'll have a new DOM node that looks like this:
    <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 Components

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

    • 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 or ReactDOM.render is called.

    Class-Based Components

    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.

    • 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.

    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

    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>
        );
      }
    }
    
    Function-Based Components
    • 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.

    With 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

    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.

    • The Button component receives an onLogin 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.
    0 讨论(0)
  • 2020-12-02 08:00

    There are three related 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 not the same thing as elements, nor is there a one-to-one relationship between them. To illustrate this, consider this code:

    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
    • element is an Element. It's not an instance of MyComponent; rather, it's simply a description of the component instance to be created. It's an object with key, props, ref and type properties. Here, key and ref are null, props is an empty object, and type is MyComponent.
    • An instance of MyComponent gets created (and, in the example above, logs itself from its constructor) when element gets rendered.
    • another_element is also an element, and has key, ref, props and type properties just like element does - but this time the value of type is the string "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.

    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.

    0 讨论(0)
提交回复
热议问题