构建 react - jsx

调试准备

调试项目使用 vite 搭建,进行 react 开发环境调试,所以使用的所有 react 方法都是 dev 方法。

vite.config.js 复制代码
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import path from "path";

export default defineConfig({
  plugins: [react()],
  resolve: {
    // 配置别名,导入 react 时从本地代码导入。
    alias: {
      react: path.resolve(__dirname, "./src/react"),
      shared: path.resolve(__dirname, "./src/shared"),
      "react-dom": path.resolve(__dirname, "./src/react-dom"),
      scheduler: path.resolve(__dirname, "./src/scheduler"),
      "react-reconciler": path.resolve(__dirname, "./src/react-reconciler"),
    },
  },
});
jsconfig.json 复制代码
{
  "compilerOptions": {
    "baseUrl": "./",
    
    // 配置路径
    "paths": {
      "react/*": ["src/react/*"],
      "react-dom/*": ["src/react-dom/*"],
      "scheduler/*": ["src/scheduler/*"],
      "shared/*": ["src/shared/*"],
      "react-reconciler/*": ["src/react-reconciler/*"]
    }
  },
  "exclude": ["node_modules", "dist"]
}

jsx 执行流程

graph LR A["用户编写 JSX"] --> B["Babel 编译"] B --> C["执行 React 运行时"]

babel 编译结果

js 复制代码
// jsx 代码
const element = (
  <h1>
    hello <span>test</span> children
  </h1>
);

// 编译结果 删除静态标记
import { jsxDEV as _jsxDEV } from "react/jsx-dev-runtime";

const element = _jsxDEV("h1", {
  children: [
    "hello ",
    _jsxDEV("span", { children: "test" }, undefined, false, { fileName: "example.jsx", lineNumber: 1, columnNumber: 15 }, this),
    " children"
  ]
}, undefined, true, { fileName: "example.jsx", lineNumber: 1, columnNumber: 1 }, this);

由编译结果代码可知,babel 编译完成后,会自动从react/jsx-dev-runtime 中获取 jsxDEV 函数。之前配置调试环境时,将react 文件夹指向 src/react,所以需要实现 src/react

实现

首先实现 jsx-dev-runtime 文件,这个文件在源码中功能很简单,只是导出函数。

jsx-dev-runtime.js 复制代码
export { jsxDEV } from "./src/jsx/ReactJSXElement";

实现 jsxDEV 函数

jsxDEV 函数的功能很明确,根据参数生成虚拟 DOM 并返回。

由编译后代码可知 jsxDEV 函数接受两个参数。

  • type 组件名(h1 div)
  • config 属性
js 复制代码
import hasOwnProperty from "shared/hasOwnProperty";
import { REACT_ELEMENT_TYPE } from "shared/ReactSymbols";

// 保留属性,不加入 props
const RESERVED_PROPS = {
  key: true,
  ref: true,
  __self: true,
  __source: true,
};

function hasValidKey(config) {
  return config.key !== undefined;
}

function hasValidRef(config) {
  return config.ref !== undefined;
}

function ReactElement(type, key, ref, props) {
  // 虚拟DOM
  return {
    $$typeof: REACT_ELEMENT_TYPE,
    type, // 组件名称 h1 span
    key, // key
    ref, // ref
    props, // 属性对象 children id style
  };
}

export function jsxDEV(type, config) {
  let propName; // 属性名
  let props = {}; // 属性对象
  let key = null; // 唯一标识
  let ref = null; // 引用,对应真实DOM

  // 传入的配置中 key 值有效才赋值给 key
  if (hasValidKey(config)) {
    key = config.key;
  }
  
  // 传入的配置中的 ref 有效才赋值给 ref
  if (hasValidRef(config)) {
    ref = config.ref;
  }

  // 遍历传入配置中的字段,如果字段是 config 本身的属性
  // 且字段不为保留属性,则赋值给 props
  for (propName in config) {
    if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
      props[propName] = config[propName];
    }
  }

  // 根据处理后的数据,生成虚拟 DOM
  return ReactElement(type, key, ref, props);
}
shared/hasOwnProperty 复制代码
const { hasOwnProperty } = Object.prototype;

export default hasOwnProperty;
shared/ReactSymbols 复制代码
export const REACT_ELEMENT_TYPE = Symbol.for("react.element");

结束

以上就是 react 中的 jsx 处理。

相关推荐
LaughingZhu20 分钟前
Product Hunt 每日热榜 | 2026-05-21
前端·人工智能·经验分享·chatgpt·html
怕浪猫26 分钟前
Electron 开发实战(一):从零入门核心基础与环境搭建
前端·electron·ai编程
小鹏linux1 小时前
Ubuntu 22.04 部署开源免费具有精美现代web页面的Casdoor账号管理系统
linux·前端·ubuntu·开源·堡垒机
前端若水2 小时前
会话管理:创建、切换、删除对话历史
前端·人工智能·python·react.js
Bigger2 小时前
mini-cc:一个轻量级 AI 编程助手的诞生
前端·ai编程·claude
涵涵(互关)2 小时前
Naive-ui树型选择器只显示根节点
前端·ui·vue
BY组态3 小时前
Ricon组态系统最佳实践:从零开始构建物联网监控平台
前端·物联网·iot·web组态·组态
BY组态3 小时前
Ricon组态系统vs传统组态软件:为什么选择新一代Web组态平台
前端·物联网·iot·web组态·组态
SoaringHeart3 小时前
Flutter进阶:OverlayEntry 插入图层管理器 NOverlayZIndexManager
前端·flutter
放下华子我只抽RuiKe53 小时前
React 从入门到生产(四):自定义 Hook
前端·javascript·人工智能·深度学习·react.js·自然语言处理·前端框架