useState
使用
- 更新状态并刷新,可以
传递函数或值
- 与reducer有一定区别,暂时可以理解为
useReducer语法糖
import { useReducer, useState } from "react";
const App = () => {
const [num, setNum] = useReducer(controll, 0);
const [state, setState] = useState(0);
console.log("会更新");
return (
<div>
<p>{state}</p>
<p>{num}</p>
<button
onClick={() => {
setState(0);
}}
>
state按钮
</button>
<button
onClick={() => {
setNum(0);
}}
>
reducer按钮
</button>
</div>
);
};
源码
- 与useReducer一样,都是在函数执行前给react的变量添加实例,然后通过变量.current.useState调用
...
export function useState(reducer, initialArg) {
const dispatcher = resolveDispatcher();
return dispatcher.useState(reducer, initialArg);
}
const HooksDispatcherOnMount = {
useReducer: mountReducer,
+ useState: mountState
}
const HooksDispatcherOnUpdate = {
useReducer: updateReducer,
+ useState: updateState
}
function mountState(initialState) {
const hook = mountWorkInProgressHook();
hook.memoizedState = initialState;
const queue = {
pending: null,
dispatch: null,
lastRenderedReducer: baseStateReducer,
lastRenderedState: initialState
}
hook.queue = queue;
const dispatch = (queue.dispatch = dispatchSetState.bind(null, currentlyRenderingFiber, queue));
return [hook.memoizedState, dispatch];
}
- state的创建hook实例与链表关联都与useReducer一样
与useReducer的差异
- 在hook上可以看到多出了
lastRenderedReducer
和lastRenderedState
这两个属性
lastRenderedReducer
- lastRenderedReducer对应的是一个函数,也可以叫做内置的reducer
- 我们在更新状态的时候,
可以传函数,也可以传递值
- 这个函数的作用就是区分我们传递进来的类型,然后返回最终结果
function baseStateReducer(state, action) {
return typeof action === 'function' ? action(state) : action;
}
lastRenderedState
dispatch
- dispatch的形式也没有变化,但是并没有复用
useReducer
的dispatchReducerAction
,而是调用了一个新的函数dispatchSetState
- 因为useState有一个
性能优化点
,当新旧两个值不同的时候才进行视图的刷新
- 而在学习useReducer的时候是先调用dispatch将
更新入队
,然后渲染视图
,视图重新执行到hook
的时候,会将队列内容取出更新
,然后渲染,但这样得等到最后才拿返回结果
,与useState的特性不符
- dispatchSetState执行步骤:
- 将旧值与传入的action(函数或值)通过lastRenderedReducer执行,拿到本次更新结果
- 然后拿到新旧两个值进行比较
- 相同,就不入队列,也不刷新视图了,直接return
- 反之则入队列,刷新视图
function dispatchSetState(fiber, queue, action) {
const update = {
action,
hasEagerState: false,
eagerState: null,
next: null
}
const { lastRenderedReducer, lastRenderedState } = queue;
const eagerState = lastRenderedReducer(lastRenderedState, action);
update.hasEagerState = true;
update.eagerState = eagerState;
if (Object.is(eagerState, lastRenderedState)) {
return;
}
const root = enqueueConcurrentHookUpdate(fiber, queue, update);
scheduleUpdateOnFiber(root);
}
更新
- 直接把
baseStateReducer传给updateReducer
了,因为updateReducer得接收个函数,可以理解为完全复用useReducer更新逻辑
function updateState() {
return updateReducer(baseStateReducer);
}