美文网首页
Day4. JSX的本质+阶段案例练习

Day4. JSX的本质+阶段案例练习

作者: JackLeeVip | 来源:发表于2020-06-15 22:25 被阅读0次

    一. JSX的本质

    • 补充一些理论原理相关的东西
    • 写出效率更高的代码
    • 最合适的位置安排一些原理相关的东西, 读源码

    1. JSX的基本写法

    • 先写最简单的jsx代码
    • ReactDOM.render(组件, document.getElementById("app"))
    • jsx只是另外一个东西的语法糖
    • 实际上, jsx仅仅只是React.createElement(component, props, ...children)函数的语法糖.
      • 所有的jsx最终都会被转换成React.createElement的函数调用.
    • jsx -> babel -> React.createElement()
    • babel做中间的转换
    jsx本质1.png
    • React.createElement在源码的什么位置呢?
    • REACT-16.13.1 packages -> react -> index.js ->
    • js里面一个{}就是一个对象
    • 开发环境做很多的验证, 希望在开发中有更多的错误提示
    • 搜索, OUTLINE大纲
    • createElement需要传递三个参数


      三个参数.png
    位置.png
    所在位置.png

    2. Babel官网查看

    • 我们知道默认jsx是通过babel帮我们进行语法转换的, 所以我们之前写的jsx代码都需要依赖babel.
    • 可以再babel官网看转换过程 babel官网
    • 疑惑, 只让传3个参数, 这里有5个, 自己进行匹配? 之后一对一的匹配, 偏移2个位置, 最后把数组赋值给props.children = childArray;
    React.createElement("div", null, "header", "content", "footer", "")
    
    匹配.png image.png 处理.png

    3. createElement写法

    • 纯函数的概念PURE
    image.png

    二. 虚拟DOM的创建过程

    • 我们通过React.createElement最终创建出来一个JS对象-> ReactElement对象, 回到源码里面看
    • 这个ReactElement对象是什么作用呢? React为什么要创建它呢?
      • 原因是React李勇ReactElement对象组成了一个JavaScript的对象树;
      • JavaScript的对象数就是大名鼎鼎的虚拟DOM(Virtual SOM);
    • DOM树, 频繁操作, 性能低
    • 映射关系, JavaScript对象表示出来, 内存中进行操作, 效率高
    • 如何查看


      DOM树.png
      image.png

    ReactElement对象

    • 一层一层的展开 -> 组件树
    • 虚拟DOM转换成真实DOM -> ReactDOM.render, 映射


      对应关系.png
    image.png

    总结

    1. jsx -> createElement函数 -> ReactElement(对象树) -> ReactDOM.render -> 浏览器上的真实DOM
    2. RN中: jsx -> createElement函数 -> ReactElement(对象树) -> ReactDOM.render -> 原生的空间(UIButton/Button)


      jsx - xuniDOM - 真实DOM.png

    为什么使用虚拟DOM

    • 为什么要采用虚拟DOM, 而不是直接修改真实的DOM?
      • 很难跟踪状态发生的改变: 原有的开发模式, 我们很难跟踪到状态发生的改变, 不方便针对我们应用程序进行调试;
      • 操作真实DOM性能较低: 传统的开发模式会进行频繁的DOM操作, 而这一做法性能非常低;
    • DOM操作性能非常低
    • 首先, document.createElement本身创建出来的就是一个车非常复杂的对象;
    • 官网
    • 性能损耗非常大
    • 我们举个例子: 我们有一组数组需要渲染:[0, 1, 2, 3, 4],
      • 我们可以通过ul和li将它们展示出来
    • 后来, 我们又增加了5条数据: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      • 方式一: 重新遍历整个数组(不推荐)
      • 方式二: 在ul后面追加另外5个li
    案例.png
    • 上面这段代码的性能非常低效
      • 因为我们通过document.createElement创建元素, 在通过ul.appendChild(li)窜然道DOM上, 进行了多次DOM操作;
      • 对于批量操作的, 最好的办法不是一次次修改DOM, 而是对批量的操作进行合并 (比如可以通过Document...)
    • 而我们真是可以通过Virtual DOM来帮助我们解决上面的问题;
    官网描述.png

    声明式编程

    • 虚拟DOM帮助我们从命令式编程转到了声明式编程的模式
    • React官方的说法: Virtual DOM是一种编程理念.
      • 在这个理念中, UI以一种理想化或者说虚拟化的方式保存在内存中, 并且它是一个相对简单的JavaScript对象
      • 我们可以通过ReactDOM.render让虚拟DOM和真实DOM同步起来, 这个过程叫做协调(Reconciliation);
    • 这种编程的方式赋予了React声明式的API
      • 你只需要告诉React希望让UI是什么状态
      • React来确保DOM和这些状态是匹配的
      • 你不需要直接进行DOM操作, 就可以从手动更改DOM 属性操作 事件处理中解放出来;

    三. 阶段案例练习

    案例.png
    • 先不用脚手架写

    案例的结构搭建

    • 每一行是一个书籍对象, 放到一个数组中
    • 数字和左右两个按钮的距离太近了, 给个间距
    <style>
        table {
          border 1px solid ##eee;
          border-collapse: collapse;
        }
    
        th, td {
          border: 1px solid #eee;
          padding: 10px 16px;
          text-align: center;
        }
    
        th{
          background-color: #ccc;
        }
    </style>
    
    reender() {
      return(
        <div>
          <table>
            <thead>
              <tr>
                <td></td>
                <td>书籍名称</td>
                <td>出版日期</td>
                <td>价格</td>
                <td>购买数量</td>
                <td>操作</td>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td></td>
                <td>1</td>
                <td>2</td>
                <td>3</td>
                <td>4</td>
                <td>5</td>
              </tr>
            </tbody>
          </table>
        </div>
      )
    }
    
    • 价格, 前面是¥符号, 后面显示两位小数
    • format-utils.js 统一处理格式, 工具函数, Number类型, 字符串转Number, "aaa" NaN(Not a Number)
    function formatPrice(price) {
      if (thpeof price !== "number") {
        price = Number("aaa") || 0;
      }
      
    return "¥" + price.toFixed(2);
    }
    
    • 书籍总价格的显示, 做一个计算
    • 总价格做一个格式化, 两种方式,
    getTotalPrice() {
      //1. for玄幻的方式
      let totalPrice = 0;
      //this, 上面做了隐式绑定 this.getTotalPrice()
      for (let item of this.state.books) {
        totalPrice += item.price * item.count;
      }
      return totalPrice;
    
      // 2. filter/map/reduce(归纳为)
      // 回调函数的参数:
      // 参数一: 上一次回调函数的结果(第一次没有上一次函数的回调函数的结果, 使用初始化值)
      const totalPrice =    this.state.books.reduce(回调函数, initialValue);
      const totalPrice =    this.state.books.reduce((前一次回调函数的结果 preValue, item, index, arr) => {}, initialValue);
    
      const totalPrice =    this.state.books.reduce((preValue, item) => {
        return preValue + item.count * item.price;
      }, 0);
    }
    
    • 移除操作, 从数组中移除, 重新调用render
    • 根据索引值, 决定移除哪一个 -> index参数
    removeBook (index) {
      // React中设计原则: state中的数据的不可变性
      // 不要直接修改state中的数据, splice修改了原来的数组
      // filter不会修改原来的数组, 返回了新的数组
      this.setState({
        books: this.state.books.filter((itme, indey) => index != indey)
      })
    }
    
    • 当所有书籍移除完毕, 显示购物车为空
    • 单独封装一个函数 renderBooks() => 函数式组件
    • all in js
    renderEmptyTip() {
      return <h2>购物车为空</h2>
    }
    
    render() {
      return this.state.books.length ? this.renderBooks() : this.renderEmptyTip();
    }
    
    • 书籍的数量改变
    • changeBookCount(index)
    • 渲染相关的函数, 放到render函数的上面
    • 功能相关的函数, 放到render函数的下面
    • 变成1的时候, 减号按钮不可点击, 如何按钮不能和用户交互? 加个判断
    changeBookCount(index, count) {
      // ES6 展开 浅拷贝
      const newBooks = [...this.state.books];
      newBooks[index].count += count;
    
      this.setState({
        books: newBooks
      })
    }
    

    coderwhy学习建议

    1. 优先看课件
    2. 看代码
    3. 看视频

    coderwhy的React核心技术与开发实战课程链接

    少年~来做同学呀~.png

    相关文章

      网友评论

          本文标题:Day4. JSX的本质+阶段案例练习

          本文链接:https://www.haomeiwen.com/subject/pvbhxktx.html