useState 의 상태값을 변경해서 전체가 리랜더링 된다고 해도,
useCallback 같은 메모이제이션 내에 포함된 상태는, 초기화 리스트인 [ ]에 직접적으로 추가하지 않으면, 그 상태는 상위 컴포넌트와 무관하게 변경되지 않는다.
예시코드
const [isUpdate, setIsUpdate] = useState(false)
useEffect(() => {
if (isUpdatingItemText) {
updateText();
setIsUpdate(false);
}
}, [isUpdate]);
const renderItem = useCallback(
({ item, index, drag, isActive }: RenderItemParams<any>) => {
return (
{isUpdate ? (
<ActivityIndicator />
) : (
<Button
onPress={() => {
setIsUpdate(true);
}}
/>
},
[isUpdate] //<- 여기에 isUpdate를 쓰는걸 놓치는 실수를 함.
);
return ( ... ) //위에 저것을 빼먹으니 여기서 암만 변경된 상태를 리랜더링 해봤자 renderItem 내의 isUpdate 값은 변하지 않는다.
// 그러니 ActivityIndicator가 나오지 않더라.
너무 바보같고 기초적인 실수라, 기록으로 남긴다.
기록으로 안남기면, 분명히 이런 실수를 또 만날 것 같고, 그때 또 몇시간 쓸 것 같아서...
데이터 저장시에 약간의 딜레이가 약 1초정도 있어서
그 잠깐 사이, UI 에서 ActivityIndicator
를 보여주려고 함.
const [isUpdate, setIsUpdate] = useState(false)
저장을 누르면 setIsUpdate(true) 로 하고
isUpdate
를 useEffect 로 감지, 변환하도록 수정.
원래 이대로면 되어야 하는데, 이상하게도 ActivityIndicator
가 전혀 출력되지 않음. 맨처음엔 UI 랜더링이 느린건가 싶었는데, 그게 아니었다.
진짜 문제는
{isUpdate ? (
<ActivityIndicator
size={24}
color={getTheme().color.mainFont}
/>
) : ()...
}
이 코드가 useCallback()
안에 포함되어 있었는데, useCallback()
의 DependencyList
파라미터로 isUpdate
상태를 추가하는 것을 깜빡함.
즉, isUpdate
가 상태가 아무리 변하고, 리랜더링이 되더라도useCallback
내의 컴포넌트는 영향을 받지 않고 isUpdate
는 영원히 false
상태였던 것.
오늘도 1 바보 했다. 그런데 useState의 값이 반영이 안되는 case가 있을거라곤 상상도 못하긴 했으니, 배움이 가치있긴 했다.