博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
④ React 列表与Keys、虚拟DOM相关说明、AJAX
阅读量:3964 次
发布时间:2019-05-24

本文共 4326 字,大约阅读时间需要 14 分钟。

查看专栏其它文章:


React


本人是个新手,写下博客用于自我复习、自我总结。

如有错误之处,请各位大佬指出。
学习资料来源于:尚硅谷


列表与Keys

之前的文章里已经使用过 JavaScript 的 map() 方法来创建列表。在这里再详细说明其它内容。

简单使用演示:

const numbers = [1, 2, 3, 4, 5];const listItems = numbers.map((numbers) =>  
  • {
    numbers}
  • ); ReactDOM.render(
      {
      listItems}
    , document.getElementById('example'));

    然后我们再将以上实例重构成一个组件,组件接收数组参数,每个列表元素分配一个 key,不然会出现警告 a key should be provided for list items,意思就是需要包含 key。

    function NumberList(props) {
    const numbers = props.numbers; const listItems = numbers.map((number) =>
  • {
    number}
  • ); return (
      {
      listItems}
    );} const numbers = [1, 2, 3, 4, 5];ReactDOM.render(
    , document.getElementById('example'));

    通常情况下,请不要忘记加 key。那这个 Key 到底是用来做什么的,且选取什么值都可以吗?

    Keys 可以在 DOM 中的某些元素被增加或删除的时候帮助 React 识别哪些元素发生了变化。因此你应当给数组中的每一个元素赋予一个确定的标识。且一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串。通常,我们使用来自数据的 id 作为元素的 key ( id :自己建立的,用于区分每个数据)。

    const todoItems = todos.map((todo) =>  
  • {
    todo.text}
  • );

    当元素没有确定的 id 时,你可以使用他的序列号索引 index 作为 key

    const todoItems = todos.map((todo, index) =>  // 只有在没有确定的 id 时使用  
  • {
    todo.text}
  • );

    复杂一些的情况:元素的 key 只有在它和它的兄弟节点对比时才有意义。

    比方说,如果你提取出一个 ListItem 组件,你应该把 key 保存在数组中的这个 <ListItem /> 元素上,而不是放在 ListItem 组件中的 <li> 元素上。

    function ListItem(props) {
    // 这里不需要指定key: return
  • {
    props.value}
  • ;} function NumberList(props) {
    const numbers = props.numbers; const listItems = numbers.map((number) => // key应该在数组的上下文中被指定
    ); return (
      {
      listItems}
    );} const numbers = [1, 2, 3, 4, 5];ReactDOM.render(
    , document.getElementById('example'));

    在这里需要注意:key 只会作为给 React 的提示,不会传递给你的组件。比如在这里子组件中,就不能读出 props.key。如果您的组件中需要使用和 key 相同的值,请将其作为属性传递。

    说回正题,数组元素中使用的 key 在其兄弟之间应该是独一无二的。然而,它们不需要是全局唯一的。当我们生成两个不同的数组时,我们可以使用相同的键。

    function Blog(props) {
    const sidebar = (
      {
      props.posts.map((post) =>
    • {
      post.title}
    • )}
    ); const content = props.posts.map((post) =>

    {
    post.title}

    {

    post.content}

    ); return (
    {
    sidebar}

    {
    content}
    );} const posts = [ {
    id: 1, title: 'Hello World', content: 'Welcome to learning React!'}, {
    id: 2, title: 'Installation', content: 'You can install React from npm.'}];ReactDOM.render(
    , document.getElementById('example'));

    虚拟DOM相关说明

    从React开篇就说到了虚拟DOM,也提到了对于React高效的原因:

    1. 虚拟(virtual)DOM, 不总是直接操作DOM

    2. DOM Diff算法, 最小化页面重绘

    接下来将对虚拟DOM的相关内容进行一些简单的说明。


    在说到何为 虚拟DOM 前,需要先说明何为 真实DOM 和其解析的流程。这部分详细内容可以看:视频中的内容讲的很详细。

    对于浏览器渲染引擎的大致工作流程如下(简化):

    第一步,用HTML分析器,分析HTML元素,构建一颗DOM树。

    第二步,用CSS分析器,分析CSS文件和元素上的样式,生成页面的样式表。

    第三步,将DOM树和样式表,关联起来,构建一颗Render树。

    第四步,有了Render树,浏览器开始布局,为每个Render树上的节点确定一个在显示屏上出现的精确坐标。

    第五步,Render树和节点显示坐标都有了,就调用每个节点paint方法,把它们绘制出来。

    然后再经过一个复杂的渲染过程,就将内容渲染了出来。

    在这个过程中,当我们改变一个元素的尺寸位置属性时,会重新进行样式计算、布局、绘制以及后面的所有流程,这种行为被称为重排

    当我们改变某个元素的颜色属性时,不会重新触发布局,但还是会触发样式计算和绘制,这种行为被称为重绘

    操作真实DOM的代价?

    而在这个过程中,JS操作真实DOM的代价还是很大的。当我们用传统的开发模式,原生JS操作DOM时,浏览器会从构建DOM树开始从头到尾执行一遍流程。在一次操作中,我需要更新10个DOM节点,浏览器收到第一个DOM请求后并不知道还有9次更新操作,因此会马上执行流程,最终执行10次。例如,第一次计算完,紧接着下一个DOM更新请求,这个节点的坐标值就变了,前一次计算为无用功。计算DOM节点坐标值就是白白的浪费性能。

    那虚拟DOM有什么好处?

    虚拟DOM就是为了解决浏览器性能问题而被设计出来的。若一次操作中有10次更新DOM的动作,虚拟DOM不会立即操作DOM,而是将这10次更新的内容保存到本地一个JS对象中,最终将这个JS对象一次性挂到DOM树上,再进行后续操作,避免大量无谓的计算量。(也就是现在我们看到的 React 和 Vue 都是这样操作)

    diff算法是虚拟DOM技术的必然产物

    这个diff算法是虚拟DOM技术的必然产物,因为我们需要对新旧虚拟DOM作对比,然后将变化的地方更新在真实DOM上。如果对diff算法感兴趣,可以查阅相关资料。

    就比如上面列表中 key 的作用就是为了高效的更新虚拟DOM,其原理就是通过key精准判断两个节点是否是同一个,从而避免频繁更新不同元素,使得整个更新渲染过程更加高效,减少DOM操作量,提高性能。

    在这里插入图片描述


    验证DOM最小化页面重绘

    在上面已经说到了,虚拟DOM 通过 Diff算法,实现了最小化页面重绘,即:可以更少的操作真实DOM,减少操作DOM的次数,更新页面的次数也就减少了。接下来我们将验证这点,虚拟DOM是否真的可以最小化页面重绘。

      
    vDOM

    因为时间在不断变化(通过 setState 更新状态),所以会重新创建虚拟DOM树。而在这个过程中,虚拟DOM会对 新 / 旧 内容进行比较,然后对有差异的部分去进行局部重绘。假如是整体重绘,那么在输入框中输入一些内容应该也会导致差异。而无论我们怎么向输入框中输入内容,也不会引起虚拟DOM对其的更新。而向输入框中输入信息却无法导致更新,是因为之前在表单时提到过,表单元素本身虽然能够保留一些内部状态,并根据用户输入进行更新,但在React中,可变的状态通常保存在组件的状态属性中,并且只能用 setState() 方法进行更新。

    在这里插入图片描述

    原理图:

    在这里插入图片描述


    AJAX

    React 组件的数据可以通过 componentDidMount 方法中的 Ajax 来获取,当从服务端获取数据时可以将数据存储在 state 中,再用 this.setState 方法重新渲染 UI。当使用异步加载数据时,在组件卸载前使用 componentWillUnmount 来取消未完成的请求。

    相关用法就不在这里赘述了,如果对AJAX不熟悉,可以查阅相关文章:

    常用的ajax请求库

    1. jQuery: 比较重, 如果需要另外引入不建议使用

    2. axios: 轻量级, 建议使用

      a. 封装XmlHttpRequest对象的ajax
      b. promise风格
      c. 可以用在浏览器端和node服务器端

    3. fetch: 原生函数, 但老版本浏览器不支持

      a. 不再使用XmlHttpRequest对象提交ajax请求
      b. 为了兼容低版本的浏览器, 可以引入兼容库fetch.js

    使用简例(axios):

      
    ajax

    使用简例(jQuery):

    ajax

    转载地址:http://hmyki.baihongyu.com/

    你可能感兴趣的文章
    DB2 用户管理
    查看>>
    DB2 脚本
    查看>>
    DB2 锁升级失败将引起死锁
    查看>>
    遇到问题该如何解决
    查看>>
    [第21课] 二项分布3
    查看>>
    [第22课] 二项分布4
    查看>>
    Pandas 筛选数据
    查看>>
    Pandas 复合索引
    查看>>
    [第23课] 期望值E(X)
    查看>>
    [第24课] 二项分布的期望值
    查看>>
    Pandas 处理 NaN
    查看>>
    Pandas 分组统计
    查看>>
    Pandas 多 DataFrame联接
    查看>>
    Sybase 系列文章目录
    查看>>
    SQLServer
    查看>>
    Hibernate 通过 Hibernate 访问数据库
    查看>>
    java面试题
    查看>>
    消息队列相关(MQ)
    查看>>
    生成短连接
    查看>>
    java多线程
    查看>>