React 배칭 가이드
배칭은 항목을 수집해 하나의 함수에 배열로 전달합니다. 배치가 설정된 크기에 도달하거나 설정된 대기 시간 동안 새 항목이 추가되지 않을 때, 또는 사용자 정의 로직에서 준비되었다고 판단할 때 배치를 실행할 수 있습니다.
배칭은 여러 항목을 함께 처리하여 작업 수를 줄입니다. 큐잉과 달리 각 항목마다 래핑된 함수를 한 번씩 호출하지 않습니다.
배칭의 작동 방식
Batching (process every 3 items or after 2 quiet ticks)
Timeline: [1 second per tick]
Calls: ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️
Batch: [ABC] [] [DE] [] [FGH] []
Executed: ✅ ✅ ✅
[======================================================]
^ Items are grouped and processed together
[Size reached] [Wait elapsed] [Size reached]
각 실행에는 현재 수집된 항목의 복사본이 전달됩니다. 배처는 래핑된 함수를 호출하기 전에 해당 항목을 비웁니다.
배칭을 사용해야 하는 경우
다음과 같은 경우 배칭을 선택합니다.
- 일괄 작업이 개별 작업보다 효율적인 경우
- 네트워크 요청, 데이터베이스 쓰기, 분석 이벤트를 그룹화할 수 있는 경우
- 최대 배치 크기나 유휴 시간 트리거가 워크로드에 적합한 경우
- 개별 항목의 결과가 필요하지 않은 경우
다음과 같은 경우 다른 유틸리티를 선택합니다.
- 모든 항목을 개별적으로 순서대로 실행해야 하는 경우 큐잉을 사용합니다.
- 가장 최근 값만 중요한 경우 디바운싱을 사용합니다.
- 호출 간에 시간 간격을 두어야 하는 경우 스로틀링을 사용합니다.
- 배치 처리가 Promise를 반환하거나 재시도 및 중단 지원이 필요한 경우 비동기 배칭을 사용합니다.
API 선택하기
- 안정적인 항목 추가 함수가 필요하면
useBatchedCallback - 플러시, 취소, 수집된 항목, 선택한 상태가 필요하면
useBatcher
컴포넌트에서 항목 추가만 필요하다면 콜백 API를 사용합니다. flush(), cancel(), 수집된 항목, 선택한 상태, 동적 옵션이 필요하면 인스턴스 API를 사용합니다.
React 예제
import { useBatcher } from '@tanstack/react-pacer'
function AnalyticsButton() {
const batcher = useBatcher(
sendEvents,
{ maxSize: 20, wait: 1000 },
(state) => ({
size: state.size,
}),
)
return (
<button onClick={() => batcher.addItem({ type: 'click' })}>
Track ({batcher.state.size} pending)
</button>
)
}
이 가이드에서 이후에 다루는 핵심 코드 조각은 useBatcher를 사용하며 컴포넌트나 다른 훅 내부에서 실행한다고 가정합니다.
배치 트리거 선택하기
배치 크기
maxSize는 수집된 항목 수가 제한에 도달하는 즉시 배치를 실행합니다.
const batcher = useBatcher(processBatch, {
maxSize: 100,
})
기본값은 Infinity이므로 크기 트리거를 제공하지 않으면 비활성화됩니다.
대기 시간
wait는 설정된 시간 동안 새 항목이 추가되지 않으면 배치를 실행합니다. 항목을 추가할 때마다 타이머가 다시 시작합니다.
const batcher = useBatcher(processBatch, {
wait: 1000,
})
기본값은 Infinity이므로 시간 트리거를 제공하지 않으면 비활성화됩니다. 항목이 계속 들어오면 타이머도 계속 다시 시작할 수 있습니다. 지속적인 트래픽에서도 배치를 결국 실행해야 한다면 wait와 maxSize를 함께 사용합니다.
사용자 정의 트리거
getShouldExecute는 각 항목을 추가한 후 실행됩니다. 현재 배치를 즉시 실행하려면 true를 반환합니다.
const batcher = useBatcher<number>(processBatch, {
getShouldExecute: (items) => items.includes(0),
})
batcher.addItem(4)
batcher.addItem(0) // Executes [4, 0].
여러 트리거를 설정한 경우 가장 먼저 조건에 도달한 트리거가 배치를 실행합니다.
수집된 항목 제어하기
플러시
flush()는 대기 중인 타이머를 지우고 현재 수집된 모든 항목을 실행합니다. 배치가 비어 있으면 아무 동작도 하지 않습니다.
batcher.addItem('event-1')
batcher.addItem('event-2')
batcher.flush()
취소
cancel()은 대기 중인 타이머를 지우지만 수집된 항목은 유지합니다. 이후 항목이 새 타이머를 예약하거나 flush()를 호출할 수 있습니다.
batcher.cancel()
console.log(batcher.peekAllItems()) // Items are still present.
비우기
clear()는 수집된 모든 항목을 제거합니다. 타이머 자체는 지우지 않지만 항목을 더 추가하지 않으면 해당 타이머에서 실행할 항목이 없습니다.
batcher.clear()
재설정
reset()은 배치 상태와 카운터를 기본값으로 복원합니다. 이미 예약된 타이머는 취소하지 않습니다. 대기 작업을 버려야 한다면 cancel()을 호출한 뒤 reset()합니다.
batcher.cancel()
batcher.reset()
배치 설정 및 관찰하기
향후 트리거 동작을 업데이트하려면 setOptions()를 사용합니다.
batcher.setOptions({
maxSize: 20,
wait: 500,
})
wait를 변경해도 기존 타이머를 다시 예약하지 않습니다. 다음 addItem() 호출이 현재 값을 사용해 해당 타이머를 대체합니다.
wait 옵션에는 배처 인스턴스를 받는 함수를 사용할 수 있습니다.
const batcher = useBatcher(processBatch, {
wait: (batcher) => (batcher.store.state.size > 10 ? 100 : 500),
})
컬렉션 변경을 관찰하려면 onItemsChange를, 완료된 배치 호출을 관찰하려면 onExecute를 사용합니다.
const batcher = useBatcher(processBatch, {
maxSize: 10,
onItemsChange: (batcher) => {
console.log('Collected:', batcher.store.state.size)
},
onExecute: (items, batcher) => {
console.log('Processed:', items)
console.log('Batches:', batcher.store.state.executionCount)
},
})
배처를 일시 중지하는 데 started를 사용하지 마세요. 현재 아무 동작도 하지 않으므로 모든 addItem() 호출에서 설정된 트리거를 평가합니다.
React 수명 주기
어댑터는 소유자가 제거될 때 수집된 항목은 유지하면서 대기 중인 타이머를 취소합니다. onUnmount를 제공하면 이 기본 정리 동작을 대체하므로 사용자 정의 콜백에서 필요한 모든 수명 주기 작업을 수행해야 합니다. 사용자 정의 정리 과정에서 작업을 플러시하면 컴포넌트가 제거되는 동안 사용자 콜백이 실행될 수 있다는 점에 유의해야 합니다.
반응형 상태
어댑터는 셀렉터 인수가 반환한 상태만 구독합니다. 셀렉터가 없으면 어댑터 상태는 비어 있습니다. 컴포넌트나 다른 훅의 최상위 수준에서 유틸리티를 만들고 뷰에서 사용하는 필드만 선택합니다.
const batcher = useBatcher(
processBatch,
{ maxSize: 20, wait: 1000 },
(state) => ({
size: state.size,
isPending: state.isPending,
}),
)
console.log(batcher.state.size, batcher.state.isPending)
옵션 함수와 수명 주기 콜백은 기반 공개 유틸리티 인스턴스를 받습니다. 위 예제처럼 해당 콜백 안에서 .store.state를 읽는 방식을 지원합니다. 렌더링 코드는 여기에 나온 선택된 어댑터 상태를 읽어야 합니다.
앱에서 유지한 선택 상태를 복원하려면 initialState로 부분 스냅샷을 전달합니다. 이 스냅샷은 기본값과 병합됩니다. 지속 가능한 필드만 복원합니다. 대기 중인 타이머는 복원되지 않습니다.
일반적으로 유용한 상태에는 다음 항목이 포함됩니다.
items: 현재 수집된 항목입니다.size: 수집된 항목 수입니다.isEmpty: 배치가 비어 있는지 여부입니다.isPending: 대기 타이머가 활성 상태인지 여부입니다.executionCount: 완료된 배치 실행 횟수입니다.totalItemsProcessed: 완료된 배치 실행에 전달된 항목 수입니다.status:'idle'또는'pending'입니다.
어댑터 시그니처는 React API 레퍼런스를, 전체 옵션 및 상태 타입은 공개 코어 레퍼런스를 참고합니다.