1.React的历史与应用
1.应用:
- 前端应用开发,PC端网页开发
- 移动原生应用开发
- 结合 Electron,进行桌面应用开发
建议:可以去了解学习 react-three-fiber(3D)
2.发展历史:
2010 : Facebook 在其 php 生态中,引入了 xhp 框架,首次引入了组合式组件的思想,启发了后来的 React 的设计。
2011 : Jordan Walke 创造了 FaxJS,也就是后来的 React 原型
2012 : 在 Facebook 收购 Instaqram 后,该 FaxJS 项目在内部得到使用,Jordan Walke 基于 Faxjs 的经验,创造了React
2013 :React正式开源,在 2013 JSConf 上 Jordan Walke 介绍了这款全新的框架
2014 - 今天:生态大爆发,各种围绕 React 的新工具 / 新框架开始涌现
2.React 的设计思路
1.UI编程痛点
补充:回调地狱
先来了解两个概念:
- 回调函数:一个函数作为参数传入另一个参数中,但是不会立即执行,只有满足一定条件后才能执行,例如定时器和Ajax中就存在回调函数:
setTimeout(function(){ //function(){console.log('执行了回调函数')}就是回调函数,它只有在3秒后才会执行
console.log('执行了回调函数');
},3000) //3000毫秒
//1.创建异步对象
var xhr=new XMLHttpRequest();
//2.绑定监听事件(接收请求)
xhr.onreadystatechange=function(){
//此方法会被调用4次
//最后一次,readyState==4
//并且响应状态码为200时,才是我们要的响应结果 xhr.status==200
if(xhr.readyState==4 && xhr.status==200){
//把响应数据存储到变量result中
var result=xhr.responseText;
console.log(result);
}
}
//3.打开链接(创建请求)
xhr.open("get","/demo/ajaxDemo",true);
//4.发送请求
xhr.send();
- 异步任务:与之相对应的概念是“同步任务”,同步任务在主线程上排队执行,只有前一个任务执行完毕,才能执行下一个任务。异步任务不进入主线程,而是进入异步队列,前一个任务是否执行完毕不影响下一个任务的执行。
什么是回调地狱?
回调地狱就是指回调函数中嵌套回调函数的情况。是一种强制代码顺序执行的操作,会造成代码可读性非常差,后期不好维护
如何解决回调地狱?
- Promise
Promise是js中的一个原生对象,是一种异步编程的解决方案,可以替换掉传统的回调函数解决方案。
- Promise构造函数接收一个函数作为参数,我们需要处理的异步任务就卸载该函数体内,该函数的两个参数是resolve,reject。异步任务执行成功时调用resolve函数返回结果,反之调用reject。
- Promise对象的then方法用来接收处理成功时响应的数据,catch方法用来接收处理失败时相应的数据。
- Promise的链式编程可以保证代码的执行顺序,前提是每一次在than做完处理后,一定要return一个Promise对象,这样才能在下一次then时接收到数据。
Promise 的缺点:
会造成代码冗余,会产生很多then,不利于代码维护
- async / await
async : 作为一个关键字放到声明函数前,表示该函数是一个异步任务,不会阻塞后面函数的执行,async函数返回数据时自动封装为一个 Promise 对象,和Promise对象一样,处理成功时用then方法来接收,失败时用catch方法来接收数据
await:
- await关键字只能在使用async定义的函数中使用
- await后面可以直接跟一个 Promise实例对象(可以跟任何表达式,更多的是跟一个返回Promise对象的表达式)
- await函数不能单独使用
- await可以直接拿到Promise中resolve中的数据。
❗ 为什么叫 await 等待呢,因为当代码执行到 async 函数中的 await 时,代码就在此处等待不继续往下执行,直到 await 拿到Promise对象中resolve的数据,才继续往下执行,这样就保证了代码的执行顺序,而且使异步代码看起来更像同步代码。
🔗Callback Hell
2.响应式和转换式
在开发场景中,写转换式系统(过程式)是很难受的,就需要新的编程理念帮我们解决问题
- 响应式系统
- 前端 UI
3.响应式编程
4.组件化(组件隔离)
总结:
5.状态归属问题
📋结论:状态归属于两个节点向上寻找最近的祖宗节点(状态上升)
6.思考:
- React 数据流是单向的,还是双向的?
7.组件设计
要求:
8.响应式编程
响应式编程:使用异步数据流进行编程
🔗响应式编程(Reactive Programming)介绍
9.生命周期
3.React(hooks)的写法
Hook:以 use 开头的函数被称为 Hook ,Hook 比普通函数更为严格,只能在你的组件(或其他 Hook)的 顶层 调用 Hook
Hooks 写法新手入门(举例两个最常用的钩子函数)
- **useState :**传入一个初始值,返回一个状态,和 set 该状态的函数,用户可以通过调用该函数来实现对状态的修改
- **useEffect:**传入一个函数,和一个数组(可以省略,[]),数组是状态的数组,称作依赖项,该函数在mount(组件挂载的时候)时,和依赖项被 set 的时候被执行
有“副作用”的函数,要传入 useEffect ,副作用代表除了单纯的计算之外,还要做其它一些事情(并不是纯函数就会有一些操作会对外部造成一定的影响),比如网络请求,更新DOM,localStorage存储数据等。
❗ 使用React封装好的库,React才能支持相应的刷新、响应
Hook 使用法则:
4.React 的实现
问题:
1.虚拟 DOM (Virtual DOM)
Virtual DOM 是一种用于和真实DOM同步,而在JS内存中维护的一个对象,它具有和DOM类似的树状结构,并和 DOM可以建立一一对应的关系。因为js 对象的查询,比对整个dom 树的查询,所消耗的性能要少。
它赋予了React声明式的API : 您告诉React希望让UI是什么状态,React就确保DOM匹配该状态(自动更新)。这使您可以从属性操作、事件处理和手动DOM更新这些在构建应用程序时必要的操作中解放出来。
优点:
- 减少DOM操作,降低浏览器性能消耗
- diff 算法,减少回流和重绘
- 支持跨平台(因为虚拟DOM本质上只是一个JS对象)
补充:
- 指令式编程:需要手动告诉程序应该怎么做
- 声明式编程:发出指令,直接执行
- 响应式编程:不仅可以声明,还可以实现当某个状态改变时的自动更新,自己响应自己的一个过程
❗注意:由于DOM 是树状的结构,就是父组件嵌套子组件,是一种递归关系,也就意味着父组件只要发生改变,子组件就会重新 render 一次,会影响性能
🔗虚拟 DOM
2. DOM diff?
DOM diff 是虚拟 DOM 的一种对比算法,当数据发生变化时,它会去对比前后的 DOM ,查找哪些地方发生了变化,然后返回需要改变的操作,其实也就是一个函数,通常称之为 patch,也可以理解成Dom diff 通过JS层面的计算,返回一个patch对象,即补丁对象,在通过特定的操作解析patch对象,完成页面的重新渲染。
How to Diff ?
完美的最小Diff 算法,需要 O(n ^ 3)的复杂度
牺牲理论最小 Diff,换取时间,得到了 O( n ) 复杂度的算法:Heuristic O(n) Algorithm
替换策略:
| 不同类型的元素 | 替换 |
|---|---|
| 同类型的 DOM 元素 | 更新 |
| 同类型的组件元素 | 递归 |
5.React 状态管理库
核心思想:将状态抽离到 UI 外部进行统一管理
状态管理库推荐:
- redux
- xstate
- mobx
- recoil
状态机:当前状态,收到外部事件,迁移到下一个状态
🤔思考:哪些东西适合放在状态管理库?
2.Modern.js / Reduck
6.应用级框架科普
-
NEXT.JS
-
MODERN.JS
-
Blitz