Post

state가 변경되고, 다음 줄의 코드가 실행되도록 설정하기

유튜브를 따라 만드는 사이드 프로젝트를 진행하던 중 keyword를 누르면, keyword의 index 값은 변경된 값이 적용되지만 변경된 keyword의 값으로 데이터를 받아오지 못하는 오류가 발생

이미지예시

@원인

  • state를 변경하는 함수인 setState는 전부 비동기적으로 처리가 되기때문에, setState 함수가 오래걸리면 다음줄의 코드부터 실행됨

  • 현재 키워드를 바꾸는 setCurrentIndex(idx)값보다 새로운 데이터를 가져오는 refetch()가 먼저 실행되고 있었음

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 변경 전 코드
const Home = () => {
  const [currentTabIndex, setCurrentTabIndex] = useState(0);

  return (
    <KeywordContainer theme={theme}>
      {keywords.map(({ keyword }, idx) => (
        <Keyword
          key={keyword}
          onClick={() => {
            setCurrentTabIndex(idx);
            refetch();
          }}
          className={idx === currentTabIndex ? "isActive" : ""}
        >
          <p># {keyword}</p>
        </Keyword>
      ))}
    </KeywordContainer>
  );
};

@해결하기

  • useEffect를 사용해서 해당 state가 변경될 때만 useEffect()가 실행되도록 설정
  • 키워드를 클릭하면 currentTabIndex가 변경되도록 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 변경 후 코드
const Home = () => {
  const [currentTabIndex, setCurrentTabIndex] = useState(0);

  // currentTabIndex가 변경될 때만 refetch함수가 실행
  useEffect(() => {
    refetch();
  }, [currentTabIndex]);

  return (
    // 중략...
    <KeywordContainer theme={theme}>
      {keywords.map(({ keyword }, idx) => (
        <Keyword
          key={keyword}
          onClick={() => setCurrentTabIndex(idx)}
          className={idx === currentTabIndex ? "isActive" : ""}
        >
          <p># {keyword}</p>
        </Keyword>
      ))}
    </KeywordContainer>
  );
};

@또 다른 오류

  • useEffect()는 컴포넌트가 처음 렌더될 때 함께 실행되기 때문에 state가 변경될 때만 실행되어야하는 함수가 실행됨
  • currentTabIndex가 변경될 때만 새로운 데이터를 가져오는 refetch()함수가 처음 렌더될 때 실행됨

해결: @useRef 훅을 사용해 첫 렌더될 때 실행 막기

  • 첫 렌더될 때 isMounted의 값이 true 값으로 바뀌고, currentTabIndex가 변경될 때마다 useEffect가 실행됨
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// useRef()로 렌더 막기
const Home = () => {
  const [currentTabIndex, setCurrentTabIndex] = useState(0);
  const isMounted = useRef(false);

  useEffect(() => {
    if (isMounted.current) {
      refetch();
    } else {
      isMounted.current = true;
    }
  }, [currentTabIndex]);

  return (
    // 중략...
    <KeywordContainer theme={theme}>
      {keywords.map(({ keyword }, idx) => (
        <Keyword
          key={keyword}
          onClick={() => setCurrentTabIndex(idx)}
          className={idx === currentTabIndex ? "isActive" : ""}
        >
          <p># {keyword}</p>
        </Keyword>
      ))}
    </KeywordContainer>
  );
};

참고사이트

This post is licensed under CC BY 4.0 by the author.