오류확인.해결

React + Firebase 연동 시 화면 깜빡임과 리렌더링 최적화하기

emilyyoo 2024. 5. 18. 22:29
728x90

 

React에서 Firebase를 사용할 때 발생하는 문제

React와 Firebase를 연동하여 메뉴 관리 시스템을 구현할 때, 종종 화면이 깜빡이거나 스크롤이 초기화되는 문제가 발생한다. 이는 컴포넌트가 불필요하게 리렌더링되거나, Firebase에서 데이터를 불러오는 과정에서 useEffect가 과도하게 실행되기 때문이다. 본 글에서는 이러한 문제를 해결하는 방법을 상세히 설명한다.

문제 분석

1. 화면이 깜빡이고 스크롤이 초기화되는 현상

원인:

  • useEffect 내부에서 loadMenuItems()를 호출하여 상태(setMenuItems())를 업데이트함.
  • 상태가 변경될 때마다 컴포넌트가 리렌더링되며, 스크롤 위치가 초기화됨.
  • useEffect가 의존성 배열 없이 정의되어 있어, 데이터 변경 시마다 불필요하게 실행됨.

해결책:

  • useRef를 사용하여 useEffect가 최초 마운트 시에만 실행되도록 변경.
  • 데이터 변경 시 전체 목록을 다시 불러오는 것이 아니라, 변경된 데이터만 업데이트하도록 개선.

2. 불필요한 전체 리스트 리렌더링 문제

원인:

  • menuItems 상태가 변경될 때마다 전체 리스트가 다시 렌더링됨.
  • MenuItemCard 컴포넌트가 React.memo로 감싸져 있지만, onDelete, onAddOption, onDeleteOption 함수가 매번 새로 생성되기 때문에 props가 변경되어 React.memo의 최적화 효과가 사라짐.

해결책:

  • useCallback을 사용하여 함수가 재생성되지 않도록 개선.
  • 개별 아이템의 상태만 변경하고, 전체 리스트를 다시 불러오는 것을 방지.

3. Firebase 데이터 업데이트 방식 비효율 문제

문제점:

  • addOption과 handleDeleteOption에서 loadMenuItems()를 호출하여 전체 데이터를 다시 불러옴.
  • Firebase에서 데이터를 불러오는 과정에서 네트워크 트래픽이 증가하고, UI 성능이 저하됨.

해결책:

  • Firestore에서 특정 문서만 업데이트하도록 updateDoc을 활용.
  • menuItems 상태에서 변경된 데이터만 업데이트하여 UI의 불필요한 리렌더링을 방지.

최적화된 코드

1. useEffect 최적화

const isMounted = useRef(false);

useEffect(() => {
  if (!isMounted.current) {
    loadMenuItems();
    isMounted.current = true;
  }
}, []);

설명:

  • isMounted라는 useRef 변수를 사용하여, useEffect가 첫 번째 렌더링에서만 실행되도록 제한.
  • 불필요한 데이터 요청을 방지하여 성능을 향상시킴.

2. 함수 재생성을 방지하는 useCallback 적용

const handleDeleteItem = useCallback(async (itemId: string) => {
  await deleteMenuItem(itemId);
  setMenuItems((prev) => prev.filter((item) => item.id !== itemId));
}, [deleteMenuItem]);

설명:

  • useCallback을 사용하여 handleDeleteItem 함수가 필요할 때만 재생성되도록 함.
  • 이를 통해 React.memo가 적용된 MenuItemCard의 불필요한 리렌더링을 방지.

3. Firebase 데이터 업데이트 최적화

const addOption = useCallback(async (itemId: string, option: Option) => {
  const itemRef = doc(db, "menu", itemId);
  await updateDoc(itemRef, {
    options: [...menuItems.find((item) => item.id === itemId)?.options || [], option],
  });
  setMenuItems((prev) =>
    prev.map((item) =>
      item.id === itemId ? { ...item, options: [...(item.options || []), option] } : item
    )
  );
}, [menuItems]);

설명:

  • updateDoc을 사용하여 Firestore의 특정 문서만 업데이트.
  • 상태를 직접 수정하여 전체 데이터를 다시 불러오지 않음.
  • UI 리렌더링을 최소화하여 성능을 개선.

결론

Firebase와 React를 함께 사용할 때, 불필요한 리렌더링을 최소화하고 성능을 최적화하는 것이 중요하다. 본 글에서 소개한 방법을 적용하면, 데이터 업데이트 시 화면 깜빡임 없이 부드럽게 UI가 유지될 수 있다. 특히 useEffect, useCallback, useRef를 적절히 활용하면, Firebase와의 연동 성능을 크게 향상시킬 수 있다.

728x90