本文转载自微信公众号「JS每日一题」,作者灰灰。转载本文请联系JS每日一题公众号。

创新互联建站主要从事网站制作、网站设计、网页设计、企业做网站、公司建网站等业务。立足成都服务井冈山,10年网站建设经验,价格优惠、服务专业,欢迎来电咨询建站服务:028-86922220
react通过将组件编写的JSX映射到屏幕,以及组件中的状态发生了变化之后 React会将这些「变化」更新到屏幕上
在前面文章了解中,JSX通过babel最终转化成React.createElement这种形式,例如:
会被bebel转化成如下:
- React.createElement(
 - "div",
 - null,
 - React.createElement("img", {
 - src: "avatar.png",
 - className: "profile"
 - }),
 - React.createElement(Hello, null)
 - );
 
在转化过程中,babel在编译时会判断 JSX 中组件的首字母:
最终都会通过RenderDOM.render(...)方法进行挂载,如下:
- ReactDOM.render(
 , document.getElementById("root")); 
在react中,节点大致可以分成四个类别:
如下所示:
- class ClassComponent extends Component {
 - static defaultProps = {
 - color: "pink"
 - };
 - render() {
 - return (
 ClassComponent
{this.props.name}
- );
 - }
 - }
 - function FunctionComponent(props) {
 - return (
 - FunctionComponent
 {props.name}
- );
 - }
 - const jsx = (
 - );
 
这些类别最终都会被转化成React.createElement这种形式
React.createElement其被调用时会传?标签类型type,标签属性props及若干子元素children,作用是生成一个虚拟Dom对象,如下所示:
- function createElement(type, config, ...children) {
 - if (config) {
 - delete config.__self;
 - delete config.__source;
 - }
 - // ! 源码中做了详细处理,⽐如过滤掉key、ref等
 - const props = {
 - ...config,
 - children: children.map(child =>
 - typeof child === "object" ? child : createTextNode(child)
 - )
 - };
 - return {
 - type,
 - props
 - };
 - }
 - function createTextNode(text) {
 - return {
 - type: TEXT,
 - props: {
 - children: [],
 - nodeValue: text
 - }
 - };
 - }
 - export default {
 - createElement
 - };
 
createElement会根据传入的节点信息进行一个判断:
虚拟DOM会通过ReactDOM.render进行渲染成真实DOM,使用方法如下:
- ReactDOM.render(element, container[, callback])
 
当首次调用时,容器节点里的所有 DOM 元素都会被替换,后续的调用则会使用 React 的 diff算法进行高效的更新
如果提供了可选的回调函数callback,该回调将在组件被渲染或更新之后被执行
render大致实现方法如下:
- function render(vnode, container) {
 - console.log("vnode", vnode); // 虚拟DOM对象
 - // vnode _> node
 - const node = createNode(vnode, container);
 - container.appendChild(node);
 - }
 - // 创建真实DOM节点
 - function createNode(vnode, parentNode) {
 - let node = null;
 - const {type, props} = vnode;
 - if (type === TEXT) {
 - node = document.createTextNode("");
 - } else if (typeof type === "string") {
 - node = document.createElement(type);
 - } else if (typeof type === "function") {
 - node = type.isReactComponent
 - ? updateClassComponent(vnode, parentNode)
 - : updateFunctionComponent(vnode, parentNode);
 - } else {
 - node = document.createDocumentFragment();
 - }
 - reconcileChildren(props.children, node);
 - updateNode(node, props);
 - return node;
 - }
 - // 遍历下子vnode,然后把子vnode->真实DOM节点,再插入父node中
 - function reconcileChildren(children, node) {
 - for (let i = 0; i < children.length; i++) {
 - let child = children[i];
 - if (Array.isArray(child)) {
 - for (let j = 0; j < child.length; j++) {
 - render(child[j], node);
 - }
 - } else {
 - render(child, node);
 - }
 - }
 - }
 - function updateNode(node, nextVal) {
 - Object.keys(nextVal)
 - .filter(k => k !== "children")
 - .forEach(k => {
 - if (k.slice(0, 2) === "on") {
 - let eventName = k.slice(2).toLocaleLowerCase();
 - node.addEventListener(eventName, nextVal[k]);
 - } else {
 - node[k] = nextVal[k];
 - }
 - });
 - }
 - // 返回真实dom节点
 - // 执行函数
 - function updateFunctionComponent(vnode, parentNode) {
 - const {type, props} = vnode;
 - let vvnode = type(props);
 - const node = createNode(vvnode, parentNode);
 - return node;
 - }
 - // 返回真实dom节点
 - // 先实例化,再执行render函数
 - function updateClassComponent(vnode, parentNode) {
 - const {type, props} = vnode;
 - let cmp = new type(props);
 - const vvnode = cmp.render();
 - const node = createNode(vvnode, parentNode);
 - return node;
 - }
 - export default {
 - render
 - };
 
在react源码中,虚拟Dom转化成真实Dom整体流程如下图所示:
其渲染流程如下所示:
参考文献
https://bbs.huaweicloud.com/blogs/265503)
https://huang-qing.github.io/react/2019/05/29/React-VirDom/
https://segmentfault.com/a/1190000018891454
                网页名称:面试官:说说ReactJsx转换成真实DOM过程?
                
                文章起源:http://www.csdahua.cn/qtweb/news45/253495.html
            
成都网站优化推广公司_创新互联,为您提供品牌网站制作、网页设计公司、标签优化、搜索引擎优化、动态网站、品牌网站设计
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网