Skip to content

Instantly share code, notes, and snippets.

@Sylvenas
Last active March 31, 2021 03:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Sylvenas/28d23025ff369ab63c95cd8a40122d4c to your computer and use it in GitHub Desktop.
Save Sylvenas/28d23025ff369ab63c95cd8a40122d4c to your computer and use it in GitHub Desktop.
react hooks 执行过程,包括mount阶段和updater阶段
/**
* Hook数据结构
*/
interface hook {
memoizedState: any; // 保存当前 hook 的 state
next: hook; // next 指向下一个 hook
queue: queue; // 更新队列
}
interface queue {
dispatch: Function; // 添加到队列的方法
last: updater; // 最后一个updater,环状链表,lastUpdater.next就是firstUpdater,可以
}
interface updater {
action: Function | any; // 更新函数
next: updater; // 下一个updater
}
// hook链表的开头
let firstHook: hook = null;
// hook 链表的结尾
let lastHook: hook = null;
// 首次渲染完成
let mounted: boolean = false;
// 当前正在执行计算的 hook
let currentUpdateHook: hook = null;
function useState(initialState: any): [any, Function] {
if (mounted) {
return updateState();
}
const hook = mountHookLinkedList();
hook.memoizedState = initialState;
const queue = (hook.queue = {
last: null,
dispatch: null,
});
const dispatcher = (queue.dispatch = dispatchAction.bind(null, queue));
return [hook.memoizedState, dispatcher];
}
function updateState(): [any, Function] {
if (currentUpdateHook === null) {
currentUpdateHook = firstHook;
}
const queue = currentUpdateHook.queue;
const last = queue.last;
let first = last !== null ? last.next : null;
let newState = currentUpdateHook.memoizedState;
if (first !== null) {
let update = first;
do {
// 执行每一次更新,去更新状态
const action = update.action;
// 函数则调用
if (typeof action === 'function') {
newState = action(newState);
} else {
newState = action;
}
update = update.next;
} while (update !== null && update !== first);
}
currentUpdateHook.memoizedState = newState;
// 关键代码,执行一轮调用之后要把更新队列清空,在下一轮的调用中重新添加队列
queue.last = null;
currentUpdateHook = currentUpdateHook.next;
const dispatch = queue.dispatch;
// 返回最新的状态和修改状态的方法
return [newState, dispatch];
}
function mountHookLinkedList() {
const hook = {
memoizedState: null,
next: null,
queue: null,
};
// 第一次生成 hook,赋值
if (lastHook === null) {
firstHook = lastHook = hook;
} else {
// 第二,三,四次生成 hook,依次挂载到前一个hook的next上
lastHook = lastHook.next = hook;
}
return lastHook;
}
function dispatchAction(queue, action) {
const updater = { action, next: null };
// 将updater对象添加到循环链表中
const last = queue.last;
if (last === null) {
// 链表为空,将当前更新作为第一个,并保持循环
updater.next = updater;
} else {
const first = last.next;
if (first !== null) {
// 在最新的updater对象后面插入新的updater对象
updater.next = first;
}
last.next = updater;
}
// 将表头保持在最新的updater对象上
queue.last = updater;
}
function TeamsInfo() {
const [age, setAge] = useState(18);
const [name, setName] = useState('income');
console.log(`Age: ${age}; Name: ${name}`);
mounted = true;
return [setAge, setName];
}
const [setAge, setName] = TeamsInfo();
setAge((x) => x + 1);
setAge((x) => x + 11);
setAge((x) => x * 2);
TeamsInfo();
setAge((x) => x * 2);
setName((x) => x + '-girls');
TeamsInfo();
console.log(firstHook);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment