본문 바로가기

개발 공부/React

React.memo (1)

코드 출처 : https://github.com/Cluster-Taek/next14-boilerplate

 

GitHub - Cluster-Taek/next14-boilerplate

Contribute to Cluster-Taek/next14-boilerplate development by creating an account on GitHub.

github.com

 

 

auth-provider.tsx

'use client';

import Spinner from '@/components/common/spinner';
import { Session } from 'next-auth';
import { useSession } from 'next-auth/react';
import { usePathname, useRouter } from 'next/navigation';
import React, { PropsWithChildren, createContext, useContext, useEffect } from 'react';

interface IAuthContext {
  initialized: boolean;
  session: Session;
}

export const AuthContext = createContext<IAuthContext | null>(null);

export function useAuth() {
  const result = useContext(AuthContext);
  if (!result?.initialized) {
    throw new Error('Auth context must be used within a AuthProvider!');
  }
  return result;
}

const publicPageList = ['/login'];

const isPublicPage = (pathname: string) => {
  return publicPageList.includes(pathname);
};

const AuthProvider = ({ children }: PropsWithChildren) => {
  const router = useRouter();
  const pathname = usePathname();
  const { data: session, status } = useSession();
  const loading = status === 'loading';

  useEffect(() => {
    if (loading) {
      return;
    }

    if (session && isPublicPage(pathname)) {
      router.push('/');
    } else if (!session && !isPublicPage(pathname)) {
      router.push('/login');
    }
  }, [loading, router, session, pathname]);

  if (loading || (session && isPublicPage(pathname))) {
    return <Spinner />;
  }

  if (isPublicPage(pathname)) {
    return <>{children}</>;
  }

  if (!session?.user) {
    return <Spinner />;
  }

  return <AuthContext.Provider value={{ initialized: true, session }}>{children}</AuthContext.Provider>;
};

export default React.memo(AuthProvider);

 

export default React.memo(AuthProvider)

  • AuthProvider 컴포넌트의 재렌더링을 최적화하기 위한 코드입니다.
  • 인증 상태(session, status, pathname)가 변경되지 않는다면, AuthProvider는 재렌더링되지 않습니다.
  • 따라서 성능을 향상시키고, 불필요한 렌더링으로 인한 비용을 줄일 수 있습니다.

React.memo의 역할

React.memo는 컴포넌트를 메모이제이션하여 불필요한 재렌더링을 방지하는 고차 컴포넌트(Higher Order Component, HOC)입니다.
React.memo로 감싼 컴포넌트는 props가 변경되지 않는 한, 재렌더링되지 않습니다.

즉, 동일한 props가 전달되면 React는 이전 렌더링 결과를 재사용합니다.


AuthProvider에서 React.memo를 사용하는 이유

AuthProvider는 인증 관련 상태와 로직을 관리하는 상위 컴포넌트입니다.
상위 컴포넌트가 재렌더링되면 자식 컴포넌트들도 영향을 받아 불필요하게 렌더링될 가능성이 있습니다.
이를 방지하기 위해 AuthProvider를 메모이제이션하여, 상위 컴포넌트의 재렌더링이 AuthProvider에 영향을 미치지 않도록 한 것입니다.


React.memo의 동작 조건

React.memo는 전달된 props를 이전 렌더링 시점의 props와 비교합니다.

  • 변경되지 않은 경우: 이전 렌더링 결과를 재사용 (컴포넌트 재렌더링 방지)
  • 변경된 경우: 새로운 렌더링 수행

얕은 비교의 의미

  • 객체, 배열, 함수 등의 참조값(메모리 주소)을 비교합니다.
  • 기본 타입(숫자, 문자열, 불리언)은 값 자체를 비교합니다.

AuthProvider의 경우

AuthProvider는 React.memo로 감싸져 있기 때문에, 부모 컴포넌트에서 전달된 props가 변경되지 않으면 재렌더링되지 않습니다.

  • AuthProvider는 props를 받지 않고 있습니다.
  • 따라서 부모 컴포넌트에서 변경될 props가 없기 때문에 기본적으로 재렌더링이 방지됩니다.

AuthProvider가 언제 재렌더링되는가?

  • AuthProvider 내부에서 사용되는 값들은 모두 자체 상태(state), context, 또는 React Hook(useSession, usePathname)을 통해 관리되고 있습니다.
  • React.memo는 props 외의 상태 변경에는 영향을 주지 못하므로 다음과 같은 상황에서는 재렌더링이 발생합니다
  1. useSession 값 변경
    • session이나 status가 변경되면 AuthProvider는 내부적으로 상태가 업데이트되며 재렌더링됩니다.
  2. usePathname 값 변경
    • 사용자가 다른 경로로 이동하면 pathname이 변경되며 AuthProvider가 재렌더링됩니다.
  3. 내부 상태나 Context 변경
    • AuthContext.Provider에서 전달된 값이 변경되면, Context를 사용하는 자식 컴포넌트에도 영향을 미칩니다.

 

'개발 공부 > React' 카테고리의 다른 글

React.memo (3) - useMemo  (0) 2025.01.27
React.memo (2)  (0) 2025.01.24
NextAuth.js 요약  (1) 2025.01.19
NextAuth.js 사용자 인증 로직 (3) NextAuth 동작 방식  (0) 2025.01.19
NextAuth.js 사용자 인증 로직 (2)  (1) 2025.01.12