Open kangyana opened 2 years ago
来看一个计数器的例子:
const DelayedIncreaser = () => {
const [count, setCount] = useState(0);
const [increase, setShouldIncrease] = useState(false);
useEffect(() => {
if (increase) {
setInterval(() => {
setCount(count => count + 1)
}, 1000);
}
}, [increase]);
return (
<div>
<button onClick={() => setShouldIncrease(true)}>+</button>
<div>Count: {count}</div>
</div>
);
}
在点击按钮时,count
每秒会增加1。
但是当卸载组件的时,就会报错。
正确的用法是卸载前清理定时器:
useEffect(() => {
if (increase) {
const id = setInterval(() => {
setCount(count => count + 1)
}, 1000);
return () => clearInterval(id);
}
}, [increase]);
const count = useRef(0);
useEffect(() => {
console.log(count.current)
}, [count.current])
ref
的更新不会引起组件的渲染,所以不会调用 useEffect
函数。
不建议用 useState
保存 Map
,也不建议用 useEffect
监听 Map
。
1. useState 问题
不要使用旧的状态
先来看一个计数器的例子:
连续快速点击 加号按钮,很可能
count
没有达到预期的值。 这是因为setState
是异步的,状态在下一次渲染时才更新。 此时的count
就是旧值。正确用法是 函数式更新:不要在不需要重新渲染时使用 useState
看下面的例子:
因为
counter
没有用在渲染,所以点击第一个按钮不会触发渲染,setState
也在等待更新。 此时再点击第二个按钮,打印的counter
为旧值。这与期待不符。解决方案是,用
useRef
替代useState
。