[React] 在useEffect中使用 setState造成無限重複渲染

張庭瑋
3 min readMay 25, 2021

--

如果有使用 eslint之類的工具,總是會在把 useEffect的 dependency補齊時發出警告

這裡我有個 list,需要在每次 props.data更新時同時更新 list

const [list, setList] = useState({});useEffect(() => {  const newList = props.data.reduce((obj, item) => {      obj[item.id] = list[item.id] || false;      return obj;    }  , {});  setList(newList);}, [props.data]);

這時 eslint會提醒將 list加入 dependency中(而且是以紅字),但加入會發生什麼事?

}, [ list, props.data]);

在第一次觸發 useEffect後,馬上因為呼叫了 setList而再次觸發 useEffect,就這樣一直無限循環,難道這裡只能拿掉 dependency了嗎?

當然最好不要,拿掉 dependency代表 list的值無法更新,可能會引起未知的 bug,這裡可以使用 useRef來解決

在 useEffect前使用 useRef來儲存舊的 list

const oldListRef = useRef();oldListRef.current = list;

然後在 useEffect中不使用 list,而是 oldListRef.current

useEffect(() => {  const newList = props.data.reduce((obj, item) => {      obj[item.id] = oldListRef.current[item.id] || false;      return obj;    }  , {});  setList(newList);}, [props.data]);

這樣就可以讓 useEffect中可以拿到新的list值,也不會因為把list 加入dependency而進入無窮迴圈了

整體:

const [list, setList] = useState({});
const oldListRef = useRef();
oldListRef.current = list;useEffect(() => { const newList = props.data.reduce((obj, item) => { obj[item.id] = oldListRef.current[item.id] || false; return obj; } , {}); setList(newList);}, [props.data]);

--

--

No responses yet