深入理解jsx

616 阅读2分钟

这是我参与8月更文挑战的第20天,活动详情查看:8月更文挑战

什么是jsx

JSX是JavaScript XML,是一种JavaScript的语法扩展,运用于React架构中,其格式比较像是模版语言,但事实上完全是在JavaScript内部实现的。元素是构成React应用的最小单位,JSX就是用来声明React当中的元素,React使用JSX来描述用户界面。

JSX在编译时会被Babel编译为React.createElement方法。

React.createElement

代码为 react 源码中的createElement,React.createElement最终会调用ReactElement方法返回一个包含组件数据的对象,该对象有个参数$$typeof: REACT_ELEMENT_TYPE标记了该对象是个React Element`。

export function createElement(type, config, children) {
  let propName;
  const props = {};

  let key = null;
  let ref = null;
  let self = null;
  let source = null;

  if (config != null) {
    // 将 config 处理后赋值给 props
    // ...省略
  }

  const childrenLength = arguments.length - 2;
  // 处理 children,会被赋值给props.children
  // ...省略

  // 处理 defaultProps
  // ...省略

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

const ReactElement = function(type, key, ref, self, source, owner, props) {
  const element = {
    // 标记这是个 React Element
    $$typeof: REACT_ELEMENT_TYPE,

    type: type,
    key: key,
    ref: ref,
    props: props,
    _owner: owner,
  };

  return element;
};

React提供了验证合法React Element的全局API React.isValidElement

export function isValidElement(object) {
  return (
    typeof object === 'object' &&
    object !== null &&
    object.$$typeof === REACT_ELEMENT_TYPE
  );
}

$$typeof === REACT_ELEMENT_TYPE的非null对象就是一个合法的React Element。换言之,在React中,所有JSX在运行时的返回结果(即React.createElement()的返回值)都是React Element

React Component

React中,我们常使用ClassComponentFunctionComponent构建组件。

class AppClass extends React.Component {
  render() {
    return <p>KaSong</p>
  }
}
console.log('这是ClassComponent:', AppClass);
console.log('这是Element:', <AppClass/>);


function AppFunc() {
  return <p>KaSong</p>;
}
console.log('这是FunctionComponent:', AppFunc);
console.log('这是Element:', <AppFunc/>);

由于

AppClass instanceof Function === true;

AppFunc instanceof Function === true;

所以无法通过引用类型区分ClassComponentFunctionComponentReact通过ClassComponent实例原型上的isReactComponent变量判断是否是ClassComponent

JSX与Fiber节点

JSX是一种描述当前组件内容的数据结构,他不包含组件schedulereconcilerender所需的相关信息。

比如如下信息就不包括在JSX中:

  • 组件在更新中的优先级
  • 组件的state
  • 组件被打上的用于Renderer标记

这些内容都包含在Fiber节点中。所以,在组件mount时,Reconciler根据JSX描述的组件内容生成组件对应的Fiber节点。 在update时,ReconcilerJSXFiber节点保存的数据对比,生成组件对应的Fiber节点,并根据对比结果为Fiber节点打上标记

总结

JSX作为描述组件内容的数据结构,为JS赋予了更多视觉表现力,是javascript的一种语言扩展,具备js的能力,且可以插入变量、进行一些运算等。看起来和html很像,需要借助Babel转换。

fiber是把整个更新过程碎片化,在每个小任务执行完成之后,把执行权交还给主线程,这样唯一的线程就不会被独占,让其他的任务依然有运行的机会。