本教程不讲解 React Hooks 的源码,只用最简单的方式来揭示 React Hooks 的原理和思想。 (我希望你看本文时,已经看过了上面一篇文章,因为本文会基于你已经了解部分 hooks 本质的前提下而展开的。例如你懂得 hooks 维护的状态其实是一个由闭包提供的。)
本文通过一个最近遇到了一个关于 React Hooks 的坑来展开讲解。一步一步地揭示如何更好地去理解 hooks,去了解函数式的魅力。
缘起
示例:https://codesandbox.io/s/brave-meadow-skl0o
function App() {
const [count, setCount] = useState(0);
const [isTag, setTag] = useState(false);
const onMouseMove = e => {
if (!isTag) {
return;
}
setCount(count + 1);
};
const onMouseUp = e => {
setTag(false);
};
const onMouseDown = e => {
setTag(true);
};
useEffect(() => {
document.addEventListener("mousemove", onMouseMove);
document.addEventListener("mouseup", onMouseUp);
return () => {
document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener("mouseup", onMouseUp);
};
}, []);
return (
<div className="App">
<h1 onMouseDown={
onMouseDown}>hello world</h1>
<h2>{
count}</h2>
</div>
);
}
对于一些事件绑定复杂的逻辑,我之前是这么写的,为了演示效果,去除了一些复杂的业务逻辑。
可以看到在这个示例中,我们的 count 始终为 0。这是为什么呢?是 setCount 出问题了?百思不得其解,在我们写 class 类式编程时,这是一个很常见的编程习惯。为什么到了 hooks 这里却不行了呢?
我们需要注意的一点是,现在编写的是函数式组件,可以说是函数式编程 (虽然不完全是,但是是这样的味道)。函数式编程的特点就是无副作用,输入输出一致性。但是对于前端一些 Dom,Bom 等 API 来说,无副作用是不可能的,事件的绑定,定时器等等都,都是有副作用的。。所以,为了处理这一部分的逻辑,React Hooks 提供了 useEffect 这个钩子来处理。所以说,我们看到的所有一些奇奇怪怪的地方,效果和理想不一致的情况,最终原因就是这个编程模式转变后,出现的"后遗症"。如果我们用函数式的思想来理解,这些问题都将会迎刃而解。
现在起,请你抛弃 class 模式的写法和更新方式,我们单从函数逻辑的角度来进行讲解。我们来看看,当 App 函数第一次运行时候各个值的状态。
function App() {
const [count -> 0, setCount] = useState(0);
const [isTag -> false, setTag] = useState(false);
const onMouseMove = e => {
if (!isTag -