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

一. 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
  • 先不用脚手架写

案例的结构搭建

  • 每一行是一个书籍对象, 放到一个数组中
  • 数字和左右两个按钮的距离太近了, 给个间距


reender() {
  return(
    
书籍名称 出版日期 价格 购买数量 操作
1 2 3 4 5
) }
  • 价格, 前面是¥符号, 后面显示两位小数
  • 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 

购物车为空

} 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的本质+阶段案例练习)