This article documents some of the knowledge learned during the learning process of react17.0.2 source code.

Entrance to the directory

  • react-main

    • packages

      • react

        • index.js

1. React.Com ponent and React. PureComponent

  • directory

    • react-main

      • packages

        • react

          • src

            • ReactBaseClasses.js

  • Define the Component

/**
 * 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;
}
Copy the code
  • isReactComponentCheck whether it is the React Component
Component.prototype.isReactComponent = {};
Copy the code
  • definesetStatefunction

The partialState argument can be object or function, and finally the callback function is executed via updater.enqueuesetState.

Component.prototype.setState = function(partialState, callback) { 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.', ); this.updater.enqueueSetState(this, partialState, callback, 'setState'); };Copy the code
  • defineforceUpdatefunction

State changes in redux state management, forcing render on the page through the forceUpdate function.

Component.prototype.forceUpdate = function(callback) {
  this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
};
Copy the code
  • definePureComponent
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;
}
Copy the code
  • Relationship between Component and PureComponent

Create a ComponentDummy class and assign the Component stereotype to ComponentDummy

PureComponent prototype inherits from an instance of ComponentDummy, new ComponentDummy()

Thus, the PureComponent class inherits from the Component class in the original form

PureComponent has a shouldComponentUpdate lifecycle built in.

function ComponentDummy() {}
ComponentDummy.prototype = Component.prototype;


const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());
pureComponentPrototype.constructor = PureComponent;


Object.assign(pureComponentPrototype, Component.prototype);
pureComponentPrototype.isPureReactComponent = true;
Copy the code

2. React.createElement & React.createFactory & React.cloneElement & React.isValidElement

  • directory

    • react-main

      • packages

        • react

          • src

            • ReactElement.js
  • ReactElement handles the attributes of the incoming element and assembles a React element

const ReactElement = function(type, key, ref, self, source, owner, Function (props) {const element = {// $$typeof symbolFor('react. Element ') $$typeof: REACT_ELEMENT_TYPE, type: // Props => {id: 1, text: props => {id: 1, text: props => {id: 1, text: props => _owner: owner,} if (__DEV__) {// Element._store = {}; DefineProperty (Element._store, 'validated', {enumerable: false, writable: disables and controls different information. 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, }); if (Object.freeze) { Object.freeze(element.props); Object.freeze(element); } } return element; }Copy the code
  • createElementUsed to generate the React element
/** * Create and return a new ReactElement of the given type. */ export function createElement(type, config, children) { let propName; // Reserved names are extracted const props = {}; let key = null; let ref = null; let self = null; let source = null; // The createElement attribute passed in is not null if (config! If (hasValidRef(config)) {Ref = config.ref; if (__DEV__) { warnIfStringRefCannotBeAutoConverted(config); If (hasValidKey(config)) {Key = "+ config.key; } self = config.__self === undefined ? null : config.__self; source = config.__source === undefined ? null : config.__source; for (propName in config) { if ( hasOwnProperty.call(config, propName) && ! RESERVED_PROPS.hasOwnProperty(propName) ) { props[propName] = config[propName]; }}} // Children may be multiple arguments 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( type, key, ref, self, source, ReactCurrentOwner.current, props, ); }Copy the code

The final output of the JS object element

{$$typeof: symbolFor('react.element'), // react element key: config.key, // key attribute is used to coordinate diff ref: Config. Ref, / / ref attribute is used to capture the rendered DOM node props: {children: / / {} {} | [],... }, type: 'div', // element type _owner: null, // who is responsible for creating this element, default is Fiber _store: null, // dev environment made backup _self: null, _source: null }Copy the code
  • createFactoryCreate a factory method of type type
/** * Return a function that produces ReactElements of a given type. */ 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; }Copy the code
  • cloneElementClone using the element as the starting point and return a new ReactElement
/**
 * Clone and return a new ReactElement using element as the starting point.
 * See https://reactjs.org/docs/react-api.html#cloneelement
 */
export function cloneElement(element, config, children) {

}
Copy the code
  • isValidElementVerifies that an object is a valid ReactElement element
/** * Verifies the object is a ReactElement. */ export function isValidElement(object) { return ( typeof object === 'object' && object ! == null && object.$$typeof === REACT_ELEMENT_TYPE ); }Copy the code

3. React.Children

  • React. Children is a handle provided by Reactthis.props.childrenMethod, whether this.props. Chilren isundefined.object(a child),arrayThe React.Children method will return the React node.
<script type="text/jsx"> var List = React.createClass({ render: function() { return ( <ul> { React.Children.map(this.props.children, function (child) { return <li>{child}</li>; }) } </ul> ); }}); React.render( <List> <span>hello</span> <span>world</span> </List>, document.body ); </script>Copy the code
  • React.children. Map traverses this. Props.Children returns an HTML structure

  • React.children. ForEach traverses this.props. Children without returning a value

  • React.children. count returns the sum of the Children elements of this.props

<List> <span>hello</span> <span>world</span> </List> console.log(React.Children.count(this.props.children)); // 2 <List></List> console.log(React.Children.count(this.props.children)); // 0 <List>null</List> console.log(React.Children.count(this.props.children)); / / 1Copy the code
  • React.Children.only

    • Returns the only child in this.props. Children. Otherwise, an exception is thrown.

    • The only child, the only method, can take only one object, not multiple objects (arrays).

4. React.createRef

  • directory

    • react-main

      • packages

        • react

          • src

            • ReactCreateRef.js
  • CreateRef creates a reference object that is a member of the parent component that can operate on its children

// an immutable object with a single mutable value export function createRef(): RefObject { const refObject = { current: null, }; If (__DEV__) {// Seal the Object (you cannot add or delete attributes, configure attributes, but can assign values to attributes) object.seal (refObject); } return refObject; }Copy the code

5. React.createContext

  • createContextCreate a context object with Provide and Consumer properties
export function createContext<T>(defaultValue: T): ReactContext<T> { const context: ReactContext<T> = { $$typeof: REACT_CONTEXT_TYPE, _currentValue: defaultValue, _currentValue2: defaultValue, _threadCount: 0, Provider: (null: any), Consumer: (null: any), }; context.Provider = { $$typeof: REACT_PROVIDER_TYPE, _context: context, }; let hasWarnedAboutUsingNestedContextConsumers = false; let hasWarnedAboutUsingConsumerProvider = false; let hasWarnedAboutDisplayNameOnConsumer = false; if (__DEV__) { const Consumer = { $$typeof: REACT_CONTEXT_TYPE, _context: context, }; Object.defineProperties(Consumer, { Provider: { get() { if (! hasWarnedAboutUsingConsumerProvider) { hasWarnedAboutUsingConsumerProvider = true; return context.Provider; }, set(_Provider) { context.Provider = _Provider; }, }, _currentValue: { get() { return context._currentValue; }, set(_currentValue) { context._currentValue = _currentValue; }, }, _currentValue2: { get() { return context._currentValue2; }, set(_currentValue2) { context._currentValue2 = _currentValue2; }, }, _threadCount: { get() { return context._threadCount; }, set(_threadCount) { context._threadCount = _threadCount; }, }, Consumer: { get() { if (! hasWarnedAboutUsingNestedContextConsumers) { hasWarnedAboutUsingNestedContextConsumers = true; } return context.Consumer; }, }, displayName: { get() { return context.displayName; }, set(displayName) { if (! hasWarnedAboutDisplayNameOnConsumer) { hasWarnedAboutDisplayNameOnConsumer = true; ,}}}}); context.Consumer = Consumer; } else { context.Consumer = context; } if (__DEV__) { context._currentRenderer = null; context._currentRenderer2 = null; } return context; }Copy the code

6. React.lazy

7. React.memo

Refer to the article

React Hook createContext & useContext cross-component passthrough context and performance optimization