React源码 memo Fragment StrictMode cloneElement createFactory
import {REACT_MEMO_TYPE} from 'shared/ReactSymbols'; export default function memo<Props>( type: React$ElementType, compare?: (oldProps: Props, newProps: Props) => boolean, ) { return { $$typeof: REACT_MEMO_TYPE, type, compare: compare === undefined ? null : compare, }; }
就是通过 func component 作为参数传入进来,然后可以传第二个参数,是 oldProps 和 newProps 的一个对比方法,return true or false 来判断他是否需要返回,就跟 shouldupdate 是同样的意思,返回一个对象,里面有 $$typeof,是 REACT_MEMO_TYPE。type 就是传入的 function component,然后 compare就是传入的第二个参数,所以跟之前的 ref , context 是一类的东西,最终实现的逻辑肯定是要到 react-dom 里面去实现,他的目的就是为了跟 PureComponent 类似的功能。
Fragment: REACT_FRAGMENT_TYPE
Fragment 就是一个 Symbole,没有什么特别的意义,Fragment 就是 <>,react 16 之后提供了我们 Fragment 这个几点,他非常方便的告诉 react 这里是有多个兄弟节点的,他本身就是一个 Symbol,没有特别的含义
StrictMode: REACT_STRICT_MODE_TYPE
export function cloneElement(element, config, children) { invariant( !(element === null || element === undefined), 'React.cloneElement(...): The argument must be a React element, but you passed %s.', element, ); let propName; // Original props are copied const props = Object.assign({}, element.props); // Reserved names are extracted let key = element.key; let ref = element.ref; // Self is preserved since the owner is preserved. const self = element._self; // Source is preserved since cloneElement is unlikely to be targeted by a // transpiler, and the original source is probably a better indicator of the // true owner. const source = element._source; // Owner will be preserved, unless ref is overridden let owner = element._owner; if (config != null) { if (hasValidRef(config)) { // Silently steal the ref from the parent. ref = config.ref; owner = ReactCurrentOwner.current; } if (hasValidKey(config)) { key = '' + config.key; } // Remaining properties override existing props let defaultProps; if (element.type && element.type.defaultProps) { defaultProps = element.type.defaultProps; } for (propName in config) { if ( hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName) ) { if (config[propName] === undefined && defaultProps !== undefined) { // Resolve default props props[propName] = defaultProps[propName]; } else { props[propName] = config[propName]; } } } } // Children can be more than one argument, and those are transferred onto // the newly allocated props object. const 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; } return ReactElement(element.type, key, ref, self, source, owner, props); }
const props = Object.assign({}, element.props); 首先他把 props 复制过来,然后把 key 和 ref 也复制过来。这些东西复制过来之后再进行一个处理,其实就是创建一个新的 react element , 整体的过程个你 createElemnt 差不多。只是传入一个 element,他进行一个 clone 这么一个过程。
export function createFactory(type) { const factory = createElement.bind(null, type); // Expose the type on the factory and the prototype so that it can be // easily accessed on elements. E.g. `<Foo />.type === Foo`. // This should not be named `constructor` since this may not be the function // that created the element, and it may not even be a constructor. // Legacy hook: remove it factory.type = type; return factory; }
createFactory 对于写 JSX 的人来说,几乎是不可能用到的,因为 createFactory 是对 createElement 的一个封装。createFactory 其实是 createElement 绑定了一个 type。比如我们要去创建一个 p 标签的节点, p 标签的节点如果使用 javascript 的 api 去创建,那么在使用 createElement 的时候都要先传入 p ,再传入 config ,再传入 children 。我们可以先创建一个 p 标签的 factory ,然后通过这个 factory 返回的方法,我们只需要传入 config,children 就可以创建一个 p 标签。而不需要重复的去传 p。但对于写 jsx 的人来说,没有任何的必要。