提出問題
觀察如下代碼,我們需要依賴words來更新自身,所以需要將words加入useEffect的依賴中。更新words觸發useEffect,useEffect再次更新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)}
/>
</>
);
}