This is the 15th day of my participation in the August More text Challenge. For details, see: August More Text Challenge
Virtual dom
What is the virtual DOM
The virtual DOM is a programming concept in which the UI is stored in memory in an idealized, or ‘virtual,’ representation and is synchronized with the ‘real’ DOM through libraries such as ReactDom, a process called coordination.
DOM information and structure are represented by JavaScript objects, and the JavaScript object structure is rerendered when the state changes. This JavaScript object is called a Virtual DOM
Why use the virtual DOM
DOM operations are slow, and even minor operations can cause pages to be reformatted, which can be very performance consuming. Compared to DOM objects, JS objects are faster and simpler to process. The DIFF algorithm compares the differences between the old and new VDOMS, and can be used to perform DOM operations in batches and minimize, thus improving performance.
jsx
What is the JSX
- Syntactic sugar
- React uses JSX instead of regular JavaScript.
- JSX is a JavaScript syntax extension that looks a lot like XML.
Why do YOU need JSX
- Development efficiency: Writing templates using JSX is simple and fast.
- Execution efficiency: JSX is optimized for faster execution when compiled into JavaScript code.
- Type safety: Errors can be found during compilation.
React 16 and React 17 use difference
React 16 Babel-Loader precompiles JSX to React. CreateElement (…)
React 17 JSX conversion does not convert JSX to React. CreateElement. Instead, it automatically introduces new entry functions from the React package and calls them. In addition, this upgrade will not change the JSX syntax, and the old JSX conversions will continue to work
fiber
- Processing time slice
- Linked list structure js object
- Object
Some key keys for fiber
Fiber {stateNode: current dom node tag: current dom node value type: string, tag type, eg:'div' child: first sibling: next sibling,}Copy the code
How to use ReactDOM rendering
- JSX: Direct render,
- Function components: Directly execute functions,
- Class component: instantiates and then calls render()
Components is a class or function Component. The Component prototype. IsReactComponent = {}
Implement reactDom manually
Create a file with create-react-app and open the index.js file
import ReactDOM from './kreact/react-dom';
const jsx=(
<div>
<h1>learn react</h1>
<p>k-react</p>
<a href='https://learn.kaikeba.com/video/411409'>this is a link</a>
<FunctionComponent name='functionComponent' />
<>
<p>Fragments</p>
</>
<App name='react component'/>
</div>
)
ReactDOM.render(
jsx,
document.getElementById('root')
);
Copy the code
Create the kreact file and create the React-dom JS file.
ReactDOM.render()
ReactDOM.render(element, container[, callback])
Copy the code
On the first call, all DOM elements in the container node are replaced, and subsequent calls are efficiently updated using React’s DOM Diffing algorithm.
If an optional callback function is provided, the callback will be executed after the component has been rendered or updated.
Return a render function
import {scheduleUpdateOnFiber} from './ReactFiberWorkloop'; function render(element, container) { console.log('react-dom', element); console.log('container', container.nodeName); / / set the root fiber node const FiberRoot = {type: the container. The nodeName. ToLowerCase (), props: {children: element}, stateNode: container, }; scheduleUpdateOnFiber(FiberRoot); } export default {render};Copy the code
The react operation to create a reactFiberworkloop JS file to process the node is based on the Scheduler to notify us when the browser has time left. Here we through the browser API, window. RequestIdleCallback (callback [options]), can return to the browser’s free time
Why doesn’t React use requestIdleCallback
- Browser Compatibility
- The trigger frequency is unstable and affected by many factors. For example, when our browser switches tabs, the previous TAB is registered
requestIdleCallback
The frequency of the trigger will become very low
import {isStr} from './utils'; import {updateHostCompose} from './ReactFiberReconclier'; // Let wipRoot = null; // Let wipRoot = null; // Let nextUnitOfWork = null; Export function scheduleUpdateOnFiber(fiber) {wipRoot = fiber; nextUnitOfWork = wipRoot; / / start from root fiber} update/update/processing node function workloop (IdleDeadline) {while (nextUnitOfWork && IdleDeadline. TimeRemaining () > 0) { nextUnitOfWork = performUnitOfWork(nextUnitOfWork); } // requestIdleCallback(workloop); Function performUnitOfWork(wip) {const {type} = wip; If (isStr(type)) {// represents the native tag updateHostCompose(wip); } // Return the next task to be updated, depth first traversal if (wip.child) {return wip.child; } // Let next = wip; // Let next = wip; // Let next = wip; If (next) {if (next. Sibling) {// sibling sibling node return next. Sibling; } next = next.return; } return null; // The parent of next is obtained by next. }Copy the code
Different components are updated differently, creating a reactFiberReconclier.js file
import { isStr,isArray} from "./utils"; Import {createFiber} from './createFiber' export function updateNodeOne(node,nextVal) { Object.keys(nextVal).forEach(k=>{ if(k === 'children'){ if(isStringOrNumber(nextVal[k])) { node.textContent = nextVal[k]; }else if(k.ice (0,2) === 'on'){const eventName = k.ice (2).tolocalelowercase (); node.addEventListener(eventName, nextVal[k]); }else{ node[k] = nextVal[k]; } // Export function updateHostCompose(wip){if(! Wip.statenode){// First render, no real dom wip.statenode = document.createElement(wip.type); updateNodeOne(wip.stateNode,wip.props); // reconcileChildren(wip,wip.props. Children); // reconcileChildren(wip,wip.props. } // export function updateFunctionCompose(wip){// return const {type,props} = wip; const children = type(props); // reconcileChildren(WIP) reconcileChildren(Children); updateNodeOne(wip.stateNode,wip.return.props); Export function updateClassCompose(wip){// function children is called, return const {type,props} = wip; const instance = new type(props); const children = instance.render(); // reconcileChildren(WIP) reconcileChildren(Children); // updateNodeOne(wip.stateNode,wip.return.props); Export function updateFragmentsCompose(wip){// Coordinate the child node, It is diff console.log('======45',wip) reconcileChildren(wip,wip.props. Children); } // Handle the children reconcileChildren(returnFiber,children) from the parent node to the parent node Let previousNewFiber = null; If (isStr(children)){// if a text node returns; } const newChildren = isArray(children) ? children :[children]; for(let i =0; i<newChildren.length; i++){ const newChild = newChildren[i]; Const newFiber = createFiber(newChild,returnFiber) if(previousNewFiber === null){ ReturnFiber. Child = newFiber} else {previousNewFiber. Sibling = newFiber; } previousNewFiber= newFiber; }}Copy the code
Create the nodes according to the fiber structure
import { Placement } from "./utils"; export function createFiber(vnode,returnFiber){ /** * fiber: * type indicates the type of the node * key indicates the uniqueness of the node under the current level * props attribute * index indicates the position under the current level * child first child * sibling next sibling * return parent * StateNode Dom node if the component is a native tag, class instance if it is a class component */ const newFiber={type: vnode.type, key:vnode.key, props:vnode.props, stateNode:null, child:null, return:returnFiber, sibling:null, Alternate :null, flags: alternate, // alternate, eg} return newFiber} alternate:null, flags: alternate,Copy the code
conclusion
ReactDOM implementation path
-
Render function
-
ScheduleUpdateOnFiber: defines a node
-
Workloop: Processing nodes in idle time of the browser requestIdleCallback(workloop)
-
PerformUnitOfWork: Updates a node, returning the next node, nodes of different types (native, function, class component)
-
UpdateHostCompose: updates the native node
-
CreateFiber: Modify the node to the fiber format
-
The node transformation is complete, there is no next child node, and wipRoot exists, indicating that the node can be submitted
-
CommitRoot: commitRoot node
-
CommitWork (child) wipRoot. / / since child nodes, submit themselves, submit a child node, submit siblings