728x90
728x90
코드 분할(Code Splitting) : useTransition 훅, Suspense 컴포넌트, lazy 함수
들어가며
- 리액트(React.js)에서 코드 분할(Code Splitting)의 장점과 함께 사용되는 @useTransition@ 훅과 @Suspense@ 컴포넌트, @lazy@ 함수에 대해 정리해본다.
코드 분할(Code Splitting)
개념
- 리액트 애플리케이션에서 코드의 일부분을 나눠서 필요한 시점에 로드하는 방식
장점
- 애플리케이션을 더 작은 청크(Chunk)로 나눔으로써 초기 로드 시 필요한 자바스크립트 크기를 줄인다.
- 이를 통해 첫 화면 렌더링 속도가 빨라지며, 느린 네트워크 환경에서도 빠르게 응답할 수 있다.
- 사용자가 필요로 하지 않는 코드는 나중에 로드되며, 상호작용할 때만 필요한 코드가 동적으로 로드되어 매끄러운 사용자 경험을 제공한다.
- 페이지 간 트래픽 비율에 따라 중요한 리소스를 우선적으로 로드하고, 덜 중요한 리소스는 나중에 로드할 수 있어 성능을 최적화(Optimization)할 수 있다.
useTransition 훅
개념
- React 18에서 도입되었으며, 비동기 상태 업데이트를 처리할 때 UI의 응답성을 개선하는 데 사용된다.
- 주로 UI 작업의 우선순위를 설정해 중요한 작업은 즉시 처리하고, 덜 중요한 작업은 비동기적으로 처리하는데 사용된다.
- 복잡한 작업이나 데이터 로드 시 UI 성능을 유지하는 데 유용하다.
사용 방법
- @isPending@은 비동기 작업이 진행 중인지를 나타낸다.
- 전환이 완료되면 @false@가 된다.
- @startTransition@은 우선순위가 낮은 작업을 비동기로 처리하여 UI 응답성을 유지한다.
import { useTransition } from 'react';
const [isPending, startTransition] = useTransition();
const handleClick = () => {
startTransition(() => {
// 우선순위가 낮은 상태 업데이트
setState(someExpensiveOperation());
});
};
사용 예
- 아래와 같이 @useTransition@ 훅을 이용하여 UI가 버벅거리지 않고 필터링 작업이 완료될 때까지 로딩 메시지(@isPending@에 따른 상태)로 사용자에게 피드백을 제공할 수 있다.
import { useState, useTransition } from "react";
// 랜덤 아이템 생성 함수
function generateItems() {
return Array.from({ length: 5000 }, (_, i) => `Item ${i + 1}`);
}
function FilterableList() {
const [query, setQuery] = useState(""); // 검색어 상태
const [list, setList] = useState(generateItems()); // 검색어 리스트
const [isPending, startTransition] = useTransition();
// 검색어 변경 시 필터링 작업을 처리
const handleInputChange = (e) => {
const inputValue = e.target.value;
setQuery(inputValue); // 검색어 상태 즉시 업데이트
// '필터링' 작업은 우선순위가 낮은 작업으로 처리하기
startTransition(() => {
const filteredList = generateItems().filter((item) =>
item.toLowerCase().includes(inputValue.toLowerCase())
);
setList(filteredList); // (필터링 작업 후) 검색어 리스트 업데이트
});
};
return (
<div>
<input
type="text"
value={query}
onChange={handleInputChange}
placeholder="Search..."
/>
{isPending ? <p>Updating List...</p> : null} {/* isPending으로 로딩 상태 표시하기 */}
<ul>
{list.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
}
export default FilterableList;
Suspense 컴포넌트
개념
- 코드 분할이나 비동기 로딩 시, 컴포넌트가 로드될 때까지의 대기 상태를 처리하는 리액트 컴포넌트
- 주로 동적 임포트나 비동기 렌더링이 필요한 상황에서 로딩 중 UI를 지정할 수 있게 해준다.
사용 방법
- @fallback@ 속성에 로드 중에 표시할 컴포넌트를 지정한다.
- 로딩 중 스피너(Spinner)나 텍스트 등을 지정할 수 있다.
import { Suspense } from 'react';
<Suspense fallback={<div>Loading...</div>}>
<LazyLoadedComponent />
</Suspense>
lazy 함수
개념
- 동적으로 컴포넌트를 로드하는 데 사용된다.
- 코드 분할을 통해 애플리케이션의 특정 컴포넌트를 필요한 시점에 로드할 수 있게 해준다.
- @Suspense@ 컴포넌트와 함께 사용된다.
- @lazy@를 사용하면, 해당 컴포넌트가 필요할 때만 동적으로 @import@ 된다.
- 이를 통해 처음부터 모든 코드를 불러오지 않고, 사용자가 특정 동작을 했을 때만 관련 코드를 로드하는 방식으로 애플리케이션의 성능을 크게 향상시킬 수 있다.
사용 방법
const LazyLoadedComponent = lazy(() => import('./LazyComponent'));
function MyComponent() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyLoadedComponent />
</Suspense>
);
}
정리
- 코드 분할(Code Splitting)
- 성능 최적화 및 사용자 경험 개선에 도움이 되는 기법
- 초기 로드 시 모든 코드를 불러오는 대신, 필요한 시점에 코드를 동적으로 로드하여 성능을 향상시킨다.
- @useTransition@ 훅
- 우선 순위가 낮은 작업을 비동기 처리한다.
- 사용자 인터페이스가 버벅거리는 것을 방지한다.
- @Suspense@ 컴포넌트
- 비동기적으로 로드되는 컴포넌트가 준비될 때까지 로딩 상태를 처리해준다.
- 로딩 중에 표시할 UI를 제공한다.
- @lazy@ 함수
- 동적으로 컴포넌트를 로드하여 불필요한 코드가 한 번에 로드되는 것을 방지한다.
- 코드 분할을 쉽게 할 수 있도록 도와준다.
종합 사용 예제
import { useState, useTransition, lazy, Suspense } from 'react';
const SlowComponent = lazy(() => import('./components/SlowComponent'));
const UseTransitionSuspenseExample = () => {
const [text, setText] = useState('');
const [items, setItems] = useState([]);
const [show, setShow] = useState(false);
const [isPending, startTransition] = useTransition();
const handleChange = (e) => {
setText(e.target.value);
startTransition(() => {
const newItems = Array.from({ length: 200 }, (_, index) => {
return (
<div key={index}>
<img
src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSlGmKtrnxElpqw3AExKXPWWBulcwjlvDJa1Q&s"
alt=""
/>
</div>
);
});
setItems(newItems);
});
};
return (
<div className="section">
<h1>useTransition and Suspense Example</h1>
<Suspense fallback={<h4>Loading...</h4>}>
<section>
<form className="form">
<input
type="text"
className="form-input"
value={text}
onChange={handleChange}
/>
</form>
<h4>Items Below</h4>
{/* 다 불러와지기 전에 Loading... 표시하기 */}
{isPending ? (
'Loading...'
) : (
<div
style={{
display: 'grid',
gridTemplateColumns: '1fr 1fr 1fr',
marginTop: '2rem',
}}
>
{items}
</div>
)}
<button onClick={() => setShow(!show)} className="btn">
toggle
</button>
{show && <SlowComponent />}
</section>
</Suspense>
</div>
);
};
export default UseTransitionSuspenseExample;
참고 사이트
728x90
728x90
'Programming > React' 카테고리의 다른 글
[React.js] 폼 데이터 처리하기 (React, React Router) (1) | 2024.09.26 |
---|---|
[React.js] 무한 스크롤(Infinite Scroll), 스켈레톤(Skeleton) 효과 적용하기 (with React Query) (0) | 2024.09.23 |
[React.js] .env 파일 만들고 사용하기 (환경 변수 관리) (0) | 2024.09.23 |
[React.js] React Query Devtools (0) | 2024.09.22 |
[React.js] useMemo 훅 (0) | 2024.09.20 |
[React.js] useCallback 훅 (0) | 2024.09.20 |
[React.js] React.memo() (0) | 2024.09.18 |
[React.js] Context API를 이용하여 전역 상태 관리하기 (2) | 2024.09.11 |