kangyana / daily-question

When your heart is set on something, you get closer to your goal with each passing day.
https://www.webpack.top
MIT License
3 stars 0 forks source link

【Q070】React Hooks 使用中常见问题 #70

Open kangyana opened 2 years ago

kangyana commented 2 years ago

1. useState 问题

不要使用旧的状态

先来看一个计数器的例子:

const Increaser = () => {
  const [count, setCount] = useState(0);

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>+</button>
      <div>Counter: {count}</div>
    </div>
  );
}

连续快速点击 加号按钮,很可能 count 没有达到预期的值。 这是因为 setState 是异步的,状态在下一次渲染时才更新。 此时的 count 就是旧值。正确用法是 函数式更新

<button onClick={() => setCount(_count => _count+ 1)}>+</button>

不要在不需要重新渲染时使用 useState

看下面的例子:

const Counter = () => {
  const [counter, setCounter] = useState(0);

  return (
    <div>
      <button onClick={() =>  setCounter(_count => _count + 1)}>Counter</button>
      <button onClick={() => console.log(counter)}>Counter Log</button>
    </div>
  );
}

因为 counter 没有用在渲染,所以点击第一个按钮不会触发渲染,setState 也在等待更新。 此时再点击第二个按钮,打印的 counter 为旧值。这与期待不符。

解决方案是,用 useRef 替代 useState

const counter = useRef(0);

<button onClick={() =>  counter.current++}>Counter</button>
<button onClick={() => console.log(counter.current)}>Counter Log</button>
kangyana commented 2 years ago

2. useEffect 问题

不要忘记清理副作用

来看一个计数器的例子:

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]);

不要使用 ref 作为 useEffect 的依赖

const count = useRef(0);

useEffect(() => {
  console.log(count.current)
}, [count.current])

ref 的更新不会引起组件的渲染,所以不会调用 useEffect 函数。

3. Map数据

不建议用 useState 保存 Map,也不建议用 useEffect 监听 Map