本次分析的源码采用的是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
这里发现setState 和 forceUpdate方法挂在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方法的踪影,源码还没读完......