react fiber
- fiber 架构目的
- 为了使react渲染的过程中可以被中断,将控制权交还给浏览器,可以让位给高优先级的任务,浏览器空闲之后再恢复渲染,对于计算量比较大的js计算或者dom计算,不会显得卡顿,有规律的执行任务
- generator 有类型中断的功能,为什么不直接使用
- 要使用generator ,需要将所有代码包装成generator的形式
- generator 内部是要有状态
如何判断当前是否有高优先级任务?
- 约定一个合理的执行时间,当超过这个执行时间,如果任务还没结束,中断当前任务,将控制权交还给浏览器
时间计算 1000ms/60f = 16ms
requestIdleCallback 使浏览器在有空的时候执行我们的回调,这个回调传入一个参数,表示浏览器有多少时间供我们执行任务
- 浏览器在一帧内要做什么事情
- 处理用户输入事件
- js执行
- requestAimations 调用
- 布局 layout
- 绘制 paint
浏览器很忙的时候怎么办?
-
requestIdleCallback timeout 参数,如果超过这个timeout后,回调还没被执行,那么会在下一帧强制执行回调
- 兼容性???
- requestIdleCallback 兼容性很差,通过messageChannel 模拟实现了requestIdleCallback的功能
- timeout超时一定会执行吗???
-
不是的,react 里预定了5个优先级的等级
- Immediate 最高优先级,这个优先级的任务应该被马上执行不能中断
- userBlocking 这些任务一般是用户交互的结果,需要及时得到反馈
- normal 不需要用户立即感受到的变化,比如网络请求
- low 这些任务可以延后,但是最终也需要执行
- idle 可以被无限延期的
-
高阶组件?什么是高阶组件?高阶组件用来做什么?
- hoc
- 一个函数
- 入参: 原来的react组件
- 返回值: 新的react组件
- 纯函数,不应该有任何的副作用
- 做什么?
- 属性代理
- 操作props
- 操作组件实例
- 劫持/继承
什么是react hook ?有啥优势?
- 可以不写class组件的情况下,使用state和其他react 特性
useState useEffect useMemo
- class 组件的缺点
- 组件间的状态逻辑很难复用
-
组件间如果有state的逻辑是相似的, class 模式下基本是用高阶组件来解决,虽然能够解决问题,但是我们需要在组件外部包一层元素,会导致层级非常冗余
-
复杂业务的状态组件会非常复杂,不好拆分
-
监听和定时器的操作,被分散在多个区域(多个生命周期函数中)
-
this 指向问题
-
- 组件间的状态逻辑很难复用
hooks 的优点
- 利于业务逻辑的封装和拆分,可以非常自由的组合各种自定义hooks(自己封装react hooks的公共逻辑)
- 可以在无需修改组件结构的情况下,复用组件状态逻辑
- 定时器 监听。。。都被聚合到同一个代码下
### react hook 的注意事项
-
- 只能在函数内部的最外层调用hook,不要在循环、条件判断或者子函数中调用
-
- 只能在react 的函数组件中调用hook,不要在其他的js函数里调用
#### 为什么hook 不能在循环、条件判断中调用?
-
- 手动实现useState
// 使用 hook
function Counter() {
const [count, setCount] = useState(0);
}
// 实现 useState
let stateArray: any[] = [];
const index = 0;
function useState<T>(initialState: T):[T, (newState: T) => void] {
const current = index;
stateArray[current] = stateArray[current] || initialState;
function setState(newState: T) {
stateArray[current] = newState;
render();
}
index++;
return [stateArray[current], setState];
}
#### 为什么useEffect 的第二个参数是空数组,就相当于componentDidMount只执行一次?
const allDeps: Array<any[] | undefined> = []; // 二维数组
let cursor = 0;
function useEffect(callback: () => viod, depArray?: any[]) {
if(!depArray) {
callback();
allDeps[cursor] = depArray;
cursor++;
return;
}
// 表示的是上一次的依赖项
const deps = allDeps[cursor];
// 依赖项是否更新
const hasChanged = deps ? depArray.some((el, i) => el !== deps[i]) : true;
if(hasChanged) {
callback();
allDeps[cursor] = depArray;
}
cursor++;
}
#### 自定义的hook怎样操作组件的?