Notice
Recent Posts
Recent Comments
Link
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
Tags
more
Archives
Today
Total
관리 메뉴

juni

React의 라이프사이클과 가상 DOM 관점에서 Hook과 메모이제이션 동작 본문

CS

React의 라이프사이클과 가상 DOM 관점에서 Hook과 메모이제이션 동작

juni_shin 2025. 3. 11. 16:27

1. 리액트의 렌더링 프로세스와 가상 DOM

const ChatRoom = () => {
  const [messages, setMessages] = useState<Message[]>([]);
  
  // 1. 렌더 단계 (Render Phase)
  console.log("컴포넌트 렌더링 시작");
  
  // 2. 커밋 단계 (Commit Phase)
  useEffect(() => {
    console.log("실제 DOM 업데이트 후 실행");
  });

  return <div>{/* JSX */}</div>;
};

랜더링 과정

  1. 랜더 단계: 가상 DOM 트리 생성
  2. 재조정: 이전 가상 DOM과 비교
  3. 커밋 단계: 실제 DOM 업데이트

2. 각 Hook/메모이제이션의 동작 시점

const ChatRoom = ({ roomId }) => {
  console.log("1. 컴포넌트 함수 실행 시작");

  // 2. useState - 렌더 단계 시작 시
  const [messages, setMessages] = useState<Message[]>([]);

  // 3. useMemo - 렌더 단계 동안
  const groupedMessages = useMemo(() => {
    console.log("3. 의존성이 변경된 경우만 실행");
    return groupMessagesByDate(messages);
  }, [messages]);

  // 4. useCallback - 렌더 단계 동안
  const handleSend = useCallback(() => {
    console.log("4. 의존성이 변경된 경우만 새로운 함수 생성");
    sendMessage(roomId);
  }, [roomId]);

  // 5. useEffect - 커밋 단계 이후
  useEffect(() => {
    console.log("5. DOM 업데이트 완료 후 실행");
    const subscription = subscribeToMessages(roomId);
    return () => subscription.unsubscribe();
  }, [roomId]);

  console.log("6. JSX 반환");
  return (
    <div>
      <MessageList messages={groupedMessages} />
      <SendButton onSend={handleSend} />
    </div>
  );
};

// React.memo - 컴포넌트의 렌더링 여부 결정
const MessageList = React.memo(({ messages }) => {
  console.log("MessageList - props가 변경된 경우만 렌더링");
  return (/* JSX */);
});

3. 라이프사이클과의 관계

const ChatApplication = () => {
  // 1. 마운트 단계 (Mounting)
  useEffect(() => {
    console.log("컴포넌트 마운트");
    return () => console.log("컴포넌트 언마운트");
  }, []);

  // 2. 업데이트 단계 (Updating)
  const [messages, setMessages] = useState<Message[]>([]);
  
  // React.memo로 불필요한 업데이트 방지
  const ChatHeader = React.memo(({ title }) => {
    console.log("헤더 컴포넌트 - props 변경 시에만 업데이트");
    return <h1>{title}</h1>;
  });

  // 특정 값 변경 시에만 실행되는 로직
  useEffect(() => {
    console.log("messages가 업데이트됨");
  }, [messages]);

  // 3. 클린업 (Cleanup)
  useEffect(() => {
    const subscription = setupChatConnection();
    // 언마운트 또는 의존성 변경 시 실행되는 클린업
    return () => {
      subscription.disconnect();
    };
  }, []);

  return (/* JSX */);
};

4. 최적화 관점에서의 동작

const ChatRoom = ({ roomId }) => {
  // 1. 가상 DOM 최적화
  const [messages, setMessages] = useState<Message[]>([]);

  // 2. 계산 최적화 (useMemo)
  const messageStatistics = useMemo(() => {
    console.log("무거운 계산 실행");
    return calculateStatistics(messages);
  }, [messages]);

  // 3. 함수 참조 최적화 (useCallback)
  const handleMessageUpdate = useCallback((newMessage) => {
    console.log("함수 재생성 방지");
    setMessages(prev => [...prev, newMessage]);
  }, []);

  // 4. 컴포넌트 렌더링 최적화 (React.memo)
  const MessageStats = React.memo(({ stats }) => {
    console.log("통계 컴포넌트 렌더링");
    return <div>{/* 통계 표시 */}</div>;
  });

  // 5. 사이드 이펙트 최적화 (useEffect)
  useEffect(() => {
    console.log("필요한 경우에만 구독 갱신");
    const subscription = subscribeToRoom(roomId, handleMessageUpdate);
    return () => subscription.unsubscribe();
  }, [roomId, handleMessageUpdate]);

  return (
    <div>
      <MessageList messages={messages} />
      <MessageStats stats={messageStatistics} />
    </div>
  );
};

5. 각 기능의 최적화 포인트

  • React.memo
    • 가상 DOM 비교 단계에서 작동
    • props 비교를 통해 불필요한 렌더링 트리 생성 방지
    • 메모리에 이전 렌더링 결과 저장
  • useMemo
    • 렌더링 중에 실행되는 계산 최적화
    • 의존성 배열의 값이 변경될 때만 재계산
    • 메모리에 계산 결과 캐싱
  • useCallback
    • 함수 인스턴스 재생성 방지
    • 자식 컴포넌트의 불필요한 리렌더링 방지
    • 모리에 함수 참조 유
  • useEffect
    • 커밋 단계 이후 실행
    • DOM 업데이트 완료 후 사이드 이펙트 처리
    • 클린업 함수를 통한 리소스 관