react-元素渲染

一:引言

React是一个由Facebook开发和维护的用于构建用户界面的JavaScript库。React使得创建交互式UI变得非常简单和直观。设计简单的视图,并且在数据发生变化时,React会有效地更新和渲染正确的组件。

React的一个核心概念是虚拟DOM(Virtual DOM)。在传统的网页开发中,当数据发生变化时,浏览器需要重新解析、布局、绘制整个DOM树,这是一个非常消耗资源的过程。React通过引入虚拟DOM的概念,改变了这种情况。在React中,每次数据发生变化时,React会在内存中创建一个新的虚拟DOM树,然后与上一次的虚拟DOM树进行比较,找出两者之间的差异,然后只更新这些差异,从而大大提高了性能。

React中的元素是构成虚拟DOM的基本单位,它们描述了你在屏幕上看到的内容。在React中创建元素的过程,以及如何将这些元素转换为虚拟DOM和真实DOM,是理解React的关键。

在本文中,我们将详细介绍React元素的创建和转换过程,以及如何将虚拟DOM转换为真实DOM。我们将通过具体的代码示例,帮助你更好地理解这些概念和过程。

二:React元素的创建

在React中,使用JSX(JavaScript XML)语法来创建元素。JSX是一种JavaScript的语法扩展,它允许你在JavaScript中编写像HTML一样的代码。这样做的好处是,你可以在JavaScript中使用更直观和易于理解的语法来创建React元素。

例如,你可以使用以下的JSX代码来创建一个h1元素:

const element = <h1 className="box" style={{color:"red"}}>JSX元素</h1>;const element = <h1 className="box" style={{color:"red"}}>JSX元素</h1>;

在这个例子中, <h1 className=”box” style={{color:”red”}}>JSX元素 是JSX语法,它表示一个h1元素,该元素具有一个className属性,值为box,一个style属性,值为 {color:”red”} ,以及一个文本子节点JSX元素

然后,这段JSX代码会通过Babel转译器转换为JavaScript代码,如下:

const element = React.createElement(


  "h1",


  {


    className: "box",


    style: {


      color: "red"


    }


  },


  "JSX元素"


);

const element = React.createElement(

  "h1",

  {

    className: "box",

    style: {

      color: "red"

    }

  },

  "JSX元素"

);

在这个例子中,React.createElement是React库中的一个方法,用于创建React元素。这个方法接收三个参数:typeconfigchildrentype参数是一个字符串或者一个函数,表示元素的类型。如果是字符串,那么它表示一个HTML标签名,如果是函数,那么它表示一个自定义组件。config参数是一个对象,包含了传递给元素的所有属性。children参数表示元素的子元素。

总的来说,React通过使用JSX语法和React.createElement方法来创建元素,这些元素描述了你在屏幕上看到的内容。接下来,我们将详细介绍这些元素的结构和属性。

三:React元素结构

当我们使用React.createElement方法创建一个React元素后,我们会得到一个对象,这个对象表示一个React元素,它具有以下属性:

    • $$typeof: 这是一个标识符,表示这个对象是一个React元素。
    • type: 这是元素的类型,就是我们传给React.createElement方法的type参数。
    • key: 这是元素的key,用于在列表中标识元素。这个属性在React的Diff算法中有特殊的意义。
    • ref: 这是元素的ref,用于引用元素。通过ref,我们可以在React中获取到真实的DOM元素。
    • props: 这是一个对象,包含了所有传递给元素的属性,以及children。

例如,如果我们创建了如下的一个React元素:

const element = React.createElement(


  "h1",


  {


    className: "box",


    style: {


      color: "red"


    }


  },


  "JSX元素"


);

const element = React.createElement(

  "h1",

  {

    className: "box",

    style: {

      color: "red"

    }

  },

  "JSX元素"

);

那么,这个元素的结构将如下所示:

{
  $$typeof: Symbol(react.element),
  type: "h1",
  key: null,
  ref: null,
  props: {
    className: "box",
    style: {
      color: "red"
    },
    children: "JSX元素"
  }

}
{
  $$typeof: Symbol(react.element),
  type: "h1",
  key: null,
  ref: null,
  props: {
    className: "box",
    style: {
      color: "red"
    },
    children: "JSX元素"
  }
}

在这个例子中,我们可以看到,element对象是一个React元素,它的类型是h1,它有一个className属性,值为box,一个style属性,值为 {color: “red”} ,以及一个children属性,值为JSX元素

总的来说,React元素的结构描述了一个元素的所有信息,包括它的类型、属性和子元素。这些信息将被用于生成虚拟DOM和真实DOM。

四:React元素转为虚拟DOM

React元素创建之后,下一步就是要将其转换为虚拟DOM。在React中,虚拟DOM是一个简单的JavaScript对象,它描述了真实DOM应该是什么样的。虚拟DOM的主要优点是:它可以使我们避免直接操作DOM,因为直接操作DOM往往是昂贵的。

在React中,虚拟DOM是通过React.createElement方法创建的。这个方法返回的就是一个虚拟DOM对象。如下:

const element = React.createElement(


  "h1",


  {


    className: "box",


    style: {


      color: "red"


    }


  },


  "JSX元素"


);const element = React.createElement(
  "h1",
  {
    className: "box",
    style: {
      color: "red"
    }
  },
  "JSX元素"
);

在这个例子中,element就是一个虚拟DOM对象,它包含了元素的类型、属性和子元素等信息。我们可以将element看作是一个描述了真实DOM应该是什么样的蓝图。

当数据发生变化时,React会创建一个新的虚拟DOM树,并与旧的虚拟DOM树进行比较,找出两者之间的差异,然后将这些差异应用到真实的DOM上,这个过程被称为”reconciliation”(协调)。

总的来说,React元素转为虚拟DOM是React工作流程的一个重要部分,它使得React可以有效地更新和渲染UI。

五:虚拟dom转为真实DOM

虚拟DOM虽然为我们提供了一个描述真实DOM应该是什么样的蓝图,但它仍然只是一个JavaScript对象,我们需要将其转化为真实的DOM,才能被浏览器渲染出来。在React中,这个过程主要是通过ReactDOM.renderReactDOM.createRoot方法完成的。

以下是一个简化的ReactDOM.render函数的实现,它描述了如何将虚拟DOM转为真实DOM,并插入到指定的容器中:

function render(vdom, container) {
  // 虚拟DOM转为真实DOM
  let realDom = createDom(vdom);

  // 插入到对应的容器
  container.appendChild(realDom);
}


function createDom(vdom) {
  let { type, props, content } = vdom;
  let dom;
  // 根据type的类型创建不同的元素
  if (type === 'REACT_TEXT') {
    dom = document.createTextNode(content);
  } else {
    dom = document.createElement(type);
  }
  // 更新并添加DOM的标签,属性等等
  if (props) {
    updateProps(dom, {}, props);
  }
  return dom;
}

function updateProps(dom, oldProps, newProps) {
  if (newProps) {
    for (const key in newProps) {
      // 如果key为children则跳过,否则往dom里面添加
      if (key === 'children') {
        continue;
      } else if (key === 'style') {
        // 因为style可能有多个,所以可以进行遍历
        const styles = newProps[key];
        for (const attr in styles) {
          dom.style[attr] = styles[attr];
        }
      } else {
        dom[key] = newProps[key];
      }
    }
  }
  if (oldProps) {
    for (const key in oldProps) {
      if (!newProps[key]) {
        dom[key] = null;
      }
    }
  }

}function render(vdom, container) {
  // 虚拟DOM转为真实DOM
  let realDom = createDom(vdom);
  // 插入到对应的容器
  container.appendChild(realDom);

}



function createDom(vdom) {

  let { type, props, content } = vdom;

  let dom;

  // 根据type的类型创建不同的元素
  if (type === 'REACT_TEXT') {
    dom = document.createTextNode(content);
  } else {
    dom = document.createElement(type);
  }
  // 更新并添加DOM的标签,属性等等
  if (props) {
    updateProps(dom, {}, props);
  }
  return dom;
}


function updateProps(dom, oldProps, newProps) {
  if (newProps) {
    for (const key in newProps) {
      // 如果key为children则跳过,否则往dom里面添加
      if (key === 'children') {
        continue;
      } else if (key === 'style') {
        // 因为style可能有多个,所以可以进行遍历
        const styles = newProps[key];
        for (const attr in styles) {
          dom.style[attr] = styles[attr];
        }
      } else {
        dom[key] = newProps[key];
      }
    }
  }
  if (oldProps) {
    for (const key in oldProps) {
      if (!newProps[key]) {
        dom[key] = null;
      }
    }
  }
}

在这个过程中,我们首先创建了一个真实的DOM元素,然后为这个元素添加了相应的属性和子元素,最后将这个元素插入到了指定的容器中。这样,我们就完成了从虚拟DOM到真实DOM的转换,接下来浏览器就可以渲染出相应的UI了。

六:完整的虚拟DOM到真实DOM的转换代码

理解了React如何将元素转换为虚拟DOM,以及如何将虚拟DOM转换为真实DOM后,我们可以看一下一个完整的虚拟DOM到真实DOM的转换的例子。

在这个例子中,我们将创建一个简单的React应用,该应用只包含一个h1元素。我们将通过以下步骤来实现这个应用:

    1. 使用React.createElement方法创建一个React元素;
    2. 将这个元素转换为虚拟DOM;
    3. 使用ReactDOM.render方法将虚拟DOM转换为真实DOM,并插入到页面的根节点中。

以下是实现这个应用的完整代码:

i ndex.js:

javascriptCopy code


import React from './react';
import ReactDOM from './react-dom';


// 创建一个React元素
const element = React.createElement("h1", {style: {color: "red"}}, 'JSX元素');


// 使用ReactDOM.render方法将虚拟DOM转换为真实DOM,并插入到页面的根节点中
ReactDOM.render(element, document.getElementById("root"));javascriptCopy code
import React from './react';
import ReactDOM from './react-dom';

// 创建一个React元素
const element = React.createElement("h1", {style: {color: "red"}}, 'JSX元素');

// 使用ReactDOM.render方法将虚拟DOM转换为真实DOM,并插入到页面的根节点中
ReactDOM.render(element, document.getElementById("root"));

react.js:

javascriptCopy code


import { REACT_ELEMENT } from './constants';
import { toObject } from './util';


function createElement(type, config, children) {
  let key, ref;
  if (config) {
    key = config.key;
    ref = config.ref;
    delete config.key;
    delete config.ref;
  }


  let props = { ...config };
  if (config) {
    if (arguments.length > 3) {
      props.children = Array.prototype.slice.call(arguments, 2).map(toObject);
    } else if (arguments.length === 3) {
      props.children = toObject(children);
    }
  }

  return {
    $$typeof: REACT_ELEMENT,
    type,
    key,
    ref,
    props
  };
}

const React = {
  createElement
};

export default React;javascriptCopy code
import { REACT_ELEMENT } from './constants';
import { toObject } from './util';

function createElement(type, config, children) {
  let key, ref;
  if (config) {
    key = config.key;
    ref = config.ref;
    delete config.key;
    delete config.ref;
  }



  let props = { ...config };
  if (config) {
    if (arguments.length > 3) {
      props.children = Array.prototype.slice.call(arguments, 2).map(toObject);
    } else if (arguments.length === 3) {
      props.children = toObject(children);
    }
  }

  return {
    $$typeof: REACT_ELEMENT,
    type,
    key,
    ref,
    props
  };
}

const React = {
  createElement
};


export default React;

react-dom.js:

javascriptCopy code


function render(vdom, container) {
  let realDom = createDom(vdom);

  container.appendChild(realDom);
}

function createDom(vdom) {
  let { type, props, content } = vdom;
  let dom;
  if (type === REACT_TEXT) {
    dom = document.createTextNode(content);
  } else {
    dom = document.createElement(type);
  }
  if (props) {
    updateProps(dom, {}, props);
  }
  return dom;
}

function updateProps(dom, oldProps, newProps) {
  if (newProps) {
    for (const key in newProps) {
      if (key === 'children') {
        continue;
      } else if (key === 'style') {
        const styles = newProps[key];
        for (const attr in styles) {
          dom.style[attr] = styles[attr];
        }
      } else {
        dom[key] = newProps[key];
      }
    }
  }
  if (oldProps) {
    for (const key in oldProps) {
      if (!newProps[key]) {
        dom[key] = null;
      }
    }
  }
}

const ReactDOM = {
  render
};


export default ReactDOM;javascriptCopy code
function render(vdom, container) {
  let realDom = createDom(vdom);
  container.appendChild(realDom);

}



function createDom(vdom) {

  let { type, props, content } = vdom;

  let dom;

  if (type === REACT_TEXT) {
    dom = document.createTextNode(content);
  } else {
    dom = document.createElement(type);
  }
  if (props) {
    updateProps(dom, {}, props);
  }
  return dom;
}

function updateProps(dom, oldProps, newProps) {
  if (newProps) {
    for (const key in newProps) {
      if (key === 'children') {
        continue;
      } else if (key === 'style') {
        const styles = newProps[key];
        for (const attr in styles) {
          dom.style[attr] = styles[attr];
        }
      } else {
        dom[key] = newProps[key];
      }
    }
  }
  if (oldProps) {
    for (const key in oldProps) {
      if (!newProps[key]) {
        dom[key] = null;
      }
    }
  }
}

const ReactDOM = {
  render
};

export default ReactDOM;

以上就是一个完整的虚拟DOM到真实DOM的转换的过程。希望这个例子可以帮助你更好地理解React的工作原理。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYlMccIf' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片