juni
React의 라이프사이클과 가상 DOM 관점에서 Hook과 메모이제이션 동작 본문
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>;
};
랜더링 과정
- 랜더 단계: 가상 DOM 트리 생성
- 재조정: 이전 가상 DOM과 비교
- 커밋 단계: 실제 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 업데이트 완료 후 사이드 이펙트 처리
- 클린업 함수를 통한 리소스 관리
'CS' 카테고리의 다른 글
HTML 이스케이프 (1) | 2025.02.27 |
---|---|
프론트엔드 ( CS 정리 ) (0) | 2025.01.23 |
프론트엔드 CS 정리 6~10 (0) | 2025.01.15 |
프론트엔드 CS 정리 1~5 (0) | 2025.01.14 |
Next.js / React ( translate, translate3d, duration, cva, quill에디터 폰트 흐려짐[미해결] ) (0) | 2024.11.11 |