数据的源头 —— JSX

著有《React18 设计原理》《javascript地月星》等多个专栏。 欢迎关注。

创作不易,有帮助别忘了点赞,收藏,评论 ~ 你的鼓励是我继续挖干货的动力。
本文全部都是原创内容,商业转载请联系作者获得授权,非商业转载需注明出处,感谢理解 ~
推荐指数(值得一读):⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️

原文 👉 juejin.cn/post/763192...

React.createElement

创建新的 Fiber,new FiberNode 是没有数据的,对于 Fiber 节点的节点类型、样式、事件、子节点等属性一无所知。这些数据来自我们在 JSX 的声明。看一个的例子。

  • 原组件
jsx 复制代码
//LazyComp.jsx
export default function LazyComp() {
  return <h1>✅Hello !</h1>;
}
jsx 复制代码
//App.jsx
const LazyComp = lazy(() => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(import('./LazyComp'));
    }, 2000); // 模拟 2 秒延迟
  });
});
export default function App() {
  return (
    <div>
      <Suspense fallback={<div>Loading...2</div>}>
        <LazyComp />
      </Suspense>
    </div>
  );
}
  • 编译后
js 复制代码
//LazyComp-BtMAPHcf.js
function LazyComp() {
  return /* @__PURE__ */ React.createElement("h1", null, "✅Hello !");
}
js 复制代码
//App-BBcglL-c.js
const LazyComp = lazy( () => {
    return new Promise( (resolve) => {
        setTimeout( () => {
            resolve(import("/dist/assets/LazyComp-BtMAPHcf.js")); //上面的LazyComp本体
        }
        , 8e3);
    }
    );
}
function App() {
  return /* @__PURE__ */
    React.createElement("div", null, /* @__PURE__ */
    React.createElement(Suspense, {
        fallback: /* @__PURE__ */
        React.createElement("div", null, "Loading...2")
    }, /* @__PURE__ */
    React.createElement(LazyComp, null)));
}

function renderWithHooks(current, workInProgress, Component, props, secondArg, nextRenderLanes) {
  ...
  var children = Component(props, secondArg); //function App(){...  return React.createElement('div',{},React.createElement('p',{}, 'xx'))}
  ...
  return children;
}

从内到外的嵌套顺序执行,最里面的 React.createElement(LazyComp, null) 是最先完成的。

按组件单位生成一次 react element。 完成这一步就有信息可以生成这一部分的 Fiber 树了。

Jsx 变成对象后就是 React Element 对象 :

js 复制代码
react ele 节点与它的属性 props

function Comp(){
    return (<div 属性/事件/样式/...>子节点...</div>)
}

var element = {
    $$typeof: REACT_ELEMENT_TYPE,
    type: type, //'div'
    key: key, //null
    ref: ref, //null
    props: props, //props是节点的属性。属性/事件/样式/子节点
    _owner: owner
  };

props = {children, style, onXX, 其他属性}
-   props.children // 子级element
-   props.fallback; // 如果是Suspense,有fallback
-   props.style //样式;
-   props.onXXX //事件
-   props.xxx //其他属性

组件也是这样子的:
<MyComp 属性/事件/样式...></MyComp>
不过我们不会在组件上直接写子节点:
<MyComp 属性/事件/样式...>❌子节点...</MyComp> 不会显示这个子节点。
本来就是按照组件为单位生成子节点,父组件不应该生成 MyComp 组件的子节点的。

代码

js 复制代码
var ReactElement = function (type, key, ref, self, source, owner, props) {
  var element = {
    $$typeof: REACT_ELEMENT_TYPE,
    type: type,
    key: key,
    ref: ref,
    props: props,
    _owner: owner
  };

  {
  
    element._store = {}; 

    //ele._store.validated  不可配置、不可枚举、可写
    Object.defineProperty(element._store, 'validated', {
      configurable: false,
      enumerable: false,
      writable: true,
      value: false
    }); 
    //ele._self  不可配置、不可枚举、不可写、只读
    Object.defineProperty(element, '_self', {
      configurable: false,
      enumerable: false,
      writable: false,
      value: self
    });
    //ele._source  不可配置、不可枚举、不可写、只读
    Object.defineProperty(element, '_source', {
      configurable: false,
      enumerable: false,
      writable: false,
      value: source
    });
    // react ele是只读的 props是children/样式/事件等属性,也是只读的
    // 不可变类型: 不是freeze;没有做任何检查和约束,但是直接设置值不会生效。
    // freeze可以作为不可变的实现。
    // 常量:大写、对象类型的属性也不可变。冻结:state是否也是一个freeze的?不是。  
    if (Object.freeze) {
      Object.freeze(element.props);
      Object.freeze(element);
    }
  }

  return element;
};

//React.createElement(Suspense/'div', {fallback:, style:, onXXX:, key:,}, React.createElement())
function createElement(type, config, children) {
  var propName; 

  var props = {};
  var key = null;
  var ref = null;
  var self = null;
  var source = null;

  // react ele的ref和key 、 react ele的props的其他属性
  if (config != null) {
    // ref
    if (hasValidRef(config)) {
      ref = config.ref;

      {
        warnIfStringRefCannotBeAutoConverted(config);
      }
    }
    // key
    if (hasValidKey(config)) {
      {
        checkKeyStringCoercion(config.key);
      }

      key = '' + config.key;
    }

    // react ele的props的其他属性 style/onXXX/fallback
    self = config.__self === undefined ? null : config.__self;
    source = config.__source === undefined ? null : config.__source;
    for (propName in config) {
      if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
        props[propName] = config[propName];
      }
    }
  } 

  //react ele的props的children=children/[...]
  //children=children单个子节点、children = []多个子节点
  var childrenLength = arguments.length - 2;
  if (childrenLength === 1) {
    props.children = children;
  } else if (childrenLength > 1) {
    var childArray = Array(childrenLength);

    for (var i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }

    {
      if (Object.freeze) {
        Object.freeze(childArray);
      }
    }

    props.children = childArray;
  } 

  // 例如App.defaultProps
  if (type && type.defaultProps) {
    var defaultProps = type.defaultProps;

    for (propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }

  {
    if (key || ref) {
      var displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type;

      if (key) {
        defineKeyPropWarningGetter(props, displayName);
      }

      if (ref) {
        defineRefPropWarningGetter(props, displayName);
      }
    }
  }

  return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props);
}

hooks 的信息也来自 JSX

js 复制代码
function App() {
  // 这些是hooks
  const [isPending, startTransition] = useTransition();
  const [inputValue, setInputValue] = useState("");
  const [list, setList] = useState([]);
  const [show, setShow] = React.useState(false);
  const [show2, setShow2] = React.useState(true);
  
  return /* @__PURE__ */
    React.createElement("div", null, /* @__PURE__ */
    React.createElement(Suspense, {
        fallback: /* @__PURE__ */
        React.createElement("div", null, "Loading...2")
    }, /* @__PURE__ */
    React.createElement(LazyComp, null)));
}
相关推荐
时光足迹3 小时前
Tiptap 简单编辑器模版
前端·javascript·react.js
时光足迹3 小时前
Tiptap编辑器
前端·javascript·react.js
时光足迹3 小时前
电子书阅读器之笔记高亮(跨段处理)
前端·javascript·react.js
空中海5 小时前
03 渲染机制、性能优化与现代 React
javascript·react.js·性能优化
openKaka_8 小时前
为什么 React 18 之后使用 createRoot,而不是 ReactDOM.render
前端·javascript·react.js
老王以为9 小时前
从源码到架构:React useActionState 深度剖析
前端·javascript·react.js
天蓝色的鱼鱼10 小时前
当AI开始替我写代码,我还要纠结选Vue还是React吗?
vue.js·react.js·ai编程
空中海1 天前
01 React Native 基础、核心组件与布局体系
javascript·react native·react.js