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
isReactComponent
Check whether it is the React Component
Component.prototype.isReactComponent = {};
Copy the code
- define
setState
function
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
- define
forceUpdate
function
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
- define
PureComponent
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
createElement
Used 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
createFactory
Create 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
cloneElement
Clone 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
isValidElement
Verifies 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 React
this.props.children
Method, whether this.props. Chilren isundefined
.object
(a child),array
The 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
createContext
Create 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