react源码学习(一)从JSX到React element

一. 体验jsx: https://babeljs.io/repl

const App = () => {
  return 
App
} //转化结果 "use strict"; var App = function App() { return React.createElement("div", null, "App"); };

注意到的是我们的JSX最终转化成为的是React.createElement这个方法:

  • 第一个参数是字符串类型或者组件或者symbol,
    • 代表的是标签元素, 如div, span
    • classComponent或者是functional Component,
    • 原生提供的Fragment, AsyncMode等, 会被特殊处理
  • 第二个参数是一个对象类型, 代表标签的属性, id, class
  • 其余的参数代表的是children,不涉及grand-children,当子节点中有孙节点的时候, 再递归使用React.createElement方法
const App = () => {
  return 
span
} "use strict"; var App = function App() { return React.createElement( "div", {id: "app",key: "key"}, React.createElement("section", null, React.createElement("img", null) ), React.createElement("span", null, "span")); };

当第一个参数是组件的时候,第一个参数是作为变量传入的, 可以想像的是, React.createElement内部有一个简单的判断, 如果传入的是组件的话, 内部还会调用React.createElement方法

const Child = () => {
	return 
Child
} const App = () => { return
} "use strict"; var Child = function Child() { return React.createElement("div", null, "Child"); }; var App = function App() { return React.createElement( "div", {id: "app"}, React.createElement(Child, null)); //这里 };

需要注意的是如果组件开头是一个小写的话, 会被解析成简单的字符串,在运行的时候就会报错

二. React.createElement
我们的createElement方法定义在packages/src/ReactElement.js

export function createElement(type, config, children) {
  let propName;
  const props = {};
  
  let key = null;
  let ref = null;
  let self = null;
  let source = null;
   
   // ref和key和其他props不同, 进行单独处理
  if (config != null) {
    if (hasValidRef(config)) {
      ref = config.ref;
    }
    if (hasValidKey(config)) {
      key = '' + config.key;
    }

    self = config.__self === undefined ? null : config.__self;
    source = config.__source === undefined ? null : config.__source;
    //将属性名挂载到props上
    for (propName in config) {
      if (
        hasOwnProperty.call(config, propName) &&
        !RESERVED_PROPS.hasOwnProperty(propName)
      ) {
        props[propName] = config[propName];
      }
    }
  }
  //第三个及以上的参数都被看作是子节点
  const childrenLength = arguments.length - 2;
  if (childrenLength === 1) {
    props.children = children;
  } else if (childrenLength > 1) {
    //当数组长度确定时,这种方式比push要节省内存  
    const childArray = Array(childrenLength);
    for (let i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }
    props.children = childArray; 
  // merge defaultProps
  if (type && type.defaultProps) {
    const defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }
  return ReactElement(
    type,
    key,
    ref,
    self,
    source,
    ReactCurrentOwner.current,
    props,
  );
}

ReactElement定义如下

const ReactElement = function(type, key, ref, self, source, owner, props) {
  const element = {
    // 每个react element的$$typeof属性都是REACT_ELEMENT_TYPE
    $$typeof: REACT_ELEMENT_TYPE, // react element的内置属性
    type: type,
    key: key,
    ref: ref,
    props: props,
    _owner: owner, //创建该元素的component
  };
  return element;
};

总的来说就是返回一个react element, 该element带有props, refs, type

3. component和pureComponent

和React.Component相关的文件放在react/ReactBaseClasses.js中
updater是和平台相关的,react dom 平台和react native平台setState后需要走的流程都是不一样的

function Component(props, context, updater) {
  this.props = props;
  this.context = context;
  //初始化refs和updater,后面会被覆写
  this.refs = emptyObject;
  this.updater = updater || ReactNoopUpdateQueue;
}

Component.prototype.isReactComponent = {};

常用的setState方法

Component.prototype.setState = function(partialState, callback) {
  invariant( //错误提醒
    typeof partialState === 'object' ||
      typeof partialState === 'function' ||
      partialState == null,
    'setState(...): takes an object of state variables to update or a ' +
      'function which returns an object of state variables.',
  );
  //重点代码
  this.updater.enqueueSetState(this, partialState, callback, 'setState');
};

Component.prototype.isReactComponent = {};

PureComponent只是实现了对Component的简单继承(详情参加<高程>一书),并且添加了isPureReactComponent属性

function ComponentDummy() {}
ComponentDummy.prototype = Component.prototype;
function PureComponent(props, context, updater) {
  this.props = props;
  this.context = context;
  this.refs = emptyObject;
  this.updater = updater || ReactNoopUpdateQueue;
}
const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());
pureComponentPrototype.constructor = PureComponent;
Object.assign(pureComponentPrototype, Component.prototype);

pureComponentPrototype.isPureReactComponent = true;

你可能感兴趣的:(react,JSX)