React核心工作原理
创始人
2024-03-23 19:57:57

## 1.1、虚拟DOM

常见问题:react virtual dom是什么?说一下diff算法?

拿到一个问题,一般回答都是是什么?为什么?怎么办?那就按照这个思路来吧!

what

用 JavaScript 对象表示 DOM 信息和结构,当状态变更的时候,重新渲染这个 JavaScript 的对象结构。这个 JavaScript 对象称为virtual dom;

why

DOM操作很慢,轻微的操作都可能导致页面重新排版,非常耗性能。相对于DOM对象,js对象处理起来更快,而且更简单。通过diff算法对比新旧vdom之间的差异,可以批量的、最小化的执行dom操作,从而提高性能。

where

React中用JSX语法描述视图,通过babel-loader转译后它们变为React.createElement(…)形式,该函数将生成vdom来描述真实dom。将来如果状态变化,vdom将作出相应变化,再通过diff算法对比新老vdom区别从而做出最终dom操作。

这里说到了JSX,那就顺带大致说一下:

什么是JSX

语法糖, React 使用 JSX 来替代常规的 JavaScript。JSX 是一个看起来很像 XML 的 JavaScript 语法扩展。

为什么需要JSX

开发效率:使用 JSX 编写模板简单快速。执行效率:JSX编译为 JavaScript 代码后进行了优化,执行更快。类型安全:在编译过程中就能发现错误。

React 16原理

babel-loader会预编译JSX为React.createElement(...)

React 17原理

React 17中的 JSX 转换不会将 JSX 转换为 React.createElement,而是自动从 React 的 package 中引入新的入口函数并调用。另外此次升级不会改变 JSX 语法,旧的 JSX 转换也将继续工作。

与vue的异同

react中虚拟dom+jsx的设计一开始就有,vue则是演进过程中才出现的,2.0版本后出现。

jsx本来就是js扩展,转义过程简单直接的多;vue把template编译为render函数的过程需要复杂的编译器转换字符串-ast-js函数字符串

1.2、render、Component基础核心api

render

ReactDOM.render(element, container[, callback]);

当首次调用的时候,容器节点里的所有DOM 元素都会被替换,后续的调用则会使用React的DOM的差分算法(DOM diffing algorithm)进行高效的更新。

如果提供了可选的回调函数,该回调将在组件被渲染或更新之后被执行。

节点类型

1、文本节点
2、html 标签节点
3、函数组件
4、类组件
...

函数组件

// 大些字母开头
function Welcome(props) {return 

Hello, {props.name}

}

类组件

React 的组件可以定义为class 或函数的形式,如需定义class 组件,需要继承React.Component 或 React.PureComponent:

class Welcome extends React.Component {render() {return 

Hello, {this.props.name}

} }

1.3、手写简版myreact

实现原生标签节点、文本节点、函数组件和类组件的初次渲染

先用 Create React App 创建一个 React 项目,安装依赖并运行;

接着在 src/index.js 里边加上 这段代码查看一下版本号,保证自己的是17版本

console.log("version", React.version);

正是因为 React17 中,React会自动替换JSX为js对象,所以我们主要需要注释掉 src/index.js 中:

// import React from "react";
// import ReactDOM from "react-dom";

接着在src 下创建一个myreact文件夹,在里边创建一个 react-dome.js

// vnode 虚拟dom对象
// node 真实dom节点// ! 初次渲染
function render(vnode, container) {// react17 可以自动转虚拟domconsole.log("vnode", vnode);// vnode->nodeconst node = createNode(vnode);// node->containercontainer.appendChild(node);
}// 创建节点
function createNode(vnode) {let node;const {type} = vnode;// todo 根据组件类型的不同创建不同的node节点if (typeof type === "string") { // 原生标签节点node = updateHostComponent(vnode);} else if (typeof type == "function") { // 函数组件 再次区分一下类组件和函数组件node = type.prototype.isReactComponent  ? updateClassComponent(vnode): updateFunctionComponent(vnode);} else { // 文本节点node = updateTextComponent(vnode);}return node;
}// 原生标签节点
function updateHostComponent(vnode) {const {type, props} = vnode;const node = document.createElement(type);console.log('document.createElement', node)// 更新节点部分updateNode(node, props); // 属性reconcileChildren(node, props.children); // 遍历childrenreturn node;
}// 更新属性
function updateNode(node, nextVal) {Object.keys(nextVal).filter((k) => k !== "children") // 过滤一下 children.forEach((k) => (node[k] = nextVal[k])); // 生成属性
}// 文本节点
function updateTextComponent(vnode) {const node = document.createTextNode(vnode);return node;
}// 函数组件
function updateFunctionComponent(vnode) {const {type, props} = vnode;// type 是一个 functionconst vvnode = type(props);// vvnode->nodeconst node = createNode(vvnode);return node;
}// 类组件
function updateClassComponent(vnode) {const {type, props} = vnode;// 类组件需要 new const instance = new type(props);console.log('instance', instance);const vvnode = instance.render();console.log('vvnode', vvnode);// vvnode->nodeconst node = createNode(vvnode);return node;
}// 遍历children
function reconcileChildren(parentNode, children) {// 和源码一点写法区别,但是也是为了判断是否是数组const newChildren = Array.isArray(children) ? children : [children];for (let i = 0; i < newChildren.length; i++) {let child = newChildren[i];// vnode// vnode->node, node插入到parentNoderender(child, parentNode);}
}export default { render };

接着,还要在创建一个 src/myreact/Component.js 文件:

// 类组件必须继承自 Component 或者 PureComponent
function Component(props) {// 需要绑定一下thisthis.props = props;
}// 做了一个 类组件的标记
Component.prototype.isReactComponent = {};export default Component;

奥,不能忘了还要改动一下 src/index.js 文件内容:

// import React from 'react';
// import ReactDOM from 'react-dom';
import ReactDOM from './myreact/react-dom';
import Component from "./myreact/Component";
import './index.css';
// import App from './App';
import reportWebVitals from './reportWebVitals';class ClassComponent extends Component {render() {return (

类组件-{this.props.name}

);} }export default ClassComponent;function FunctionComponent(props) {return (

函数组件-{props.name}

); }const jsx = (

111111

222222

111111

百度
)// 原生标签 // 文本节点 // 函数组件 // 类组件ReactDOM.render(jsx,document.getElementById('root') );// console.log("version", React.version); // version 17.0.1// If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals reportWebVitals();

参考 React面试题详细解答

整体代码就是这样,具体过程就不在这里细致说明了,大家好好品一下代码,有疑问的可以联系我。

小结

1、React17 中,React会自动替换JSX为js对象。2、js对象即vdom,它能够完整描述dom结构。3、ReactDOM.render(vdom, container)可以将vdom转换为dom并追加到container中。4、实际上,转换过程需要经过一个diff过程。

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...