INP 줄이기: 이벤트 처리기 최적화
무거운 처리기를 디바운싱하고 scheduler.yield()를 사용하며 주 스레드를 차단하는 긴 작업을 피합니다.
INP 줄이기: 이벤트 처리기 최적화은(는) CoddyKit의 무료 React Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 React Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. React Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
INP란 무엇입니까
Interaction to Next Paint(INP)는 사용자의 상호작용(클릭, 탭, 키 누르기)부터 browser가 응답을 그릴 때까지의 지연 시간을 측정합니다. INP가 200ms를 초과하면 반응이 둔하게 느껴집니다.
React 이벤트가 느려질 수 있는 이유
너무 많은 작업을 동기적으로 처리하는 React 이벤트 처리기는 메인 스레드를 차단합니다. JS 작업이 완료될 때까지 browser가 응답을 그릴 수 없으므로 INP가 높아집니다.
입력한 내용 디바운스하기
키 입력으로 실행되는 비용이 큰 작업(검색 API 호출, 복잡한 계산)을 디바운스합니다. 키를 입력할 때마다 React 상태가 업데이트되는 것은 괜찮지만, 비용이 큰 작업에는 디바운스를 적용해야 합니다.
import { useDeferredValue, useState } from 'react';
function SearchPage() {
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query); // defers re-render of slow parts
return (
<>
<input value={query} onChange={e => setQuery(e.target.value)} />
<SearchResults query={deferredQuery} /> {/* re-renders with lower priority */}
</>
);
}긴급하지 않은 업데이트에 useTransition 사용하기
느린 상태 업데이트를 startTransition으로 감싸 긴급하지 않은 작업으로 표시합니다. React가 해당 작업을 지연 처리하는 동안 입력 반응성을 유지할 수 있습니다.
const [isPending, startTransition] = useTransition();
function handleFilter(value) {
setInputValue(value); // urgent — update input immediately
startTransition(() => {
setFilteredList(expensiveFilter(value)); // non-urgent — can be interrupted
});
}무거운 작업을 메인 스레드 밖으로 옮기기
대규모 데이터 세트 파싱이나 이미지 처리처럼 CPU를 많이 사용하는 작업에는 Web Workers를 사용합니다. worker가 계산하는 동안 메인 스레드는 계속 반응할 수 있습니다.
const worker = new Worker(new URL('./heavy-worker.js', import.meta.url));
function processData(data) {
return new Promise(resolve => {
worker.postMessage(data);
worker.onmessage = e => resolve(e.data);
});
}
// In component:
const handleClick = async () => {
const result = await processData(largeDataset); // doesn't block main thread
setResult(result);
};긴 작업 피하기
긴 작업(50ms 초과)은 메인 스레드를 차단하고 INP를 높입니다. setTimeout, scheduler.yield() 또는 requestIdleCallback을 사용해 작업을 여러 부분으로 나눕니다.
async function processInChunks(items) {
const CHUNK_SIZE = 100;
for (let i = 0; i < items.length; i += CHUNK_SIZE) {
const chunk = items.slice(i, i + CHUNK_SIZE);
processChunk(chunk);
await new Promise(r => setTimeout(r, 0)); // yield to browser between chunks
}
}scheduler.yield() (최신 API)
scheduler.yield()는 제어권을 browser 이벤트 루프에 돌려주므로, 코드를 재개하기 전에 대기 중인 사용자 상호작용을 처리할 수 있습니다.
async function longTask() {
for (const item of largeList) {
processItem(item);
if (/* every N items */) {
await scheduler.yield(); // let browser handle pending clicks/inputs
}
}
}처리기에서 동기 레이아웃 피하기
레이아웃 속성(offsetWidth, getBoundingClientRect())을 읽으면 동기 레이아웃 재계산이 강제로 발생합니다. 레이아웃이 반복해서 다시 계산되는 현상을 피하려면 읽기 작업을 쓰기 작업보다 먼저 묶어 처리합니다.
// Bad — forces layout recalculation on each iteration:
items.forEach(item => {
const height = item.offsetHeight; // READ — forces layout
item.style.height = height * 2 + 'px'; // WRITE — dirties layout
});
// Good — batch reads, then writes:
const heights = items.map(item => item.offsetHeight); // all reads
heights.forEach((h, i) => items[i].style.height = h * 2 + 'px'); // all writes비동기 INP를 위한 React 19 Actions
React 19 Actions는 UI를 차단하지 않고 비동기 변경 작업을 처리합니다. 대기 상태 업데이트가 독립적으로 진행되므로 페이지가 계속 상호작용 가능한 상태로 유지됩니다.
function LikeButton({ postId }) {
const [optimistic, setOptimistic] = useOptimistic(false);
async function handleLike() {
setOptimistic(true);
await likePost(postId); // async — doesn't block
}
return <button onClick={handleLike}>{optimistic ? 'Liked' : 'Like'}</button>;
}이벤트 위임의 주의점
React는 합성 이벤트 위임을 사용해 루트에 리스너 하나를 연결합니다. useEffect에서 개별 DOM 리스너를 수백 개 연결하지 말고, JSX 요소에서는 React의 합성 이벤트를 사용합니다.
DevTools에서 INP 측정하기
Chrome DevTools의 Performance 패널을 사용해 상호작용을 기록하고 긴 작업을 살펴봅니다. 타임라인에서 'Interaction' 항목을 찾은 다음 확장해 실행을 차단하는 스크립트 평가를 확인합니다.
빠른 확인
사용자 상호작용으로 중단할 수 있도록 상태 업데이트를 긴급하지 않은 작업으로 표시하는 React 훅은 무엇입니까?
요약
비용이 큰 작업에 디바운스를 적용하고, 긴급하지 않은 업데이트에는 startTransition을 사용하며, CPU 작업은 Web Workers로 옮기고, 긴 작업은 scheduler.yield()로 나누어 INP를 개선합니다. 레이아웃이 반복해서 다시 계산되는 현상을 피하려면 DOM 읽기 작업을 쓰기 작업보다 먼저 묶어 처리합니다.
자주 묻는 질문
“INP 줄이기: 이벤트 처리기 최적화” 강의는 무료인가요?
네 — “INP 줄이기: 이벤트 처리기 최적화” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 React Academy 강의 전체를 잠금 해제할 수 있습니다. React Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“INP 줄이기: 이벤트 처리기 최적화”에서 뭘 배우나요?
무거운 처리기를 디바운싱하고 scheduler.yield()를 사용하며 주 스레드를 차단하는 긴 작업을 피합니다. 브라우저에서 직접 실행하는 실습 코드로 React Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
React Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 React Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.
“INP 줄이기: 이벤트 처리기 최적화” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 React Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 React Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- React 앱에서 핵심 웹 지표 측정하기
- 묶음 분석과 코드 분할 전략
- React의 이미지와 글꼴 최적화
- INP 줄이기: 이벤트 처리기 최적화