前端 - react中使用jsx语法包裹import进来的组件,这过程中发生了哪些事情?

查看:878
本文介绍了前端 - react中使用jsx语法包裹import进来的组件,这过程中发生了哪些事情?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问 题

例如:在A文件中有如下代码

export default class Person extends React.Component {
    constructor(props){
        super(props)
    }
    render(){
        return <div>Hello</div>
    }
}

上面是es6写的Person组件

引用:在B文件中使用Person组件

import Person from './A.jsx'

class Persons extends React.Component{
     constructor(props){
        super(props)
    }
    render(){
        return (
            <div>
                <Person />
            </div>
        )
    }
}   

问题:
1.react中使用jsx语法包裹import进来的组件(这里是把Person变为<Person/>),这过程中发生了哪些事情?
2.react有没有隐式的使用new Person

解决方案

其实呢,jsx语法中,react并不是用new的形式来创建组件,而是使用React.createElement来创建组件的,所以当你在使用

    <Person />

这种语法来书写组件时,其实解析出来的形式为:

    React.createElement(Person,null,null)

而我们写:

    <div>这里是文字</div>

最终编译解析成:

     React.createElement('div',null,'这里是文字')

而如果你需要往person里面添加一些props的属性,jsx的语法为:

    <Person 
        name='Jack'
    />

而解析出来的语法为:

     React.createElement(Person,{name : 'jack'},null)

而当我们div之间有多个嵌套的最终解析会如何,例如下面的写法:

    <div>
        <h2>这里是标题</h2>
        <p>这里是内容</p>
    </div>

而jsx最终解析为:

     React.createElement('div',null,React.createElement('h2',null,'这里是标题'),React.createElement('p',null,'这里是内容'))

React文档中提到,React.createElement方法提供三个参数:

    React.createElement(
      type,                          
      [props],
      [...children]
    )

第一个参数为组件的类型,小写则为原生的提供的组件,大写则为自定义的组件
第二个参数为传入的props
第三个参数则为children,传入的为子元素的解析

而这三个参数可以完美适应所有的jsx的书写方式,另附react官方文档:
React Without JSX

附录2:React.createElement方法的源码,

//createElement 方法的源码
ReactElement.createElement = function (type, config, children) {
  var propName;

  // Reserved names are extracted
  var props = {};

  var key = null;
  var ref = null;
  var self = null;
  var source = null;

  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;
    // Remaining properties are added to a new props object
    for (propName in config) {
      if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
        props[propName] = config[propName];
      }
    }
  }

  // Children can be more than one argument, and those are transferred onto
  // the newly allocated props object.
  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 (process.env.NODE_ENV !== 'production') {
      if (Object.freeze) {
        Object.freeze(childArray);
      }
    }
    props.children = childArray;
  }

  // Resolve default props
  if (type && type.defaultProps) {
    var defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }
  if (process.env.NODE_ENV !== 'production') {
    if (key || ref) {
      if (typeof props.$$typeof === 'undefined' || props.$$typeof !== REACT_ELEMENT_TYPE) {
        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);
};

//最终返回的ReactElement,顺便附带注释吧
/**
 * Factory method to create a new React element. This no longer adheres to
 * the class pattern, so do not use new to call it. Also, no instanceof check
 * will work. Instead test $$typeof field against Symbol.for('react.element') to check
 * if something is a React Element.
 *
 * @param {*} type
 * @param {*} key
 * @param {string|object} ref
 * @param {*} self A *temporary* helper to detect places where `this` is
 * different from the `owner` when React.createElement is called, so that we
 * can warn. We want to get rid of owner and replace string `ref`s with arrow
 * functions, and as long as `this` and owner are the same, there will be no
 * change in behavior.
 * @param {*} source An annotation object (added by a transpiler or otherwise)
 * indicating filename, line number, and/or other information.
 * @param {*} owner
 * @param {*} props
 * @internal
 */
var ReactElement = function (type, key, ref, self, source, owner, props) {
  var element = {
    // This tag allow us to uniquely identify this as a React Element
    $$typeof: REACT_ELEMENT_TYPE,

    // Built-in properties that belong on the element
    type: type,
    key: key,
    ref: ref,
    props: props,

    // Record the component responsible for creating this element.
    _owner: owner
  };

  if (process.env.NODE_ENV !== 'production') {
    // The validation flag is currently mutative. We put it on
    // an external backing store so that we can freeze the whole object.
    // This can be replaced with a WeakMap once they are implemented in
    // commonly used development environments.
    element._store = {};

    // To make comparing ReactElements easier for testing purposes, we make
    // the validation flag non-enumerable (where possible, which should
    // include every environment we run tests in), so the test framework
    // ignores it.
    if (canDefineProperty) {
      Object.defineProperty(element._store, 'validated', {
        configurable: false,
        enumerable: false,
        writable: true,
        value: false
      });
      // self and source are DEV only properties.
      Object.defineProperty(element, '_self', {
        configurable: false,
        enumerable: false,
        writable: false,
        value: self
      });
      // Two elements created in two different places should be considered
      // equal for testing purposes and therefore we hide it from enumeration.
      Object.defineProperty(element, '_source', {
        configurable: false,
        enumerable: false,
        writable: false,
        value: source
      });
    } else {
      element._store.validated = false;
      element._self = self;
      element._source = source;
    }
    if (Object.freeze) {
      Object.freeze(element.props);
      Object.freeze(element);
    }
  }

  return element;
};

看看这个其实就可以理解了

这篇关于前端 - react中使用jsx语法包裹import进来的组件,这过程中发生了哪些事情?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆