• 티스토리 홈
  • 프로필사진
    루루개발자
  • 방명록
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
루루개발자
  • 프로필사진
    루루개발자
    • 분류 전체보기 (213)
      • react & next.js (13)
      • Node.js & Javascript & Type.. (24)
        • d3.js (10)
      • 차트 만들기 (1)
      • 티스토리 스킨 개발 (7)
      • 내가 만든 패키지 (3)
      • 내가 만든 CSS (1)
      • CSS (7)
      • 도커 & 쿠버네티스 (3)
      • 개인 프로젝트 (7)
      • 리뷰 & 추천 (2)
      • 알고리즘 (1)
      • IT 기타 (18)
      • 잡동사니 (1)
      • Spring Boot (5)
      • 취미로 그리는 그림들 (120)
      • 개인적인 생각들 (0)
  • 반응형
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
      등록된 댓글이 없습니다.
    • 최근 공지
        등록된 공지가 없습니다.
      # Home
      # 공지사항
      #
      # 태그
      # 검색결과
      # 방명록
      • 리액트 렌더링 시점 및 훅 호출 순서 확인해보기
        2022년 05월 16일
        • 루루개발자
        • 작성자
        • 2022.05.16.:00
        반응형


        안녕하세요. 루루개발자 입니다.
        요즘 한창 리액트 렌더링 시점과 훅 호출 순서 등에 대한 테스트를 진행해보고 있는데,
        테스트 과정 및 결과를 공유드리고자 합니다.

        먼저 다음과 같은 파일 및 코드가 있다고 가정해봅시다.

        -- index.tsx

        import { useCallback, useEffect, useState } from "react";
        import { AppTestBox } from "../../../src/components/boxes/app-test-box/app-test-box";
        import { useTest } from "../../../src/hooks/use-test-hook/use-test.hook";
        
        const Index = () => {
          const [count, setCount] = useState(() => {
            console.log('count useState() 호출됨');
            return 0;
          });
        
          const refHandler = useCallback((el: any) => {
            console.log('refHandler() 호출됨');
          }, []);
        
          useEffect(() => {
            console.log('첫번째 useEffect() 호출됨');
          }, []);
        
          const [count2, setCount2] = useState(() => {
            console.log('count2 useState() 호출됨');
            return 0;
          });
        
          const renderingCheck = useCallback(() => {
            console.log('렌더링됨');
            return '';
          }, []);
        
          useTest();
        
          useEffect(() => {
            console.log('두번째 useEffect() 호출됨');
          }, [count]);
        
          const countPlus = useCallback(() => {
            console.log('countPlus() 호출됨');
            setCount(count + 1);
          }, [count]);
        
          useEffect(() => {
            console.log('세번째 useEffect() 호출됨');
          });
        
          const countPlus2 = useCallback(() => {
            console.log('countPlus2() 호출됨');
            setCount2(count2 + 1);
          }, [count2]);
        
          return (
            <div ref={refHandler}>
              <AppTestBox
                callback={() => { console.log('AppTestBox 컴포넌트의 callback() 호출됨.') }}></AppTestBox>
              {
                renderingCheck()
              }
              <div>
                { count }<br />
                { count2 }
              </div>
              <button onClick={countPlus}>count 증가</button>
              <button onClick={countPlus2}>count2 증가</button>
            </div>
          );
        };
        
        export default Index;


        -- app-test-box.tsx

        import { useCallback, useEffect, useState } from "react";
        
        interface Props {
          callback: () => void;
        }
        
        export const AppTestBox = (props: Props) => {
          const [hookVar1, setHookVar1] = useState(() => {
            console.log('AppTestBox 컴포넌트의 hookVar1 useState() 호출됨.');
            return 0;
          });
        
          const [hookVar2, setHookVar2] = useState(() => {
            console.log('AppTestBox 컴포넌트의 hookVar2 useState() 호출됨.');
            return 0;
          });
        
          useEffect(() => {
            console.log('AppTestBox 컴포넌트의 첫번째 useEffect() 호출됨.');
          });
        
          const refHandler = useCallback((el: any) => {
            console.log('AppTestBox 컴포넌트의 refHandler() 호출됨.');
          }, []);
        
          const _callback = useCallback(() => {
            console.log('AppTestBox 렌더링됨.');
            props.callback();
            return (
              <div ref={refHandler}></div>
            );
          }, [props, refHandler]);
        
          return _callback();
        };


        -- use-test.hook.ts

        import { useEffect, useState } from "react";
        
        export const useTest = () => {
          const [hookVar1, setHookVar1] = useState(() => {
            console.log('useTest 훅의 hookVar1 useState() 호출됨.');
            return 0;
          });
        
          const [hookVar2, setHookVar2] = useState(() => {
            console.log('useTest 훅의 hookVar2 useState() 호출됨.');
            return 0;
          });
        
          useEffect(() => {
            console.log('useTest 훅의 첫번째 useEffect() 호출됨');
          });
        
          useEffect(() => {
            console.log('useTest 훅의 두번째 useEffect() 호출됨');
          });
        };



        index.tsx 파일은 페이지 컴포넌트이고, app-test-box.tsx 파일은 제가 만든 컴포넌트 입니다. use-test.hook.ts 파일 또한 제가 만든 커스텀 훅입니다.

        위 상태에서 index.tsx 페이지 컴포넌트에 접근하면 브라우저의 콘솔창은 아래와 같이 표시됩니다.


        1. 부모 컴포넌트의 useState 가 호출됩니다.
        2. 부모 컴포넌트에 명시된 커스텀 훅의 useState 가 호출됩니다.
        3. 부모 컴포넌트의 뷰(View)가 렌더링 됩니다.
        4. 자식 컴포넌트인 AppTestBox 의 useState 가 호출됩니다.
        5. 자식 컴포넌트인 AppTestBox 의 뷰(View)가 렌더링 됩니다.
        6. 자식 컴포넌트인 AppTestBox 에서 요소의 ref 속성에 넘겼던 콜백함수가 호출됩니다.
        7. 부모 컴포넌트에서 요소의 ref 속성에 넘겼던 콜백함수가 호출됩니다.
        8. 자식 컴포넌트인 AppTestBox 의 useEffect 함수들이 호출됩니다.
        9. 부모 컴포넌트에 명시된 useEffect 함수들이 호출됩니다.
        9-1. 작성한 순서에 따라 useEffect 함수는 순차적으로 호출됩니다.
        9-2. 부모컴포넌트에 작성된 useEffect 함수들 중간에 커스텀 훅이 존재하고 커스텀 훅 안에 useEffect 가 존재하면 커스텀 훅 안의 useEffect 가 호출되고, 그 다음에 명시된 부모컴포넌트의 useEffect 가 호출됩니다.


        위 결과로 인해 알 수 있는 점을 다음과 같이 정리해보았습니다.

        1. 요소의 ref 속성에 넘기는 콜백함수는 부모컴포넌트보다 자식컴포넌트에서 먼저 호출된다.
        2. 렌더링 되기 전에 해당 컴포넌트의 모든 useState 가 호출된다.
        3. 부모 컴포넌트의 뷰(View)가 렌더링 된 이후에 자식 컴포넌트의 useState 가 호출된다.
        4. 부모컴포넌트보다 자식컴포넌트의 useEffect 가 먼저 호출된다.
        5. 작성된 useEffect 함수 중간에 커스텀 훅이 존재하면 커스텀 훅 안에 존재하는 useEffect 가 모두 호출되고 그 다음 작성된 useEffect 가 호출된다.


        테스트를 진행해보고 결과를 정리해보니 모르고 있었던 부분들이 있었네요.테스트를 해보길 잘한 것 같습니다.

        읽어주셔서 감사합니다. :)

        반응형

        'react & next.js' 카테고리의 다른 글

        Next.js 에서 local, development, production 환경 셋팅하기  (0) 2022.10.13
        자식 컴포넌트에 전달하는 props 관련 테스트  (0) 2022.05.29
        react 에서 useEffect 가 2번 호출되는 현상 (두 번 렌더링 되는 현상)  (0) 2022.05.15
        리액트에 style 적용하는 방법 2가지  (0) 2022.05.08
        리액트 훅(react hook)에 대해  (0) 2022.05.07
        다음글
        다음 글이 없습니다.
        이전글
        이전 글이 없습니다.
        댓글
      조회된 결과가 없습니다.
      스킨 업데이트 안내
      현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
      ("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
      목차
      표시할 목차가 없습니다.
        • 안녕하세요
        • 감사해요
        • 잘있어요

        티스토리툴바