React 的历史与利用
React 是一个 JavaScript 库
React : A JavaScript library for building user interfaces. ——Jordan Walke
-
利用场景:
- 前端利用开发,如 Facebook、Instagram、Netflex 网页版
- 挪动原生利用开发,如 Instagram、Discord、Oculus
- 联合 Electron,进行桌面利用开发
- 3D 开发:react-three-fiber
-
React 的历史
- 2010 年:Facebook 在其 php 生态中,引入了 xhp 框架,首次引入了组合式组件的思维,启发了起初的 React 的设计
- 2011 年:Jordan Walke 发明了 FaxJS,也就是起初的 React 原型
- 2012 年:在 Facebook 收买 Instagram 后,该 FaxJS 我的项目在外部失去应用,Jordan Walke 基于 FaxJS 的教训发明了 React
- 2013 年:React 正式开源,在 2013 JSConf 上 Jordan Walke 介绍了这款全新的框架
- 2014 年:生态大暴发,各种围绕 React 的新工具 / 新框架开始涌现
React 的设计思路
-
原生 JavaScript UI 编程痛点
- 状态更新,UI 不会自动更新,须要手动调用 DOM 进行更新
- 欠缺根本的代码层面的封装和隔离,代码层面没有组件化
- UI 之间的数据依赖关系须要手动保护,如果依赖链路过长会引起回调天堂 Callback Hell
-
响应式与转换式
- 转换式零碎:给定输出求解输入,例如编译器、数值计算
- 响应式零碎:监听事件,音讯驱动,例如监控零碎、UI 界面
-
响应式零碎
事件 -> 执行既定回调 -> 状态变更
-
响应式的前端 UI 编程:
事件 -> 执行既定回调 -> 状态变更 -> UI 更新
-
React 响应式编程特点
- 状态更新,UI 自动更新
- 前端代码组件化,可复用,可封装
- 状态之间的相互依赖关系,只需申明即可
-
组件化
- 组件是组件的组合 / 原子组件
- 组件外部领有状态,内部不可见
- 父组件可将状态传入组件外部
-
组件状态归属问题
- 共享状态归属于两个组件节点的最近先人节点,即状态晋升
- React 是单向数据流,永远是父组件给子组件传递状态,子组件只能调用函数更改状态
- 应用状态治理库如 redux 解决状态不合理晋升的问题
- 如何批改 DOM : 将 JSX 文件本义为 JS 文件、利用虚构 DOM 树和 diff 算法来更新 DOM
-
组件设计
- 组件申明了状态和 UI 的映射
- 组件有 props 和 state 两种状态
- 组件可由其余组件拼装而成
-
组件特点:
- 组件外部领有公有状态 state
- 组件承受内部的 props 状态提供复用性
- 依据以后的 state 和 props 返回一个 UI
React Hooks 的写法
- 最罕用的两个 Hooks 是 useState 和 useEffect
-
useState:传入一个初始值,返回一个状态,和 set 该状态的函数,用户能够通过调用该函数,来实现状态的批改
import React, {useState} from 'react'; const Example = () => {const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
-
useEffect:两个参数,一个是要执行的函数,一个是依赖项数组(能够不传依赖性)。有副作用的函数要传入到 useEffect 来执行。副作用示意除了单纯的计算之外还要做其余的事件,比方网络申请、更新 DOM、localStorage 数据等。
import React, {useState, useEffect} from 'react'; const Example = () => {const [count, setCount] = useState(0); // 应用一个副作用,传入的 [count] 数组使得此副作用只有当 count 变量扭转时才会被调用 useEffect(() => { // 副作用:Update the document title using the browser API document.title = `You clicked ${count} times`; }, [count]); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
-
Hooks 的应用规定:
- 只在最顶层应用 Hooks,不要在循环,条件或嵌套函数中调用 Hooks,确保总是在 React 函数的最顶层以及任何 return 之前调用他们。
- 只在 React 函数中调用 Hooks,不要在一般的 JavaScript 函数中调用 Hooks,能够在 React 的函数组件中调用 Hooks,能够在自定义 Hooks 中调用其余 Hooks
React 的实现
-
React 是不能间接在浏览器中运行的,有这些问题
- React 的 JSX 语法不合乎 JavaScript 规范语法
- 返回的 JSX 产生扭转时,如何更新 DOM
- state/props 更新时要从新触发 render 函数
-
如何实现
- 将 JSX 文件转译(transpile)成 JS 文件
-
利用虚构 DOM 树
- 实在 DOM(Document Object Model)是浏览器创立页面的文档对象模型
- 虚构 DOM 树是在 JS 内存中保护的一个对象,具备和 DOM 相似的树状构造,并和 DOM 能够建设一一对应的关系
- 利用虚构 DOM 就不必操作实在 DOM 提供的 API 来批改 DOM 了:它赋予了 React 申明式的 API,通知 React 心愿让 UI 是什么状态,React 就确保 DOM 匹配该状态,前端工程师便能够从属性操作、事件处理和手动 DOM 更新这些操作中解放出来
-
利用 Diff 算法
- 状态扭转时,先更新虚构 DOM 树,而不是间接更新 DOM 树,通过 Diff 算法,求出起码要更新的节点,而后再去更新真正的 DOM 树
-
完满的最小 Diff 算法,须要 O(n^3)的复杂度;就义实践最小 Diff,换取工夫,失去了 O(n)复杂度的算法
不同类型元素 同类型元素 同类型的组件元素 替换 更新 递归
React 状态治理库
- 核心思想:将状态抽离到 UI 内部进行对立治理
- 状态治理库的弊病:UI 依赖于内部的一个状态治理库会升高代码的复用性,因而状态治理库总是呈现在业务代码中
- 常见状态治理库:redux、xstate、mobx、recoil
- 状态机:以后状态收到内部事件,迁徙到下一个状态