React 的 useState 踩坑

168 阅读1分钟

先看段代码:

import {useState, useEffect} from 'react'

function Example() {
  const [waitlist, setWaitlist] = useState([]);
  const [,forceUpdate] = useState({})
  const [num, setNum] = useState(0);

  useEffect(() => {
    const id = setInterval(() => {
      setNum(num + 1)
      console.log('id: ' + id + ', num: ' + num)
      waitlist.push(Math.random())
      setWaitlist(waitlist)
    }, 1000);
    return () => clearInterval(id)
  }, []);

  function handleUpdate() {
    console.log(waitlist)
    forceUpdate({})
  }

  return (
    <div>
      <h2>test</h2>
      <div><button onClick={forceUpdate}>force</button></div>
      <div>{num}</div>
      <ol>
        {waitlist.map((name) => (
          <li key={name}>{name}</li>
        ))}
      </ol>
    </div>
  )
}

function App() {
  return (
    <div className="App">
      <Example />
    </div>
  );
}

export default App;

运行结果:控制台输出信息可知 waitlist 数组在不断新增数据项,但view却并未更新; 解决方法,有几种(每种都可单独用):

  1. setWaitlist(waitlist) 改成 setWaitlist(Array.from(waitlist));
  2. setNum(num + 1) 改成 setNum(c => c + 1);
  3. 如上定一个const [,forceUpdate] = useState({}) 专门负责 forceUpdate;

后记,由于React设计哲学是基于函数式编程,组件会被渲染多次,即上面的组件代码(同一个组件)会被执行多次,因此有很多面向对象或基于对象的编程习惯和思想会与之产生冲突,试着接受和习惯就好。