Their “self-introductions.”

React Element


React Element is the smallest unit for building a React application. It is a lightweight description of a DOM element that ends up being transformed into a pure JavaScript object. The React Element object contains a few basic attributes such as:


  • type: the type of the element, either a string (e.g. ‘div’, ‘span’, etc. HTML elements) or a React component.

  • props: contains the attributes of the element, as well as the data passed to the child element.

  • key: an optional string that must be unique between sibling elements, used to help identify the element’s stability during re-rendering.


React Element is immutable; once created, you can’t change its contents or properties. If the interface needs to be updated, React creates a new Element and efficiently updates the DOM by comparing the old and the new Elements if necessary. Therefore, you can think of React Element as pure data structures describing the structure of the interface, which are the components of the virtual DOM that are used to ultimately generate the real DOM structure. This design allows React to efficiently update the interface by comparing and re-rendering Elements without directly manipulating the DOM.

// <div classname="snail-run">snailRun</div>;
{
  '$$typeof'Symbol(react.transitional.element),
  type: 'div',
  key: null,
  props: { classname: 'snail-run', children: 'snailRun' },
  _owner: null,
  _store: {}
}

React Component


React Component are separate, reusable chunks of code that make up a React application. They are essentially JavaScript functions or classes that return React Element . Components can take input (called props ) and return React Element . There are two types of components: function components and class components. Function components are generally cleaner and support hooks, and they can also be the first argument to React.createElement , which is the type field. In our day-to-day development of React projects, the most common component we write is React Component , so we’ll write about the simplest function and class components:

function AppFunc() {
  return <div>snailRun</div>;
}
class AppClass extends React.Component {
  render() {
    return <div>snailRun</div>;
  }
}

JSX


JSX is a syntax extension (syntactic sugar) that looks a lot like XML or HTML . JSX It provides a more intuitive way to describe the UI, and it allows developers to write tag language in JavaScript code. During compilation, JSX is converted to the standard JavaScript object, React Elements , the JSX example code:

<div classname="name">snailRun</div>

Fiber


Fiber is a new internal architecture for enhancing React’s capabilities, particularly in animation, layout, and interrupted rendering. Fiber First introduced at React 16 , the architecture addresses the problem of unbreakable recursive updates in previous versions of React by breaking up rendering into smaller units, and after each small portion of work, handing control back to the browser to let the browser handle the rest of the work, such as animation, layout, and input response. This ability is called “interruptible rendering” Fiber, as a static data structure, stores a lot of information, much like a JSX data structure, but it stores a lot more. It’s essentially an abstraction of a unit of work that represents what React needs to do to build and update the DOM. Each React Element corresponds to a Fiber node, and the structure of the application can be thought of as a giant Fiber tree.

 Diff Algorithm


When a component’s state or properties change, React needs to decide whether to update the DOM or not. React uses the **Diff algorithm** to compare the old and new fiber trees and mark and prioritize the Fiber nodes that need to be added, deleted, or updated, and then commits the changes to the DOM, a process called Reconciliation (orchestration).


The Diff algorithm identifies the parts that need to be updated and generates the appropriate actions to update the DOM.This approach ensures that only the parts that have actually changed are re-rendered, optimizing performance.


Trivia >> The difference between first-screen rendering and updating is whether or not there is a diff algorithm in the process of creating the fiber tree

 Look at the source code.


Let’s take a look at the compilation result of JSX. First of all, let’s write a JSX code without adding any plugin, we can see that the error is reported, because originally JavaScript doesn’t know how to compile JSX.


We’ll add a transform-react-jsx plugin at this point by sliding left to the bottom and clicking on add plugin .


We can see that the JSX syntax was successfully compiled, and our left side was compiled to become the right side, which results in the JSX result:


So let’s now see what the result of compiling this code is? That is, what does React.createElement do? I helped you find the implementation of React.createElement in the React source code, which is the following code:

/**
 * Create and return a new ReactElement of the given type.
 * See https://reactjs.org/docs/react-api.html#createelement
 */
export function createElement(type, config, children) {
  if (__DEV__) {
    if (!isValidElementType(type)) {
      // This is an invalid element type.
      //
      // We warn in this case but don't throw. We expect the element creation to
      // succeed and there will likely be errors in render.
      let info = '';
      if (
        type === undefined ||
        (typeof type === 'object' &&
          type !== null &&
          Object.keys(type).length === 0)
      ) {
        info +=
          ' You likely forgot to export your component from the file ' +
          "it's defined in, or you might have mixed up default and named imports.";
      }

      let typeString;
      if (type === null) {
        typeString = 'null';
      } else if (isArray(type)) {
        typeString = 'array';
      } else if (type !== undefined && type.$$typeof === REACT_ELEMENT_TYPE) {
        typeString = `<${getComponentNameFromType(type.type) || 'Unknown'} />`;
        info =
          ' Did you accidentally export a JSX literal instead of a component?';
      } else {
        typeString = typeof type;
      }

      console.error(
        'React.createElement: type is invalid -- expected a string (for ' +
          'built-in components) or a class/function (for composite ' +
          'components) but got: %s.%s',
        typeString,
        info,
      );
    } else {
      // This is a valid element type.

      // Skip key warning if the type isn't valid since our key validation logic
      // doesn't expect a non-string/function type and can throw confusing
      // errors. We don't want exception behavior to differ between dev and
      // prod. (Rendering will throw with a helpful message and as soon as the
      // type is fixed, the key warnings will appear.)
      for (let i = 2; i < arguments.length; i++) {
        validateChildKeys(arguments[i], type);
      }
    }

    // Unlike the jsx() runtime, createElement() doesn't warn about key spread.
  }

  let propName;

  // Reserved names are extracted
  const props = {};

  let key = null;
  let ref = null;

  if (config != null) {
    if (__DEV__) {
      if (
        !didWarnAboutOldJSXRuntime &&
        '__self' in config &&
        // Do not assume this is the result of an oudated JSX transform if key
        // is present, because the modern JSX transform sometimes outputs
        // createElement to preserve precedence between a static key and a
        // spread key. To avoid false positive warnings, we never warn if
        // there's a key.
        !('key' in config)
      ) {
        didWarnAboutOldJSXRuntime = true;
        console.warn(
          'Your app (or one of its dependencies) is using an outdated JSX ' +
            'transform. Update to the modern JSX transform for ' +
            'faster performance: https://react.dev/link/new-jsx-transform',
        );
      }
    }

    if (hasValidRef(config)) {
      if (!enableRefAsProp) {
        ref = config.ref;
        if (!disableStringRefs) {
          ref = coerceStringRef(ref, getOwner(), type);
        }
      }

      if (__DEV__ && !disableStringRefs) {
        warnIfStringRefCannotBeAutoConverted(config, config.__self);
      }
    }
    if (hasValidKey(config)) {
      if (__DEV__) {
        checkKeyStringCoercion(config.key);
      }
      key = '' + config.key;
    }

    // Remaining properties are added to a new props object
    for (propName in config) {
      if (
        hasOwnProperty.call(config, propName) &&
        // Skip over reserved prop names
        propName !== 'key' &&
        (enableRefAsProp || propName !== 'ref') &&
        // Even though we don't use these anymore in the runtime, we don't want
        // them to appear as props, so in createElement we filter them out.
        // We don't have to do this in the jsx() runtime because the jsx()
        // transform never passed these as props; it used separate arguments.
        propName !== '__self' &&
        propName !== '__source'
      ) {
        if (enableRefAsProp && !disableStringRefs && propName === 'ref') {
          props.ref = coerceStringRef(config[propName], getOwner(), type);
        } else {
          props[propName] = config[propName];
        }
      }
    }
  }

  // Children can be more than one argument, and those are transferred onto
  // the newly allocated props object.
  const childrenLength = arguments.length - 2;
  if (childrenLength === 1) {
    props.children = children;
  } else if (childrenLength > 1) {
    const childArray = Array(childrenLength);
    for (let i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }
    if (__DEV__) {
      if (Object.freeze) {
        Object.freeze(childArray);
      }
    }
    props.children = childArray;
  }

  // Resolve default props
  if (type && type.defaultProps) {
    const defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }
  if (__DEV__) {
    if (key || (!enableRefAsProp && ref)) {
      const displayName =
        typeof type === 'function'
          ? type.displayName || type.name || 'Unknown'
          : type;
      if (key) {
        defineKeyPropWarningGetter(props, displayName);
      }
      if (!enableRefAsProp && ref) {
        defineRefPropWarningGetter(props, displayName);
      }
    }
  }

  const element = ReactElement(
    type,
    key,
    ref,
    undefined,
    undefined,
    getOwner(),
    props,
  );

  if (type === REACT_FRAGMENT_TYPE) {
    validateFragmentProps(element);
  }

  return element;
}

 Now let me briefly explain the code:

 Parameter Description:


  • type: the type of the element, either a string of HTML tags or a React component (function components and class components)

  • config: a configuration object containing the properties (props) of the element, possibly including special properties such as key and ref.

  • children: child elements, which can be any number of arguments indicating the child nodes of the element.

 Example: React.createElement("div", {classname: "snail-run"}, "snailRun");

 Primary Logic:


  1. Type validation: first check if type is valid. If it is not valid, an error message will be output on the console. The validity check includes whether it is undefined, whether it is an empty object, whether it is an array, and so on.

  2.  Handles configuration objects (config):


    • Handle ref: if there is a ref attribute in the configuration object and the current environment allows ref as an attribute, then add it to the new props object.

    • Handling key: If there is a key attribute in the configuration object, convert it to a string and store it.

    • Copy Other Properties: Copies other properties from the config object to the new props object, ignoring special or reserved properties such as key、ref、__self and __source .
  3.  Handles child elements:


    • If there is only one child element, assign it directly to props.children .

    • If there are multiple child elements, put them into an array and assign them to props.children .

  4. Handling default attributes: If type type has a default attribute ( defaultProps ), populate attributes not explicitly set in props with the default value.


  5. Creating a React Element: Use the ReactElement function to create a new React element, passing in parameters such as type、key、ref、props .


  6. Special type handling: if type is Fragment , the attributes of Fragment will also be validated.

 Differences between development and production environments


The conditional compilation directive at __DEV__ appears several times in the code, which is used to distinguish between development and production environments. In the development environment, more warning and error checking is done to help developers identify potential problems. Summary:


  • createElement The function accepts the arguments, checks them and processes them, and finally returns ReactElement , which means that JSX compiles the result to ReactElement .

  • **JSX ** is the syntactic sugar used to declare elements when writing React components, essentially React.createElement , and eventually JSX is converted to React Element .

 Their relationship


  1. JSX’s relationship to React Element: JSX is a syntactic extension of JavaScript , which looks a lot like HTML . Developers usually use JSX to describe the UI structure. When JSX is compiled, it is converted to React Element . Therefore, you can think of JSX as the syntactic sugar that creates React Element .

  2. React Element vs. React Component: React Element is the smallest building block in a React application, and it is a lightweight description of the component’s output. React Component In turn, it is a separate unit that encapsulates the logic and state that returns React Element . Thus, a component is a container for creating and managing elements.

  3. The relationship between React Element and Fiber nodes: each React Element corresponds internally to a Fiber node, which are the units that actually perform the work.

  4. Relationship between React Component and Fiber: The Fiber architecture, a new orchestration algorithm introduced in the React 16 release, is used to improve the performance and responsiveness of applications. Each React Component corresponds to one or more Fiber nodes at render time. React A unit of work in the Fiber node is typically a node, and React builds and updates the virtual DOM through these units of work.

  5. Diff Algorithm Compare Element Changes: When a component’s state or attributes change, React uses the Diff algorithm to compare the old with the new React Element to determine what needs to be updated.

  6. Fiber’s relationship to the Diff algorithm: Diff The algorithm is the process used in React to compare the differences between the old and new virtual DOMs and determine how to effectively update the real DOM. In the Fiber architecture, the Diff algorithm is used to determine which Fiber nodes need to be changed and which can be preserved. Fiber The architecture allows React to interrupt and resume the Diff process, allowing tasks to be prioritized to optimize performance.

  7. Overall process: When the state or properties of a component change, React re-executes the render function of the component ( React Component ) created by JSX ( React.createElement syntactic sugar) to generate a new React Element . Then, React uses the Diff algorithm to compare the old and new elements, breaks down the changes into small tasks via the **Fiber architecture**, executes these tasks incrementally, generates a new fiber tree, and finally reflects the changes to the real DOM .


To summarize, JSX provides a declarative syntax for generating React Element / React Component (function components or class components), the elements that are exported from React Component . React Component Their lifecycle and state changes are managed through the Fiber schema, while the Fiber schema internally uses the **Diff algorithm** to optimize the update process. These concepts work together to allow React to build user interfaces efficiently and flexibly.

By hbb

Leave a Reply

Your email address will not be published. Required fields are marked *