교육 (Today I Learned)/Hanaro

[Hanaro] 27일차 / React (Hooks- useEffect, useLayoutEffect, useCallback)

Bay Im 2024. 2. 23. 09:36

02 React Hooks

  • useEffect
    • useEffect call twice
      • 개발환경 + Strict Mode에서 의존 관계 배열이 비워져있을 때 2회 호출 (Mount - UnMount - Mount)
        • Mount는 컴포넌트가 최초로 나타낼 때, UnMount는 사라질 때
        • rendering은 컴포넌트가 Mount 된 후 컴포넌트가 호출 될 때
      • cleanup 해주고 2회 호출되어도 안전한 코딩을 해야함 (ex. timer, eventListener, data, add, remove)
      • 예시
        • const [goodSec, setGoodSec] = useState(0);
          useEffect(() => {
            const intl = setInterval(() => {
              setGoodSec((pre) => pre + 1);
            }, 1000);
          
            return () => clearInterval(intl);
          }, []);
          …
    • useEffect with Promise
      • Promise는 실행될 때 callback 함수를 background로 제어를 넘긴다.
      • re-render 등으로 UnMount시 Promise는 background에 존재하므로 cleanup 되지 않는다.
      • cleanup 코드에서 Promise를 중지(abort)해줘야 2번 render되지 않는다.
        • controller = new AbortContoller();
        • const { signal } = controller;
        • fetch(url, { signal });
    • useRef with useEffect
      • componentDidMount 되기 전에 DOM 참조 안된다.
      • <element ref={xRef} />: 여기서 element가 Mount되기 전에는 xRef는 undefined | null
      • 자식의 DOM을 useRef로 참조 시 forwardRef + useEffect 필수
      • 예시
        • Login.userIdRef input에 focus 주기
        const Login = () => {
          …
          useEffect(() => {
            console.log('Login, please!');
            userIdRef.current?.focus();
            return () => {
              console.log('로그인 되셨어요');
            };
          }, []);  // 단 1번의 효과
        }
        
        • 컴포넌트 외부에서 DOM을 올바르게 참조하기
        // My.tsx
        {session.loginUser ? <Profile ref={logoutBtnRef} /> : <Login />}
        
        // Profile.tsx
        const Profile = forwardRef((props, ref) => {
          …
        <button ref={ref}>Logout</button>
        
        Profile.displayName = 'Profile';
        
  • useLayoutEffect
    • useLayoutEffect란
      • layou(render-tree) 직후 mount(painting) 전 동기적으로 실행 (DOM을 화면에 그리기 직전에 호출)
      • rendering → useLayoutEffect → [painting & display 동시(비동기) useEffect(didMount)]
      • DOM의 좌표와 크기 등은 모두 결정된 후 화면에 그리기 전에 완료해야 하므로 동기(sync, block)로 실행
      • useEffect와 같이 claenup 및 의존 관계 배열 사용은 동일
    • 사용
      • 예시
      useLayoutEffect(() => { // ← 만약 useEffect로 하면 거의(컴퓨터가 빠르면 찰나의 차이) 동일
        window.addEventListener('mousemove', catchMousePosition);
      
        return () => window.removeEventListener('mousemove', catchMousePosition);
      })
      
      
    • useEffect와 useLayoutEffect의 차이
      • useEffect
        • mount 직후 (painting과 비동기로 실행)
      • useLayoutEffect
        • rendering 직후 mount(painting) 전 실행
  • useCallback
    • useCallback이란
      • 특정 함수를 새로 만들지 않고 재사용하고 싶을 때 사용 (함수 cache)
      • 메모화된 함수는 자식 컴포넌트에서 re-render시 재호출 방지
      • 한 번만 생성되어야 하는 함수를 전달할 때 사용
    • 사용
      • 기본 형태
      const 메모화된_함수 = useCallback(() => { 
         함수_코드;       // 실행 시 평가되고, 평가된 바이트코드를 FunctionDeclarations에 등록 ⇒ memoization
       }, [의존관계배열]);