useState
- useState 就是一个 Hook
- 通过在函数组件里调用它来给组件添加一些内部 state,React 会在重复渲染时保留这个 state
- useState 会返回一对值:当前状态和一个让你更新它的函数,你可以在事件处理函数中或其他一些地方调用这个函数。它类似 class 组件的 this.setState,但是它不会把新的 state 和旧的 state 进行合并
- useState 唯一的参数就是初始 state
- 返回一个 state,以及更新 state 的函数
- 在初始渲染期间,返回的状态 (state) 与传入的第一个参数 (initialState) 值相同
setState 函数用于更新 state。它接收一个新的 state 值并将组件的一次重新渲染加入队列
每次渲染都是独立的闭包
- 每一次渲染都有它自己的 Props and State
- 每一次渲染都有它自己的事件处理函数
- 捕获渲染值特性 alert会“捕获”我点击按钮时候的状态
- 在单次渲染的范围内,props和state始终保持不变
函数式更新
- 如果新的 state 需要通过使用先前的 state 计算得出,那么可以将函数传递给 setState。该函数将接收先前的 state,并返回一个更新后的值
惰性初始 state
- initialState 参数只会在组件的初始渲染中起作用,后续渲染时会被忽略
- 如果初始 state 需要通过复杂计算获得,则可以传入一个函数,在函数中计算并返回初始的 state,此函数只在初始渲染时被调用
性能优化
- 调用 State Hook 的更新函数并传入当前的 state 时,React 将跳过子组件的渲染及 effect 的执行。(React 使用 Object.is 比较算法 来比较 state)
- 减少渲染次数
- 把内联回调函数及依赖项数组作为参数传入 useCallback,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新
- 把创建函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算
useState深入学习
- useState是内置执行器的useReducer
- useState相对于useReducer增加了一些优化比如eagerState(急切的状态)
挂载阶段:
let currentlyRenderingFiber = null;
let workInProgressHook = null;
function mountState(initialState) {
const hook = mountWorkInProgressHook();
hook.memoizedState = hook.baseState = initialState;
const queue = {
pending: null,
dispatch: null,
lastRenderedReducer: basicStateReducer,
lastRenderedState: initialState,
};
hook.queue = queue;
const dispatch = (queue.dispatch = dispatchSetState.bind(null, currentlyRenderingFiber, queue));
return [hook.memoizedState, dispatch];
}
function mountWorkInProgressHook() {
const hook = {
memoizedState: null,
queue: null,
next: null,
};
if (workInProgressHook === null) {
currentlyRenderingFiber.memoizedState = workInProgressHook = hook;
} else {
workInProgressHook = workInProgressHook.next = hook;
}
return workInProgressHook;
}
function dispatchSetState(fiber, queue, action) {
const update = {
action,
hasEagerState: false,
eagerState: null,
next: null,
};
const lastRenderedReducer = queue.lastRenderedReducer;
const currentState = queue.lastRenderedState;
const eagerState = lastRenderedReducer(currentState, action);
update.hasEagerState = true;
update.eagerState = eagerState;
if (is(eagerState, currentState)) {
return;
}
const root = enqueueConcurrentHookUpdate(fiber, queue, update);
scheduleUpdateOnFiber(root, fiber);
}
更新阶段(复用useReducer的更新方法)
let currentHook = null;
function updateReducer(reducer) {
const hook = updateWorkInProgressHook()
const queue = hook.queue
queue.lastRenderedReducer = reducer
const current = currentHook
const pendingQueue = queue.pending
let newState = current.memoizedState
if (pendingQueue !== null) {
queue.pending = null
const first = pendingQueue.next
let update = first
do {
if (update.hasEagerState) {
newState = update.eagerState
} else {
const action = update.action
newState = reducer(newState, action)
}
update = update.next
} while (update !== null && update !== first)
}
hook.memoizedState = queue.lastRenderedState = newState 更新hook状态
return [hook.memoizedState, queue.dispatch]
},
function updateWorkInProgressHook() {
if (currentHook === null) {
const current = currentlyRenderingFiber.alternate
currentHook = current.memoizedState
} else {
currentHook = currentHook.next
}
const newHook = {
memoizedState: currentHook.memoizedState,
queue: currentHook.queue,
next: null
}
if (workInProgressHook === null) {
currentlyRenderingFiber.memoizedState = workInProgressHook = newHook
} else {
workInProgressHook = workInProgressHook.next = newHook
}
return workInProgressHook
}