게으른개발너D

부모 컴포넌트에서 useState 사용에 따른 리로딩 (feat. setTimeout) 본문

개발/ReactJS

부모 컴포넌트에서 useState 사용에 따른 리로딩 (feat. setTimeout)

lazyhysong 2023. 6. 5. 15:33


Player 기능을 개발하는 도중 Player Component 안에서 사용하는 state들이 불필요하게 반복 호출된다는 점을 알게되었다.

아래는 페이지를 새로고침했을 때의 영상이다.

console log로 몇번 호출하는지 count를 새보니 3번이나 반복 호출된다.

 

처음에는 Player component 안에서 사용하는 useEffect때문인줄 알았다.

useEffect 안에서 state값을 변경하면 컴포넌트 위에서부터 state 값을 다시 호출하기 때문이다.

 

function CocoPlayer() {
  const playList = useRecoilValue(playListState);
  const [nowPlayingIdx, setNowPlayingIdx] = useState(savedNowPlaying.index);
  const [nowPlaying, setNowPlaying] = useState(savedNowPlaying.track);
  const [isPlay, setIsPlay] = useState(false);
  const [isNewMusic, setIsNewMusic] = useState(true);
  const [cocoAudio, setCocoAudio] = useState(new Audio(savedNowPlaying.track.preview));
  const [progressSize, setProgressSize] = useState(1);
  const [progress, setProgress] = useState(0);
  const [durationTime, setDurationTime] = useState(0);
  const [playTime, setPlayTime] = useState(0);

  useEffect(() => {
    cocoAudioSetting();
    setIsNewMusic(true);
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [nowPlaying]);
  
  useEffect(() => {
    console.log("타이머 useEffect", count)
    let progressTimer: any;
    if(isPlay) {
      progressTimer = setInterval(adjustProgress, 1000);
      return () => clearInterval(progressTimer);
    } else {
      clearInterval(progressTimer);
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isPlay]);
  
  ...

하지만 state들의 처음 세팅 값과 useEffect의 첫호출에서 state 세팅값이 같기때문에 다시 호출될 필요가 없다.

세팅 값이 다르더라도 굳이 왜?? 세번이나 호출되지??? 하고 별 짓을 다하였다.

문제는 부모 component에 있었다.

 

 

화면상  Base.tsx 컴포넌트를 layout으로 두고 그 안에 Sidemenu와 Player 컴포넌트, Router children인 Outlet을 넣었다.

영상을 보면 화면을 새로고침했을때 초록색점에 화면을 뒤덮었다가 사라지는 효과를 볼 수 있다.

해당 효과를 넣은 Base.tsx

function Base() {
  const [pageFade, setPageFade] = useState(false);
  
  useEffect(() => {
    setPageFade(true);
    setTimeout(() => setPageFade(false), 1000);
  }, []);
  
  return <>
    <BaseLayoutContainer>
      <CocoMainContainer>
        <SideMenu />
        <Outlet />
      </CocoMainContainer>
    </BaseLayoutContainer>

    {/* player */}
    <CocoPlayer />

    { pageFade ? <PageFadeIn /> : null }
    
  </>;
}

pageFade라는 state를 만들고 pageFade가 true면 초록이 효과를 주고, false면 없어지게 만들었다.

처음엔 false로 세팅한 후 useEffect 안에서 true로 변경하고 setTimeout으로 1초 후 false로 변경되게 만들었다.

이 과정에서 컴포넌트가 불필요하게 두번이나 더 호출되는 것이다,ㅋㅋㅋㅋㅋㅋㅋㅋ ㅠㅠ

부모 컴포넌트가 리로딩되면 그 안에 자식 컴포넌트들도 당연히 다시 호출된다.

 

1번 정상호출

2번 useEffect에서 pageFade 값이 true로 바꿔주었으므로 다시 호출

3번 setTimeout으로 pageFade 값이 1초후에 false로 바뀌므로 다시 호출

 

ㅠㅠ..

 

그래서 페이지 효과는 그냥 지웠다.

 

자식 컴포넌트가 있는 곳에선 불필요한 state 값 변경은 자제해야겠다.

그리고 로직이 어떻게 흘러가는지 계속 생각하면서 코드를 짜야될 듯하다.

Comments