[TIL] useCallback 과 useState 사용시 작은실수

햄스터아저씨·2022년 1월 19일
0

오늘의 배움

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가 있을거라곤 상상도 못하긴 했으니, 배움이 가치있긴 했다.

profile
서버도 하고 웹도 하고 시스템이나 인프라나 네트워크나 그냥 다 함.

0개의 댓글