이번 포스팅은 오늘 하루 여닫을 수 있는 소식 목록을 구현하며 겪은 문제들을 정리하기 위해 작성한다.
// 기존 코드
const toggleNthIsOpen = (i: number) => {
setNewsData(prev => {
prev[i].isOpen = !prev[i].isOpen;
return [...prev];
});
};
기존 코드에서 객체 배열의 n번째 원소에 더 빠르게 접근하기 위해 인덱스로 타겟 객체를 직접 조작했다. useState
의 세터함수에서 이전 상태를 인자로 받을 때 직접 조작해도 side effect가 없기 때문에 위와 같이 구현했다.
하지만, React는 상태 변화를 감지할 때 얕은 비교(swallow comparison)를 하기 때문에 배열 내부의 객체 내부의 프로퍼티의 변화까지는 감지하지 못하는 문제가 있었다. 이를 위해 배열과 타겟 객체를 깊은 복사를 통해 변경 해주어야만 얕은 비교로도 상태의 변화를 감지할 수 있다. 변경된 코드는 아래와 같다.
// 해결
const toggleNthIsOpen = (i: number) => {
setNewsData(prev => {
prev[i] = { ...prev[i], isOpen: !prev[i].isOpen };
return [...prev];
});
};
외부 패키지를 이용하는 방법도 있다. (use-deep-compare)
https://bestofreactjs.com/repo/sandiiarov-use-deep-compare-react-awesome-react-hooks
Class component static getDerivedStateFromProps method
Function component bodies
State updater functions (the first argument to setState)
Functions passed to useState, useMemo, or useReducer
리액트는 strict-mode
에서 아래 목록에 해당하는 함수들을 두 번씩 호출한다.
constructor
, render
, shouldComponentUpdate
메서드getDerivedStateFromProps
메서드useState
, useMemo
, useReducer
함수들일단은 명식적으로 react 프로젝트의 use-strict모드를 꺼서 에러를 해결했지만, 리엑트의 철학이 무엇인지. 어떡하면 side-effect가 없는 순수함수 형태로 작성할 수 있을지 고민해야겠다.