1. react 学习 JSX

181 阅读2分钟

什么是jsx

JSX 是 JavaScript XML 的缩写,它允许我们在 JavaScript 代码中直接编写类似 HTML 的语法,从而更直观地描述 UI 结构。

react 中的 jsx

在 React 中,JSX 语法会被编译成 React.createElement 或 jsx 函数调用。这个编译过程通常是通过 Babel 等工具实现的。这种编译结果生成了一个描述 UI 结构的对象,而 React 使用这些对象来构建和更新 DOM。

const element = <h1>Hello, world!</h1>;
// 编译后结果
const element = /*#__PURE__*/ React.createElement('h1', null, 'Hello, world!');
// 或
import { jsx as _jsx } from 'react/jsx-runtime';
const element = /*#__PURE__*/ _jsx('h1', {
  children: 'Hello, world!'
});

jsx 两个部分

编译时: 编译时由babel实现 运行时: 实现 jsx 或 React.createElement 两个方法, 但最终的效果是相同的:创建一个描述 UI 的对象(React 元素)两个方法返回类下面的数据结构描述 UI。

const REACT_ELEMENT_TYPE = Symbol.for('react.element');

function ReactElement(type, key, ref, props) {
  const element = {
    // 特殊的标识符,用于标识这是一个 React 元素
    $$typeof: REACT_ELEMENT_TYPE,
    
    // 元素的类型,可以是字符串(HTML 标签)或函数(React 组件)
    type,
    
    // 元素的唯一标识符(可选),用于优化 React 的调和过程
    key,
    
    // 引用,通常用于访问或操作 DOM 元素(可选)
    ref,
    
    // 元素的属性
    props,
    
    // 自定义字段 实现时与 真实的ReactElement 区分
    _owner: '_Yzj' // 这里的 '_Yzj' 只是一个示例,占位符,实际中是 Fiber 节点
  };
  return element;
}

实现 JSX 方法

  1. React.createElement 方法

const RESERVED_PROPS = {
  key: true,
  ref: true,
};

function createElement(type, config, ...children) {
  const props = {};

  let key = null;
  let ref = null;

  if (config != null) {
    if (config.ref !== undefined) {
      ref = config.ref;
    }
    if (config.key !== undefined) {
      key = '' + config.key;
    }

    for (const propName in config) {
      if (Object.prototype.hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
        props[propName] = config[propName];
      }
    }
  }

  if (children.length === 1) {
    props.children = children[0];
  } else if (children.length > 1) {
    props.children = children;
  }

  return ReactElement(type, key, ref, props);
}
  1. jsx 方法

React 17 引入了新的 JSX 转换方式,不再需要显式导入 React。新的转换方式使用两个新的自动导入函数:jsx 和 jsxs。jsx 用于创建没有子元素或只有一个子元素的元素,而 jsxs 用于创建有多个子元素的元素

const element = <h1>Hello, world! <span>1233</span></h1>;
// 转化后的结果
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
const element = /*#__PURE__*/_jsxs("h1", {
  children: ["Hello, world! ", /*#__PURE__*/_jsx("span", {
    children: "1233"
  })]
});
  1. jsx

    function jsx(
      type: string | Function,
      config: Props,
      maybeKey?: Key
    ): ReactElement {
      const props: Props = {};
      let key: Key = null;
      let ref: Ref = null;
    
      if (maybeKey !== undefined) {
        key = '' + maybeKey;
      }
    
      if (config != null) {
        if (config.ref !== undefined) {
          ref = config.ref;
        }
        if (config.key !== undefined) {
          key = '' + config.key;
        }
    
        for (const propName in config) {
          if (
            Object.prototype.hasOwnProperty.call(config, propName) &&
            !RESERVED_PROPS.hasOwnProperty(propName)
          ) {
            props[propName] = config[propName];
          }
        }
      }
    
      return ReactElement(type, key, ref, props);
    }
    
  2. jsxs

    function jsxs(
      type: string | Function,
      config: Props,
      maybeKey?: Key
    ): ReactElement {
      const props: Props = {};
      let key: Key = null;
      let ref: Ref = null;
    
      if (maybeKey !== undefined) {
        key = '' + maybeKey;
      }
    
      if (config != null) {
        if (config.ref !== undefined) {
          ref = config.ref;
        }
        if (config.key !== undefined) {
          key = '' + config.key;
        }
    
        for (const propName in config) {
          if (
            Object.prototype.hasOwnProperty.call(config, propName) &&
            !RESERVED_PROPS.hasOwnProperty(propName)
          ) {
            props[propName] = config[propName];
          }
        }
      }
    
      const childrenLength = arguments.length - 2;
      if (childrenLength === 1) {
        props.children = arguments[2];
      } else if (childrenLength > 1) {
        const childArray = Array(childrenLength);
        for (let i = 0; i < childrenLength; i++) {
          childArray[i] = arguments[i + 2];
        }
        props.children = childArray;
      }
    
      return ReactElement(type, key, ref, props);
    }