一. JSX的本质
- 补充一些理论原理相关的东西
- 写出效率更高的代码
- 最合适的位置安排一些原理相关的东西, 读源码
1. JSX的基本写法
- 先写最简单的jsx代码
ReactDOM.render(组件, document.getElementById("app"))
- jsx只是另外一个东西的语法糖
- 实际上, jsx仅仅只是
React.createElement(component, props, ...children)
函数的语法糖. - 所有的jsx最终都会被转换成
React.createElement
的函数调用.
- 所有的jsx最终都会被转换成
- jsx -> babel -> React.createElement()
- babel做中间的转换
- React.createElement在源码的什么位置呢?
- REACT-16.13.1 packages -> react -> index.js ->
- js里面一个{}就是一个对象
- 开发环境做很多的验证, 希望在开发中有更多的错误提示
- 搜索, OUTLINE大纲
-
createElement需要传递三个参数
三个参数.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
二. 虚拟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
总结
- jsx -> createElement函数 -> ReactElement(对象树) -> ReactDOM.render -> 浏览器上的真实DOM
-
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
- 上面这段代码的性能非常低效
- 因为我们通过document.createElement创建元素, 在通过ul.appendChild(li)窜然道DOM上, 进行了多次DOM操作;
- 对于批量操作的, 最好的办法不是一次次修改DOM, 而是对批量的操作进行合并 (比如可以通过Document...)
- 而我们真是可以通过Virtual DOM来帮助我们解决上面的问题;
声明式编程
- 虚拟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学习建议
- 优先看课件
- 看代码
- 看视频
网友评论