0Pricing
React Academy · 강의

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 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. React 앱에서 핵심 웹 지표 측정하기
  2. 묶음 분석과 코드 분할 전략
  3. React의 이미지와 글꼴 최적화
  4. INP 줄이기: 이벤트 처리기 최적화
← React Academy(으)로 돌아가기