欢迎点击领取 -《前端面试题进阶指南》:前端登顶之巅-最全面的前端知识点梳理总结
简介
hooks的理念:
它是一个被称作为代数效应的思想。代数效应是函数式编程中的一个概念,用于将副作用从函数调用中剥离出去。函数式组件本身是一个函数,那么在函数式编程中有一个理念就叫做代数效应。
为什么要将将副作用从函数调用中剥离出去?我们举个例子。同步 => 异步,如果我们的函数是一个异步的操作,交给IO操作,那么它就是一个有函数副作用的方法。 而在es6中提供了异步的实现方式async aweait,但是它们是具有可传染性的,它的输出结果是一个promise对象。
理解代数效应
我们虚构一种语法perform、 resume with ,然后使用Try catch功能区捕获我们的自定义方法,当我们调用resume with的时候,我们的调用栈就会回到perform id这一行,从而解决不论是否是同步异步所带来的影响
// hooks理念的实现,理解代数效应语法
function getTotalNum(id1, id2) {
const num1 = getNum(id1); // 1 异步方法请求
const num2 = getNum(id2); // 2
return num1 + num2;
}
function getNum(id) {
const num = perform id;
return num;
}
// 虚构一种语法
try {
getTotalNum(1, 2);
} handle(id) {
switch (id) {
case 1:
resume with 230;
case 2:
resume with 122;
default:
resume with 0;
}
}
代数效应与Generator
我们知道15版本到16版本,Reat重大的一次重构,主要是在它的协调器上面(Reconciler),主要目的是将:老的同步更新转化为 异步可中断更新。
其实这一转变就是代数效应中try…handle的作用。
Generator: 浏览器原生就支持类似的实现,这就是Generator => async await => promise
如果只考虑“单一优先级任务的中断与继续”情况下Generator可以很好的实现异步可中断更新。
如果通过全局变量保存之前执行的中间状态,又会引入新的复杂度。所以因为这一原因,react团队放弃了 Generator
代数效应与Fiber
React内部实现的一套状态更新机制。支持任务不同优先级,可中断与恢复,并且恢复后可以复用之前的中间状态。而我们可以把 Fiber、generator理解为代数效应思想在js中的体现。
Hooks实现
dispatcher 是包含了hooks函数的共享对象,Hooks queue用顺序下链接在一起的节点。
- 它的初始状态在首次渲染时被创建。
- 她的状态可以即时更新。
- React会在之后的渲染中记住hook的状态
- React会根据调用顺序为您提供正确的状态
- React会知道这个hook属于哪个Fiber。
// useState更新实现过程
let isMount = true; // 区分我们的组件是首次调用还是更新调用; componentDidMount updateMount
let workInProgressHook = null // 记录我们hooks指针,当前处理的hooks
const fiber = {
stateNode: App, // 这个app组件是在源码的环境中运行的,首先我们每个组件,它在react中都有一个对应的fiber节点。
memoizedState: null // 保存了函数组件hooks的数据
}
function useState(initialState) {
let hook;
if (isMount) {
hook = {
memoizedState: initialState || 0,
next: null,
queue: {
pending: null
}
}
if (!fiber.memoizedState) {
fiber.memoizedState = hook;
workInProgressHook = hook;
} else {
workInProgressHook.next = hook;
}
} else {
hook = workInProgressHook;
workInProgressHook = workInProgressHook.next;
}
// 更新状态
let baseState = hook.memoizedState;
if (hook.queue.pending) {
let firstUpdate = hook.queue.pending.next;
do {
const action = firstUpdate.action;
baseState = action(baseState);
firstUpdate = firstUpdate.next
} while (firstUpdate !== hook.queue.pending.next)
hook.queue.pending = null;
}
hook.memoizedState = baseState;
return [baseState, dispatchAction.bind(null, hook.queue)]
}
function dispatchAction(queue, action) {
const update = { // 环状链表,优先级
action,
next: null
}
if (queue.pending === null) {
update.next = update; // u0 -> u0 -> u0
} else {
// u0 -> u1 -> u0
update.next = queue.pending.next;
queue.pending.next = update;
}
queue.pending = update;
schedule();
}
// 运行执行调度方法
function schedule() {
workInProgressHook = fiber.memoizedState; // 触发我们的组件
const app = fiber.stateNode(); // 触发我们的组件
isMount = false
return app;
}
// 组件本身
function App() {
const [num, updateNum] = useState(0);
const [count, updateCount] = useState(10);
console.log('isMount?', isMount)
console.log('num', num)
console.log('count:', count)
return { // 模拟我们的事件点击
onClick() {
updateNum(num => num + 1)
},
onFocus() {
updateCount(item => item + 10)
}
}
}
window.app = schedule();