一、基础
1. React API
看一下 React 暴露出来的 API:
const React = {Children: {map,forEach,count,toArray,only,},createRef,Component,PureComponent,createContext,forwardRef,lazy,memo,Fragment: REACT_FRAGMENT_TYPE,StrictMode: REACT_STRICT_MODE_TYPE,Suspense: REACT_SUSPENSE_TYPE,createElement: __DEV__ ? createElementWithValidation : createElement,cloneElement: __DEV__ ? cloneElementWithValidation : cloneElement,createFactory: __DEV__ ? createFactoryWithValidation : createFactory,isValidElement: isValidElement,version: ReactVersion,__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: ReactSharedInternals,};
Children
官方提供的一些用于处理 props.children 的方法
createRef
新的ref用法,React即将抛弃 <div ref="myDiv" /> 这种 string ref 的用法,将来你只能使用两种方式来使用 ref
class App extends React.Component{constructor() {this.ref = React.createRef()}render() {return <div ref={this.ref} />// orreturn <div ref={(node) => this.funRef = node} />}}
或者使用函数组件
const App = () => {const inputEl = useRef(null)return (<input ref={inputEl} type="text" />)}
Component & PureComponent
这两个类基本相同,唯一的区别是PureComponent的原型上多了一个标识
if (ctor.prototype && ctor.prototype.isPureReactComponent) {return (!shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState));}
这是检查组件是否需要更新的一个判断,ctor 就是你声明的继承自 Component or PureComponent 的类,他会判断你是否继承自 PureComponent,如果是的话就 shallowEqual 比较 state 和 props
PureComponent优点
继承PureComponent的组件,若state和props前后不改变,则不重新渲染。
Component优点
灵活性大,可以自由根据实际情况在shouldComponentUpdate生命周期中进行优化
createElement & cloneElement & createFactory & isValidElement
createElement
它可谓是 React 中最重要的 API 了,他是用来创建 ReactElement 的,但是多数人却从没见过也没用过,这是为啥呢?因为你用了 JSX,JSX 并不是标准的 js,所以要经过编译才能变成可运行的 js,而编译之后,createElement 就出现了:
// jsx<div id="app">content</div>// jsReact.createElement('div', { id: 'app' }, 'content')
cloneElement
用于克隆一个 ReactElement
createFactory
是专门用来创建某一类 ReactElement 的工厂
isValidElement
用来验证是否是一个 ReactElement新的ref用法,React即将抛弃
2. React Element
该部分详细源码如下:
/*** 创建并返回指定类型的 ReactElement* @param {*} type - 可以是标签名字符串(如 'div' 或 'span'),也可以是 React 组件类型(class 组件或函数组件),或是 React fragment 类型* @param {*} config - 配置项,标签的 attribute* @param {*} children - 子元素*/export function createElement(type, config, children) {let propName;// Reserved names are extractedconst props = {};let key = null;let ref = null;let self = null;let source = null;if (config != null) {// 单独处理 key 和 refif (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// 存储除内置 props 外的其他 propsfor (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.// 将一个或多个 children,即第三个及以后的参数,处理后赋值给 props.childrenconst childrenLength = arguments.length - 2;if (childrenLength === 1) {props.children = children;} else if (childrenLength > 1) {const childArray = Array(childrenLength);for (let i = 0; i < childrenLength; i++) {childArray[i] = arguments[i + 2];}props.children = childArray;}// Resolve default props// 若该类型存在默认的 props, 并且未进行配置,则按默认的进行赋值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 = {// This tag allows us to uniquely identify this as a React Element// 用于标示 element 是什么类型$$typeof: REACT_ELEMENT_TYPE,// Built-in properties that belong on the elementtype: type,key: key,ref: ref,props: props,// Record the component responsible for creating this element._owner: owner,};return element;};
3. React Component
class Welcome extends React.Component {constructor(props) {super(props)this.state = {}}componentDidMount(){}render() {return <h1>Hello, {this.props.name}</h1>;}}
以上是我们使用类组件时的常见使用方式,主要使用 Component 和 PureComponent 这两个基类,该部分详细源码如下:
React.component
/*** Copyright (c) Facebook, Inc. and its affiliates.** This source code is licensed under the MIT license found in the* LICENSE file in the root directory of this source tree.*/import invariant from 'shared/invariant';import lowPriorityWarning from 'shared/lowPriorityWarning';import ReactNoopUpdateQueue from './ReactNoopUpdateQueue';const emptyObject = {};if (__DEV__) {Object.freeze(emptyObject);}/*** Base class helpers for the updating state of a component.*/function Component(props, context, updater) {this.props = props;this.context = context;// If a component has string refs, we will assign a different object later.this.refs = emptyObject;// We initialize the default updater but the real one gets injected by the// renderer.this.updater = updater || ReactNoopUpdateQueue;}// 给 Components 赋值以做标记Component.prototype.isReactComponent = {};/*** 给 Component 的原型增加 setState-更新状态 方法* @param {object|function} partialState - 更新的状态值, 可以对象或函数,将和当前 state 合并,生成下一个状态* @param {?function} callback - 回调函数,用于 state 更新完成后执行的回调函数*/Component.prototype.setState = function(partialState, callback) {// 判断 partialState 是否符合条件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.',);// 这里是 state 更新机制的重点// 具体实现在 react-dom 中,不在 reactthis.updater.enqueueSetState(this, partialState, callback, 'setState');};/*** 给 Component 的原型增加 forceUpdate-强制更新 方法,用于强制更新场景,无论 props 和 state 是否改变* @param {?function} callback - 回调函数,用于更新完成后执行的回调函数*/Component.prototype.forceUpdate = function(callback) {this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');};
重点:
- Component() 方法本质是一个类,多用于继承
- setState() 和 forceUpdate 是 Component 原型上的方法,其本质是调用 ReactNoopUpdateQueue.js 中的 enqueueSetState() 方法
- React.Component() 只涉及了props、context、refs、updater、isReactComponent、setState、forceUpdate,其他均没有自己实现
React.PureComponent
如果一个组件的渲染只依赖于外界传进去的 props 和自己的 state,而并不依赖于其他的外界的任何数据,也就是说像纯函数一样,给它什么,它就吐出(渲染)什么出来。这种组件的复用性是最强的。这里的 PureComponent 便是如此使用的,它只有在 props 或 state 改变时才会重新渲染 ```javascript // 通过借用构造函数,实现典型的寄生组合式继承,避免原型污染 function ComponentDummy() {} ComponentDummy.prototype = Component.prototype;
/**
- Convenience component with default shallow equality check for sCU. */ function PureComponent(props, context, updater) { this.props = props; this.context = context; // If a component has string refs, we will assign a different object later. this.refs = emptyObject; this.updater = updater || ReactNoopUpdateQueue; }
const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy()); pureComponentPrototype.constructor = PureComponent; // 无须再通过原型链再向上找一级. Object.assign(pureComponentPrototype, Component.prototype); pureComponentPrototype.isPureReactComponent = true;
export {Component, PureComponent};
```
重点:
1. 借助空方法 ComponentDummy 使用典型的寄生组合式继承方式,避免原型污染
2. 使用 Object.assign(pureComponentPrototype, Component.prototype) 复制prototype,便可以不用再去 Component 的原型中找方法,减少了一次原型链的查找
参考:
https://segmentfault.com/a/1190000019783986?utm_source=tag-newest
https://www.cnblogs.com/heyushuo/p/10057676.html
