React Hook源码解析(二)
2023-12-01 05:00:14
在 上一篇源码解析 中,我们主要分析了 Hook 在 React 中是如何保存的,以及 Hook 的更新过程。本文中,我们将通过下面两个问题,继续深入研究 Hook,以弥补上文中略过的一些细节。
- 我们点击一次 button,最终页面上会输出多少呢?
- 熟悉 React 的朋友们,很快就会得到答案:3。在上一篇源码解析中,这部分代码如何实现的?
我们点击一次 button,最终页面上会输出多少呢?
我们先回顾一下代码片段:
const App = () => {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(prevState => prevState + 1);
setCount(prevState => prevState + 1);
};
return (
<div>
<button onClick={handleClick}>+</button>
<p>{count}</p>
</div>
);
};
按照我们的预期,点击一次按钮,count
应该增加 2。但是,我们实际得到的结果却是 3。这是因为,在 handleClick
函数中,我们调用 setCount
函数两次。
第一次调用 setCount
函数时,传递了一个函数作为参数。这个函数接收一个参数,即前一个状态值。在该函数中,我们对前一个状态值加 1,并返回新的状态值。
setCount(prevState => prevState + 1);
第二次调用 setCount
函数时,我们同样传递了一个函数作为参数。但是,这次的函数中,我们再次对前一个状态值加 1,并返回新的状态值。
setCount(prevState => prevState + 1);
由于 setCount
函数是异步的,所以它并不会立即更新状态。因此,当我们第二次调用 setCount
函数时,它收到的前一个状态值是第一次调用 setCount
函数后返回的新状态值。
0 -> 1 -> 2 -> 3
因此,最终页面上输出的结果是 3。
在上一篇源码解析中,这部分代码如何实现的?
在上文中,我们提到 useReducer
钩子可以用来处理复杂的状态管理。我们给出了以下代码片段:
const reducer = (state, action) => {
switch (action.type) {
case 'increment':
return state + 1;
case 'decrement':
return state - 1;
default:
return state;
}
};
const App = () => {
const [count, dispatch] = useReducer(reducer, 0);
const handleClick = () => {
dispatch({ type: 'increment' });
dispatch({ type: 'increment' });
};
return (
<div>
<button onClick={handleClick}>+</button>
<p>{count}</p>
</div>
);
};
这段代码使用 useReducer
钩子来管理 count
状态。reducer
函数是一个纯函数,它接收一个状态和一个动作作为参数,并返回一个新的状态。
dispatch
函数用于派发动作。动作是一个对象,它包含一个 type
属性和一个可选的 payload
属性。
在 handleClick
函数中,我们调用 dispatch
函数两次。第一次我们派发一个 increment
动作,第二次我们派发一个 decrement
动作。
dispatch({ type: 'increment' });
dispatch({ type: 'increment' });
reducer
函数根据动作的类型来更新状态。对于 increment
动作,它将状态增加 1。对于 decrement
动作,它将状态减少 1。
因此,当我们点击按钮时,状态会增加 2。最终页面上输出的结果是 3。