浅析React Hook之useReducer
提示:本文主要讲解useReducer
认识Fiber
Fiber是什么?
Fiber是一种数据结构,用于描述虚拟DOM。 react目前的做法是使用链表。每个virtualDOM节点内部表示为一个Fiber
Fiber树
顾名思义,将Fiber连接起来就是Fiber树
Fiber是一个执行单单元
Fiber是一个执行单元,每次执行完一个执行单元, React 就会检查现在还剩多少时间,如果没有时间就将控制权让出去
认识循环链表
循环链表是另一种形式的链式存储结构
它的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环
思考:这种结构该如何实现???
代码如下(示例):
function enqueueUpdate(queue, action){
const update = {action, next:null}
}
认识Hook
什么是hook?
Hook是React 16.8的新增特性。它可以让你在不便携class的情况下使用state以及其他的React特性。
为什么会引入hook
官方给出的动机是解决长时间使用和维护react过程中经常遇到的问题。 1、在组件之间复用状态逻辑很难(比如:render、props和高阶组件) 2、复杂组件变得难以理解(比如:不想干的逻辑放在一起) 3、难以理解的class(比如:this的工作方式)
常见hook
如何实现useReducer
用法:略
注册Hook流程
ReactFiberHooks
let ReactCurrentDispatcher = {
current: null
}
let currentlyRenderingFiber = null;
let workInProgressHook = null;
let currentHook = null;
const HooksDispatcherOnMount = {
useReducer: mountReducer
}
const HooksDispatcherOnUpdate = {
useReducer: updateReducer
}
export function useReducer(reducer, initialArg) {
return ReactCurrentDispatcher.current.useReducer(reducer, initialArg);
}
export function renderWithHooks(_current, workInProgress, Component) {
currentlyRenderingFiber = workInProgress;
workInProgress.memoizedState = null;
if (_current !== null) {
ReactCurrentDispatcher.current = HooksDispatcherOnUpdate;
} else {
ReactCurrentDispatcher.current = HooksDispatcherOnMount;
}
let children = Component();
currentlyRenderingFiber = null;
currentHook = null;
workInProgressHook = null;
return children;
}
function updateReducer(reducer) {
const hook = updateWorkInProgressHook();
const queue = hook.queue;
queue.lastRenderedReducer = reducer;
const current = currentHook;
const pendingQueue = queue.pending;
if (pendingQueue !== null) {
const first = pendingQueue.next;
let newState = current.memoizedState;
let update = first;
do {
const action = update.action;
newState = reducer(newState, action);
update = update.next;
} while (update !== null && update !== first);
queue.pending = null;
hook.memoizedState = newState;
queue.lastRenderedState = newState;
}
const dispatch = dispatchAction.bind(null,currentlyRenderingFiber,queue);
return [hook.memoizedState, dispatch];
}
function updateWorkInProgressHook() {
let nextCurrentHook;
if (currentHook === null) {
const current = currentlyRenderingFiber.alternate;
nextCurrentHook = current.memoizedState;
} else {
nextCurrentHook = currentHook.next;
}
currentHook = nextCurrentHook;
const newHook = {
memoizedState: currentHook.memoizedState,
queue: currentHook.queue,
next: null,
};
if (workInProgressHook === null) {
currentlyRenderingFiber.memoizedState = workInProgressHook = newHook;
} else {
workInProgressHook = workInProgressHook.next = newHook;
}
return workInProgressHook;
}
export function mountReducer(reducer, initialArg) {
const hook = mountWorkInProgressHook();
let initialState = initialArg;
hook.memoizedState = initialState;
const queue = (hook.queue = {pending: null, lastRenderedReducer: reducer, lastRenderedState: initialState});
const dispatch = dispatchAction.bind(null,currentlyRenderingFiber,queue);
return [hook.memoizedState, dispatch];
}
export function mountWorkInProgressHook() {
const hook = {
memoizedState: null,
queue: null,
next: null,
};
if (workInProgressHook === null) {
currentlyRenderingFiber.memoizedState = workInProgressHook = hook;
} else {
workInProgressHook = workInProgressHook.next = hook;
}
return workInProgressHook;
}
export function dispatchAction(fiber, queue, action) {
const update = { action, next: null };
const pending = queue.pending;
if (pending === null) {
update.next = update;
} else {
update.next = pending.next;
pending.next = update;
}
queue.pending = update;
const lastRenderedReducer = queue.lastRenderedReducer;
const currentState = queue.lastRenderedState;
const eagerState = lastRenderedReducer(currentState, action);
if (Object.is(eagerState, currentState)) {
return
}
scheduleUpdateOnFiber(fiber);
}
useState
思考一下useState和useReducer是不是有相同的点?那怎么实现呐。。。
期待更多。。。
|