useState

react对useState进行了封装,调用了mountState。

function useState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
currentHookNameInDev = 'useState';
mountHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV;
try {
return mountState(initialState);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
}

mountState

如果initialState是函数还可以执行。

生成一个dispatch方法,通过闭包绑定当前states。

把初始值存到memoizedState上。这个memoizedState绑定到fiber树上。用来存储state。

function mountState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
// 把hooks加入queue,实际上是为了保证执行顺序。
const hook = mountWorkInProgressHook();
if (typeof initialState === 'function') {
initialState = initialState();
}
hook.memoizedState = hook.baseState = initialState;
const queue = (hook.queue = {
last: null,
dispatch: null,
lastRenderedReducer: basicStateReducer,
lastRenderedState: (initialState: any),
});
const dispatch: Dispatch<
BasicStateAction<S>,
> = (queue.dispatch = (dispatchAction.bind(
null,
// Flow doesn't know this is non-null, but we do.
((currentlyRenderingFiber: any): Fiber),
queue,
): any));
return [hook.memoizedState, dispatch];
}

memoizedState

react其实不知道我们调用了几次useState。

所以还是在memoizedState上动手脚,这个处理体现在mountWorkInProgressHook

 memoizedState: {
baseState,
next,
baseUpdate,
queue,
memoizedState
}

memoizedState.next就是下一次useState的hook对象。

hook1 === Fiber.memoizedState
state1 === hook1.memoizedState
state2 = hook1.next.memoizedState

因为以这种方式存储,所以usestate必须在functionalComponent的根作用域中。不能被for,和if。

setstate

mountState函数返回的是 return [hook.memoizedState, dispatch];

dispatch通过闭包就可以处理state。

更新

useState在更新的时候是调用的updateState,这个函数其实是封装的updateReducer。

function renderWithHooks(){
ReactCurrentDispatcher.current =
nextCurrentHook === null
? HooksDispatcherOnMount
: HooksDispatcherOnUpdate;
};
HooksDispatcherOnMount: {
useState: mountState,
}
HooksDispatcherOnUpdate: {
useState: updateState,
}

updateReducer

可以看到updateReducer把新的fiber中的state值更新,返回新的值。然后后续走渲染流程。(之前写过reat 的渲染流程)

还可以看到这有个循环update = update.next; while (update !== null && update !== first);

这就是hooks的batchUpdate。

function updateReducer<S, I, A>(
reducer: (S, A) => S,
initialArg: I,
init?: I => S,
): [S, Dispatch<A>] {
const hook = updateWorkInProgressHook();
const queue = hook.queue; queue.lastRenderedReducer = reducer; // ...
// The last update in the entire queue
const last = queue.last;
// The last update that is part of the base state.
const baseUpdate = hook.baseUpdate;
const baseState = hook.baseState; // Find the first unprocessed update.
let first;
if (baseUpdate !== null) {
if (last !== null) {
// For the first update, the queue is a circular linked list where
// `queue.last.next = queue.first`. Once the first update commits, and
// the `baseUpdate` is no longer empty, we can unravel the list.
last.next = null;
}
first = baseUpdate.next;
} else {
first = last !== null ? last.next : null;
}
if (first !== null) {
let newState = baseState;
let newBaseState = null;
let newBaseUpdate = null;
let prevUpdate = baseUpdate;
let update = first;
let didSkip = false;
do {
const updateExpirationTime = update.expirationTime;
if (updateExpirationTime < renderExpirationTime) {
// Priority is insufficient. Skip this update. If this is the first
// skipped update, the previous update/state is the new base
// update/state.
if (!didSkip) {
didSkip = true;
newBaseUpdate = prevUpdate;
newBaseState = newState;
}
// Update the remaining priority in the queue.
if (updateExpirationTime > remainingExpirationTime) {
remainingExpirationTime = updateExpirationTime;
}
} else {
markRenderEventTimeAndConfig(
updateExpirationTime,
update.suspenseConfig,
); // Process this update.
if (update.eagerReducer === reducer) {
// If this update was processed eagerly, and its reducer matches the
// current reducer, we can use the eagerly computed state.
newState = ((update.eagerState: any): S);
} else {
const action = update.action;
newState = reducer(newState, action);
}
}
prevUpdate = update;
update = update.next;
} while (update !== null && update !== first); if (!didSkip) {
newBaseUpdate = prevUpdate;
newBaseState = newState;
} // Mark that the fiber performed work, but only if the new state is
// different from the current state.
if (!is(newState, hook.memoizedState)) {
markWorkInProgressReceivedUpdate();
} hook.memoizedState = newState;
hook.baseUpdate = newBaseUpdate;
hook.baseState = newBaseState; queue.lastRenderedState = newState;
} const dispatch: Dispatch<A> = (queue.dispatch: any);
return [hook.memoizedState, dispatch];
}

最新文章

  1. webgl动画小测试
  2. Android 学习Activity(1)activity和intent
  3. 浅谈Javascript事件模拟
  4. Rails--n+1查询
  5. WORD2007多级列表
  6. 【转】【C#】判断两个文件是否相同
  7. Oracle数据库作业-3 查询
  8. VC2010 _com_error 返回的错误信息
  9. VB.Net 文件处理类
  10. Android studio教程:[6]创建多个Activity
  11. 可以使用QT给龙芯开发软件
  12. Linux笔记(一) - 目录处理命令
  13. Java生成名片式的二维码源码分享
  14. javascript实现继承的三种方式
  15. JS自定义鼠标右击菜单
  16. Material Designer的低版本兼容实现(五)—— ActivityOptionsCompat
  17. JavaScript学习-2循环
  18. JS应用实例5:全选、动态添加
  19. MVC 模式——第3章
  20. 图文解说视频直播原理-zz

热门文章

  1. IO多路复用(转)
  2. Netty中FastThreadLocal源码分析
  3. Xamarin移动开发备忘
  4. maven 学习---使用“mvn site-deploy”部署站点
  5. 7 CentOS 7网卡配置
  6. 给普通用户赋予sudo权限后报错,提示/etc/sudoers文件权限拒绝
  7. 8.InfluxDB-InfluxQL基础语法教程--ORDER BY子句
  8. nrm : 无法加载文件 C:\Users\TANG\AppData\Roaming\npm\nrm.ps1,因为在此系统上禁止运行脚本。
  9. Lnmp搭建zabbix运维监控系统
  10. input子系统四 input事件处理【转】