原文 : React Components, Elements, and Instances


The difference between components and their instances and elements bothers many React beginners. Why are there three different terms for things on the screen?


Manage instances

If you’re new to React, you’ve probably only used component classes and instances before. For example, you declare a Button by creating a class. During app execution, you’ll get several instances of this component on the screen, each with its own properties and local state. This is traditional object-oriented programming. So why introduce elements?

In traditional UI patterns, you create and destroy child component instances yourself. If a Form component wants to render a Button component, it needs to create its own instance and keep it up to date manually.

class Form extends TraditionalObjectOrientedView {
  render() {
    // Read some data passed to the view
    const { isSubmitted, buttonText } = this.attrs;

    if(! isSubmitted && !this.button) {
      // Form is not yet submitted. Create the button!
      this.button = new Button({
        children: buttonText,
        color: 'blue'
      });
      this.el.appendChild(this.button.el);
    }

    if (this.button) {
      // The button is visible. Update its text!
      this.button.attrs.children = buttonText;
      this.button.render();
    }

    if (isSubmitted && this.button) {
      // Form was submitted. Destroy the button!
      this.el.removeChild(this.button.el);
      this.button.destroy();
    }

    if (isSubmitted && !this.message) {
      // Form was submitted. Show the success message!
      this.message = new Message({ text: 'Success! ' });
      this.el.appendChild(this.message.el); }}}Copy the code

The above is the pseudo-code for the Form component, but this is more or less the end result of your composing UI code that uses a library such as BackBone to achieve consistent behavior in an object-oriented manner.

Each component instance must maintain references to its DOM nodes and child component instances, and create, update, and destroy them when appropriate. Lines of code grow to the square of the number of possible states a component can have, and the parent component has direct access to its child component instances, making it difficult to decouple them in the future.

So, how is React different?

Describe trees in terms of elements

In React, this is where the element comes into play. An element is a generic object that describes a component instance or DOM node and its required properties. It contains only information about the component type (for example, button), attributes (for example, color), and some of its children.

Elements aren’t actual instances, but a way to tell React what you want to see on screen. Elements we cannot call any of the above methods, because it is simply a description of an immutable object, there are two fields: type: (string | ReactClass) and props: object.

{
  type: 'button'.props: {
    className: 'button button-blue'.children: {
      type: 'b'.props: {
        children: 'OK! '}}}}Copy the code

This element is just a way of representing the following HTML as a normal object:

<button class='button button-blue'>
  <b>
    OK!
  </b>
</button>
Copy the code

Notice how the elements are nested. By convention, when we create an element tree, we specify one or more child elements as the children attribute of the element it contains.

Importantly, both child and parent elements are descriptions, not real instances. When you create them, they don’t point at anything on the screen. You can create them and throw them away without any other effect.

React elements are easy to walk through, don’t require parsing, and they’re much lighter than actual DOM elements — because they’re just objects!

The component element

In fact, the element type can also be a function or class corresponding to the React component, as follows:

{
  type: Button,
  props: {
    color: 'blue'.children: 'OK! '}}Copy the code

That’s the core idea of React.

Elements that describe components are also elements, just like elements that describe DOM nodes. They can be nested and mixed with each other.

This feature lets you define a DangerButton component as a Button that can have a specific color property without worrying about the Button rendering into a DOM < Button >, a

, or any other element.
const DangerButton = ({ children }) = > ({
  type: Button,
  props: {
    color: 'red'.children: children
  }
});
Copy the code

You can group the DOM elements and component elements in an element tree:

const DeleteAccount = (a)= > ({
  type: 'div'.props: {
    children: [{
      type: 'p'.props: {
        children: 'Are you sure? '}}, {type: DangerButton,
      props: {
        children: 'Yep'}}, {type: Button,
      props: {
        color: 'blue'.children: 'Cancel'}}});Copy the code

Or, if you prefer to use the JSX notation:

const DeleteAccount = (a)= > (
  <div>
    <p>Are you sure?</p>
    <DangerButton>Yep</DangerButton>
    <Button color='blue'>Cancel</Button>
  </div>
);
Copy the code

This mixing and matching helps to keep components decoupled because they can express “inheritance” and “dependency” relationships only by composition:

  • ButtonIt’s a particular propertyDOM < Button >.
  • DangerButtonIt’s a particular propertyButton.
  • DeleteAccountindivContains oneButtonAnd aDangerButton.

A component encapsulates a tree of elements

When React sees an element with a function or class type, it knows to ask the component which element to render and give the appropriate attributes.

When React sees this element:

{
  type: Button,
  props: {
    color: 'blue'.children: 'OK! '}}Copy the code

React will ask the Button what it should render. Button will then return the following element:

{
  type: 'button'.props: {
    className: 'button button-blue'.children: {
      type: 'b'.props: {
        children: 'OK! '}}}}Copy the code

React will repeat this process until it knows the underlying DOM tag element for each component on the page.

React is like being a kid, when you explain every “X is Y” to them and ask “what’s Y?” Until they figure out every little thing in the world.

Remember the Form mentioned above? It can be written as follows using React:

const Form = ({ isSubmitted, buttonText }) = > {
  if (isSubmitted) {
    // Form submitted! Return a message element.
    return {
      type: Message,
      props: {
        text: 'Success! '}}; }// Form is still visible! Return a button element.
  return {
    type: Button,
    props: {
      children: buttonText,
      color: 'blue'}}; };Copy the code

That’s it. For the React component, the input is the attribute and the output is the element tree.

The returned element tree can contain elements describing DOM nodes and elements describing other components. This allows you to compose UI parts that are independent of each other, without relying on their internal DOM structure.

We use React to create, update, and destroy instances, describing them in the elements returned from the component, and React manages those instances.

Components can be classes or functions

In the code above, Form, Message, and Button are React components. They can either be written as functions like the code above, or as classes inherited from React.ponent. These three ways of declaring components are equivalent.

// 1) As a function of props
const Button = ({ children, color }) = > ({
  type: 'button'.props: {
    className: 'button button-' + color,
    children: {
      type: 'b'.props: {
        children: children
      }
    }
  }
});

// 2) Using the React.createClass() factory
const Button = React.createClass({
  render() {
    const { children, color } = this.props;
    return {
      type: 'button'.props: {
        className: 'button button-' + color,
        children: {
          type: 'b'.props: {
            children: children } } } }; }});// 3) As an ES6 class descending from React.Component
class Button extends React.Component {
  render() {
    const { children, color } = this.props;
    return {
      type: 'button'.props: {
        className: 'button button-' + color,
        children: {
          type: 'b'.props: {
            children: children } } } }; }}Copy the code

When a component is defined as a class, it is more powerful than a function component. It can store some local state and perform custom logic when the corresponding DOM node is created or destroyed.

A function component is less powerful, but simpler, and resembles a class component with a single render() method. Unless you need features that are only available in classes, we encourage you to use function components.

However, both function and class components are essentially components of React. They take attributes as input and return elements as output.

Top-down coordination algorithm

When you call:

ReactDOM.render({
  type: Form,
  props: {
    isSubmitted: false.buttonText: 'OK! '}},document.getElementById('root'));
Copy the code

React will ask the Form component what element tree it returns based on these attributes. It will gradually “refine” its understanding of the component tree to get to simpler terms:

// React: You told me this...
{
  type: Form,
  props: {
    isSubmitted: false.buttonText: 'OK! '}}// React: ... And Form told me this...
{
  type: Button,
  props: {
    children: 'OK! '.color: 'blue'}}// React: ... and Button told me this! I guess I'm done.
{
  type: 'button'.props: {
    className: 'button button-blue'.children: {
      type: 'b'.props: {
        children: 'OK! '}}}}Copy the code

This is part of the React call coordination algorithm procedure, which is triggered by calls to reactdom.render () and setState(). At the end of the coordination, React knows the resulting DOM tree, and a renderer like React-DOM or React-Native updates to the DOM node with the set of minimum changes required (in the case of React Native, platform-specific views are applied).

This progressive parsing process is what makes the React application so easy to optimize. If some part of the component tree is too large for React to access effectively. If the relevant properties have not changed, you can tell it to skip this “detail” and only diffing certain parts of the component tree. If these attributes are immutable, calculating whether they change is very fast, so React and immutability work well together and can provide optimal optimization with minimal effort.

You may have noticed that this blog post focuses on components and elements, not instances. The truth is that instances in React are much less important than most object-oriented UI frameworks.

Only components declared as classes have instances, and you never create them directly. React does that for you. Since mechanisms for parent component instances to access child component instances already exist, they are only used for necessary operations (such as setting the focus of a field) and should generally be avoided.

React is responsible for creating one instance of each class component, so components can be written in an object-oriented way using methods and native state, but otherwise, instances aren’t very important in the React programming model and are managed by React itself.

conclusion

An element is a generic object that describes what you want to display on the screen based on a DOM node or other component. Elements can include other elements in their attributes. Creating a React element is easy. Once an element is created, it does not change.

Components can be declared in several different ways. It can be a class with a render() method. Or in the simple case, you can define it as a function. In both cases, it accepts attributes as input and returns a tree of elements as output.

When a component receives attributes as input, it becomes a specific parent component, returning an element, its type, and those attributes. That’s why people say these properties flow in one direction: from father to son.

An instance is an instance referenced to this in the component class you wrote. It is useful for storing local state and responding to life cycle events.

Function components have no instances. Class components have instances, but you don’t need to create component instances directly – React takes care of that.

Finally, elements can be created using react.createElement (), JSX, or the Element Factory Helper. Don’t write elements as plain objects in the actual code – know that they are plain objects hidden underneath.

Develop reading

  • Introduce React element
  • Simplify React element
  • React(virtual)DOM terminology

For security reasons, all React element objects require an extra field -? Typeof: Symbol. For (‘react.element’) declaration. This is the missing part of the above. This article uses inline objects for elements to let you know what’s going on underneath, but unless you add? Typeof, or change the code to use React.createElement () or JSX, otherwise the code will not run in the default logic.