react source code analysis 5. JSX & Core api
Video Explanation (efficient learning): Enter learning
Previous articles:
1. Introduction and interview questions
3.react source code architecture
4. Source directory structure and debugging
6.legacy and concurrent mode entry functions
20. Summary & answers to interview questions in Chapter 1
What is virtual Dom
In a word, the dom information and structure are represented by js objects. When updating, the dom corresponding to the updated object is re rendered. This object is the return result of React.createElement()
virtual Dom is a programming method. It is stored in memory in the form of objects. It describes the necessary information of our Dom and synchronizes with the real DOM with modules such as react dom. This process is also called reconciler. This method can declaratively render the corresponding ui state and liberate us from DOM operations, In react, the relevant information of the component tree is stored in the form of fiber tree. When updating, the relevant DOM can be rendered incrementally, so fiber is also a part of the implementation of virtual Dom
Why use virtual Dom
A large number of dom operations are slow, and small updates may cause page rearrangement. js objects are better than in memory and can be processed faster. You can compare the differences between new and old virtual DOMS through diff algorithm, and perform dom changes in batch, asynchronous and minimized to improve performance
In addition, it can cross platform, JSX -- > reactelement object -- > Real node. If there is an intermediate layer, the corresponding processing can be carried out before operating the real node, and the processing results are reflected on the real node. The real node can be a browser environment or a Native environment
Is virtual Dom really fast? In fact, virtual Dom is only fast when updating, but not necessarily fast at the beginning of the application
const div = document.createElement('div'); let str = '' for(let k in div){ str+=','+k } console.log(str)
jsx&createElement
jsx can declaratively describe views and improve development efficiency. It can be converted into the syntax sugar of React.createElement() through babel, which is also an extension of js syntax.
jsx is the render function of ClassComponent or the return value of FunctionComponent. It can be used to represent the content of the component. After babel compilation, it will be compiled into React.createElement. That's why the jsx file declares import React from 'react' (you don't need to import it after react17). You can view the compiled results of jsx on the site
The source code of React.createElement does the following things
- Process config and assign other config values except reserved attributes to props
- Assign children to props.children after processing
- Processing defaultProps
- Calling ReactElement returns a jsx object (virtual DOM)
//ReactElement.js export function createElement(type, config, children) { let propName; const props = {}; let key = null; let ref = null; let self = null; let source = null; if (config != null) { //Process config and assign other config values except reserved attributes to props //... } const childrenLength = arguments.length - 2; //Assign children to props.children after processing //... //Processing defaultProps //... return ReactElement( type, key, ref, self, source, ReactCurrentOwner.current, props, ); } const ReactElement = function(type, key, ref, self, source, owner, props) { const element = { $$typeof: REACT_ELEMENT_TYPE,//Represents a ReactElement type type: type,//class or function key: key,//key ref: ref,//ref attribute props: props,//props _owner: owner, }; return element; };
$$typeof represents the type of component. For example, there is a function in the source code to check whether it is a legal Element, that is, the root object.$$typeof === REACT_ELEMENT_TYPE
//ReactElement.js export function isValidElement(object) { return ( typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE ); }
If the component is ClassComponent, the type is the class itself. If the component is created by FunctionComponent, the type is this function. ClassComponent.prototype.isReactComponent is used in the source code to distinguish the two. Note that components created by class or function must be capitalized first, and then treated as ordinary nodes. Type is a string.
There are no priority, status, effectTag and other tags on the jsx object. These tags are on the Fiber object. During mount, the Fiber is built according to the jsx object. During update, a new workInProgress Fiber is formed according to the comparison between the latest jsx and current Fiber. Finally, the workInProgress Fiber is switched to current Fiber.
render
//ReactDOMLegacy.js export function render( element: React$Element<any>,//jsx object container: Container,//Mount dom callback: ?Function,//Callback ) { return legacyRenderSubtreeIntoContainer( null, element, container, false, callback, ); }
You can see what render does, that is, it calls legacyRenderSubtreeIntoContainer. This function will be explained in the next chapter. Here we focus on the three parameters used by ReactDom.render().
component
//ReactBaseClasses.js function Component(props, context, updater) { this.props = props;//props attribute this.context = context;//Current context this.refs = emptyObject;//ref mounted object this.updater = updater || ReactNoopUpdateQueue;//Updated object } Component.prototype.isReactComponent = {};//Indicates classComponent
In the component function, props, context, refs, updater, etc. are mainly mounted on the current instance, so these can be obtained on the component instance. The main bearer structure of update is updater, which mainly focuses on isReactComponent, which is used to indicate that this component is a class component
Summary: jsx is the syntax sugar of React.createElement. jsx is transformed into React.createElement function through babel. After the execution of React.createElement, jsx object, also known as virtual DOM, is returned. Fiber will compare jsx object with current Fiber to form workInProgress Fiber
pureComponent is also very simple, similar to component. It will inherit the prototype and assign isPureReactComponent
function PureComponent(props, context, updater) { this.props = props; this.context = context; 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};