提出问题

观察如下代码,我们需要依赖words来更新自身,所以需要将words加入useEffect的依赖中。更新words触发useEffectuseEffect再次更新words,然后就产生了死循环。

function App() {
  const [value, setValue] = useState('');
  const [words, setWords] = useState([
    {
      id: 0,
      text: 'like',
      correct: false,
    },
  ]);

  useEffect(() => {
    const items = value.split(' ');
    
    // 我们需要用words来更新自身
    const nextWords = words.map((word) => {
      return {
        ...word,
        correct: word.text === items[index],
      };
    });

    setWords(nextWords);
  }, [value, words]);

  return (
    <>
      <input
        type="text"
        value={value}
        onChange={(e) => setValue(e.target.value)}
      />
    </>
  );
}

分析问题

为了跳出useEffect的死循环,问题的关键是,我们不能在useEffect重更新依赖数组中的东西,否则必定产生死循环。那如何避免更新自己的依赖呢?答案是用一个新的变量来存储。

解决方案

我们创建了一个新的nextWords来保存更新后的words,避免了更新依赖项死循环的问题。

function App() {
  const [value, setValue] = useState('');
  const [words, setWords] = useState([
    {
      id: 0,
      text: 'like',
      correct: false,
    },
  ]);
  const [nextWords, setNextWords] = useState([])

  useEffect(() => {
    const items = value.split(' ');
    
    // 我们需要用words来更新自身
    const nextWords = words.map((word) => {
      return {
        ...word,
        correct: word.text === items[index],
      };
    });
    
    // 这里不会导致死循环,因为nextWords并非依赖项
    setNextWords(nextWords);
  }, [value, words]);

  return (
    <>
      <input
        type="text"
        value={value}
        onChange={(e) => setValue(e.target.value)}
      />
    </>
  );
}

热饭班长
3.7k 声望434 粉丝

先去做,做出一坨狗屎,再改进。