1. React 클래스형 컴포넌트 생명주기 메서드
클래스형 컴포넌트는 componentDidMount, componentDidUpdate, componentWillUnmount와 같은 생명주기 메서드를 사용하여 컴포넌트의 특정 시점에 원하는 작업을 수행할 수 있습니다.
componentDidMount
- 실행 시점: 컴포넌트가 처음으로 DOM에 삽입된 직후
- 용도: 초기 데이터 로드, 이벤트 리스너 등록, DOM 조작 등 초기화 작업
componentDidMount() {
console.log('컴포넌트가 마운트되었습니다.');
}
componentDidUpdate
- 실행 시점: 컴포넌트가 업데이트된 직후
- 용도: 이전과 현재의 상태나 props를 비교하여 추가 작업을 수행할 때 사용
componentDidUpdate(prevProps, prevState) {
if (prevProps.value !== this.props.value) {
console.log('컴포넌트가 업데이트되었습니다.');
}
}
componentWillUnmount
- 실행 시점: 컴포넌트가 DOM에서 제거되기 직전.
- 용도: 타이머 제거, 이벤트 리스너 해제, 데이터 구독 해제 등 정리 작업.
componentWillUnmount() {
console.log('컴포넌트가 언마운트됩니다.');
}
2. 함수형 컴포넌트의 생명주기
함수형 컴포넌트는 생명주기 메서드 대신 useEffect 훅을 사용하여 컴포넌트의 특정 시점에 작업을 수행합니다.
useEffect: componentDidMount, componentDidUpdate, componentWillUnmount의 역할을 모두 수행할 수 있는 다목적 훅입니다.
- 마운트 시 한 번만 실행: 빈 의존성 배열을 사용하여 마운트 시점에만 실행됩니다.
useEffect(() => {
console.log('컴포넌트가 마운트되었습니다.');
}, []);
- 업데이트 시마다 실행: 의존성 배열이 없으면 모든 렌더링 시점에 실행됩니다.
useEffect(() => {
console.log('컴포넌트가 업데이트되었습니다.');
});
- 언마운트 시 클린업: 리턴 함수에서 정리 작업을 수행합니다.
useEffect(() => {
return () => {
console.log('컴포넌트가 언마운트됩니다.');
};
}, []);
3. 함수형 컴포넌트의 최적화 방법
React에서는 불필요한 렌더링과 성능 문제를 해결하기 위해 useMemo, useCallback, React.memo 같은 최적화 도구를 제공합니다.
useMemo: 계산량이 많은 함수의 결과를 메모이제이션하여, 불필요한 재계산을 방지합니다.
- 사용 시점: 값이 변경되지 않으면 이전의 계산 결과를 재사용하고 싶을 때
const memoizedValue = useMemo(() => expensiveFunction(input), [input]);
useCallback: 함수 인스턴스를 메모이제이션하여, 컴포넌트가 다시 렌더링될 때마다 새로운 함수가 생성되지 않도록 합니다.
- 사용 시점: 함수의 참조가 변하지 않도록 유지하고 싶을 때
const handleClick = useCallback(() => {
console.log('버튼 클릭!');
}, []);
React.memo: 컴포넌트를 메모이제이션하여, props가 변경되지 않는 한 불필요한 재렌더링을 방지합니다.
- 사용 시점: 컴포넌트가 동일한 props로 불필요하게 다시 렌더링될 때
const MyComponent = React.memo(({ value }) => {
return <div>{value}</div>;
});
useMemo, useCallback, memo를 활용할 수 있는 과제:
import React, { useState } from 'react';
import './App.css';
/*
1. **최적화 적용**:
1. 주어진 기본 코드를 `useCallback`, `useMemo`, `React.memo`를 활용하여 최적화합니다.
2. `ListItem` 컴포넌트를 `React.memo`로 래핑하여, 컴포넌트가 불필요하게 재렌더링되지 않도록 합니다.
3. `items` 배열을 `useMemo`를 사용하여 메모이제이션하고, `filteredItems` 배열도 `useMemo`를 사용하여 메모이제이션합니다.
4. `handleItemClick` 함수를 `useCallback`으로 메모이제이션하여, 함수 인스턴스가 불필요하게 새로 생성되지 않도록 합니다.
2. **변경 사항 확인**:
1. 최적화 적용 후, 브라우저의 콘솔을 확인하여 `ListItem` 컴포넌트의 렌더링 로그를 통해 최적화가 올바르게 적용되었는지 확인합니다.
*/
// 리스트 항목 컴포넌트
const ListItem = ({ item, onClick }) => {
console.log(`Rendering ${item}`);
return <li onClick={() => onClick(item)}>{item}</li>;
};
const App = () => {
const [searchTerm, setSearchTerm] = useState('');
const [selectedItem, setSelectedItem] = useState(null);
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Fig', 'Grape'];
const filteredItems = items.filter((item) =>
item.toLowerCase().includes(searchTerm.toLowerCase())
);
const handleItemClick = (item) => {
setSelectedItem(item);
};
return (
<div className="app-wrapper">
<div className="app-container">
<input
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="Search..."
className="search-input"
/>
<ul className="item-list">
{filteredItems.map((item) => (
<ListItem key={item} item={item} onClick={handleItemClick} />
))}
</ul>
{selectedItem && (
<p className="selected-item">Selected Item: {selectedItem}</p>
)}
</div>
</div>
);
};
export default App;
과제 정답 코드:
import React, { memo, useCallback, useMemo, useState } from 'react';
import './App.css';
/*
1. **최적화 적용**:
1. 주어진 기본 코드를 `useCallback`, `useMemo`, `React.memo`를 활용하여 최적화합니다.
2. `ListItem` 컴포넌트를 `React.memo`로 래핑하여, 컴포넌트가 불필요하게 재렌더링되지 않도록 합니다.
3. `items` 배열을 `useMemo`를 사용하여 메모이제이션하고, `filteredItems` 배열도 `useMemo`를 사용하여 메모이제이션합니다.
4. `handleItemClick` 함수를 `useCallback`으로 메모이제이션하여, 함수 인스턴스가 불필요하게 새로 생성되지 않도록 합니다.
2. **변경 사항 확인**:
1. 최적화 적용 후, 브라우저의 콘솔을 확인하여 `ListItem` 컴포넌트의 렌더링 로그를 통해 최적화가 올바르게 적용되었는지 확인합니다.
*/
// 리스트 항목 컴포넌트
const ListItem = memo(({ item, onClick }) => {
console.log(`Rendering ${item}`);
return <li onClick={() => onClick(item)}>{item}</li>;
});
const App = () => {
const [searchTerm, setSearchTerm] = useState('');
const [selectedItem, setSelectedItem] = useState(null);
const items = useMemo(() => {
return ['Apple', 'Banana', 'Cherry', 'Date', 'Fig', 'Grape'];
}, []);
const filteredItems = useMemo(
() =>
items.filter((item) =>
item.toLowerCase().includes(searchTerm.toLowerCase())
),
[items, searchTerm]
);
const handleItemClick = useCallback((item) => {
setSelectedItem(item);
}, []);
return (
<div className="app-wrapper">
<div className="app-container">
<input
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="Search..."
className="search-input"
/>
<ul className="item-list">
{filteredItems.map((item) => (
<ListItem key={item} item={item} onClick={handleItemClick} />
))}
</ul>
{selectedItem && (
<p className="selected-item">Selected Item: {selectedItem}</p>
)}
</div>
</div>
);
};
export default App;
useMemo vs React.memo 차이점
- useMemo:
- 기능: 값을 메모이제이션하여 재계산을 피하는 훅입니다. 의존성 배열의 값이 변경되지 않는 한 이전에 계산된 값을 반환합니다.
- 사용 목적: 복잡한 계산 결과를 메모이제이션하거나 값이 변경되지 않는 한 불필요한 재계산을 방지합니다. 예를 들어, 리스트 필터링, 복잡한 객체 생성 등.
- 적용 대상: 계산된 값이나 함수의 반환값.
- React.memo:
- 기능: 컴포넌트를 메모이제이션하여, props가 변경되지 않는 한 컴포넌트를 재렌더링하지 않습니다.
- 사용 목적: 컴포넌트의 불필요한 재렌더링을 방지하여 성능을 최적화합니다.
- 적용 대상: React 컴포넌트.
요약:
- useMemo는 값을 메모이제이션하여 재계산을 방지하고,
- React.memo는 컴포넌트를 메모이제이션하여 불필요한 재렌더링을 방지합니다.
위 최적화를 적용하면 성능 개선이 이루어지며, 브라우저 콘솔에서 ListItem의 렌더링이 필요할 때만 발생하는지 확인해 최적화가 올바르게 적용되었는지 점검할 수 있습니다.
const filteredItems = useMemo(
() => items.filter((item) => item.toLowerCase().includes(searchTerm.toLowerCase())),
[items, searchTerm]
);
이 코드에서 useMemo의 두 번째 인자인 [items, searchTerm]은 의존성 배열입니다. 이 배열이 중요한 이유는 useMemo가 언제 콜백 함수를 실행해야 하는지를 결정하기 때문입니다.
이유:
- items: items 배열이 변경되면 filteredItems를 다시 계산해야 하기 때문에 의존성 배열에 포함합니다. 이 배열이 변경되지 않으면 filteredItems도 변경될 필요가 없으므로 재계산하지 않습니다.
- searchTerm: 사용자가 검색어를 입력할 때마다 searchTerm이 변경되며, 이에 따라 filteredItems도 달라져야 합니다. 의존성 배열에 searchTerm을 포함함으로써 사용자의 입력에 따라 필터링된 결과가 최신 상태로 유지됩니다.
의존성 배열의 역할:
- 의존성 배열의 값이 변경될 때만 useMemo의 콜백 함수가 다시 실행됩니다.
- 최적화 목적: 불필요한 재계산을 방지하고, items와 searchTerm이 동일하면 이전에 메모이제이션한 값을 재사용함으로써 성능을 개선합니다.
따라서 [items, searchTerm]를 의존성으로 설정하는 것은 filteredItems가 정확하게 필요한 시점에만 계산되도록 하여, 성능과 동작의 일관성을 유지하게 합니다.
'자기계발' 카테고리의 다른 글
번들링과 코드스플리팅 (1) | 2024.09.28 |
---|---|
React Developer Tools를 활용한 React 애플리케이션 성능 최적화 (0) | 2024.09.27 |
Redux Toolkit으로 전역상태 관리하기 (0) | 2024.09.26 |
Redux로 전역상태 관리하기 (0) | 2024.09.26 |
Context API (0) | 2024.09.26 |