本次分析的源码采用的是16.4.1的版本

核心接口

图片描述


React.Children

提供了处理 this.props.children 的工具集:

  • map
  • forEach
  • count
  • toArray
  • only

我们先来看看mapChildren做了什么事情


map: mapChildren

图片描述

即当children为空时,返回null;
不为null时调用mapIntoWithKeyPrefixInternal,最终返回一个result数组.
这里说一下,可以通过传入的func对所有子组件进行操作,具体使用方法看下图参数
图片描述

通过配合cloneElement的例子:

class RadioGroup extends Component {
    constructor(props){
        super(props);
    }
    renderChildren(props) {
        return React.Children.map(props.children, (child, index) => {
            if (child.type === RadioOption)
                return React.cloneElement(child, {
                    // 把父组件的props.name赋值给每个子组件
                    name: props.name
                })
            return child
        })
    }
    render() {
        return (
            <div>
                {this.renderChildren(this.props)}
            </div>
        )
    }
}

forEach、count、toArray我们先不看,先看下only


only: onlyChild

图片描述

看注释就能明白了
这个函数会返回第一个children,同时通过isValidElement判断是不是唯一的一个,若不是会报错

因为若只有一个那一定是一个Object对象,否则为一个数组
所以可以通过判断是否为children是不是一个Object对象
我们来看下函数验证一下
图片描述

果然有个一判断是否为Object的条件,剩下两个是判断是否为null和$$typeof是否为element


React.createRef

照旧看下源码
图片描述

这里发现用了Object.seal方法来封闭了refObject,即阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要可写就可以改变,这里说下不可变(immutable)对象的几个好处:

  • 线程安全
  • 易于理解
  • 比可变对象有更高的安全性

createRef是React 16.3 发布的方法
同时还有一个用于高阶组件的forwardRef
基本原理是通过劫持ref并且将之转换成prop实现的
具体使用如下

function HOC(WrappedComponent) {
    class HOC extends React.Component {
        constructor(props){
            super(props);
        }
      render() {
        const {forwardedRef, ...rest} = this.props;
        return <WrappedComponent ref = {forwardedRef} {...rest} />;
      }
    }
    return React.forwardRef((props, ref) => {
        return <HOC {...props} forwardedRef = {ref} />;
    });;
}
class Child extends React.Component{
    constructor(props){
      super(props);
    }
    render(){
      return <input />
    }
}
const LogProps = HOC(Child);

class Father extends React.Component{
    constructor(props){
      super(props);
      this.myRef = React.createRef();
    }
    componentDidMount(){
      console.log(this.myRef.current);
    }
    render(){
      return <LogProps ref = {this.myRef}/>
    }
}

React.Component 和 React.PureComponent

这里是Component
图片描述

这里是PureComponent
图片描述

这里是ComponentDummy
图片描述

这里发现setStateforceUpdate方法挂在Component下,通过一个ComponentDummy的“伪组件”来当作中介,使PureComponent也能访问到setState 和 forceUpdate方法。
细心的可能发现这里有个objectAssign方法,这个方法把Component的原型跟PureComponent的原型合并了,也就是说PureComponent和Component共用了一个原型
图片描述

这里的shouldUseNative()是对原生的assgin方法进行兼容性判断,我把源码贴出来,有兴趣的可以看看
图片描述


createFactory: createFactoryWithValidation

图片描述

createElement: createElementWithValidation

图片描述

在最后我们可以看到有一个判断type === REACT_FRAGMENT_TYPE,这个REACT_FRAGMENT_TYPE是一个可以包裹碎片化元素的组件
React.Fragment包裹碎片化的组件,可以写作

  <>
    ...
  </>
  但可能有的编译器不支持,最好写作
  <React.Fragment>
    ...
  </React.Fragment>

看到现在都没发现render方法的踪影,源码还没读完......

本文固定链接: http://www.js-code.com/react/react_43562.html