📄 tanstack/pacer/latest/docs/framework/react/examples/useBatchedCallback

File: useBatchedCallback.md | Updated: 11/15/2025

Source: https://tanstack.com/pacer/latest/docs/framework/react/examples/useBatchedCallback



TanStack

Pacer v0v0

Search...

+ K

Auto

Log In

TanStack StartRC

Docs Examples GitHub Contributors

TanStack Router

Docs Examples GitHub Contributors

TanStack Query

Docs Examples GitHub Contributors

TanStack Table

Docs Examples Github Contributors

TanStack Formnew

Docs Examples Github Contributors

TanStack DBbeta

Docs Github Contributors

TanStack Virtual

Docs Examples Github Contributors

TanStack Paceralpha

Docs Examples Github Contributors

TanStack Storealpha

Docs Examples Github Contributors

TanStack Devtoolsalpha

Docs Github Contributors

More Libraries

Maintainers Partners Support Learn StatsBETA Discord Merch Blog GitHub Ethos Brand Guide

Documentation

Framework

React logo

React

Version

Latest

Search...

+ K

Menu

Getting Started

Guides

API Reference

Debouncer API Reference

Throttler API Reference

Rate Limiter API Reference

Queue API Reference

Batcher API Reference

Debouncer Examples

Throttler Examples

Rate Limiter Examples

Queue Examples

Batcher Examples

TanStack Query Examples

Framework

React logo

React

Version

Latest

Menu

Getting Started

Guides

API Reference

Debouncer API Reference

Throttler API Reference

Rate Limiter API Reference

Queue API Reference

Batcher API Reference

Debouncer Examples

Throttler Examples

Rate Limiter Examples

Queue Examples

Batcher Examples

TanStack Query Examples

React Example: UseBatchedCallback

Github StackBlitz CodeSandbox

=================================================================================================================================================================================================================================================================================================================================================================================================================================================

Code ExplorerCode

Interactive SandboxSandbox

  • public

  • src

    • index.tsx file iconindex.tsx
  • .eslintrc.cjs file icon.eslintrc.cjs

  • .gitignore file icon.gitignore

  • README.md file iconREADME.md

  • index.html file iconindex.html

  • package.json file iconpackage.json

  • tsconfig.json file icontsconfig.json

  • vite.config.ts file iconvite.config.ts

tsx

import { useState } from 'react'
import ReactDOM from 'react-dom/client'
import { useBatchedCallback } from '@tanstack/react-pacer/batcher'

interface LogEntry {
  id: number
  message: string
  timestamp: Date
}

function App1() {
  const [logs, setLogs] = useState<LogEntry[]>([])
  const [logCount, setLogCount] = useState(0)

  // Create batched logger function - Stable reference provided by useBatchedCallback
  const batchedLogger = useBatchedCallback(
    (entries: LogEntry[]) => {
      console.log('Processing batch of logs:', entries)
      setLogs((current) => [...current, ...entries])
    },
    {
      maxSize: 3, // Process when 3 logs collected
      wait: 2000, // Or after 2 seconds
    },
  )

  function addLog(message: string) {
    const newLog: LogEntry = {
      id: Date.now() + Math.random(),
      message,
      timestamp: new Date(),
    }
    setLogCount((c) => c + 1)
    batchedLogger(newLog)
  }

  return (
    <div>
      <h1>TanStack Pacer useBatchedCallback Example 1</h1>
      <div style={{ marginBottom: '20px' }}>
        <button onClick={() => addLog(`Log entry ${logCount + 1}`)}>
          Add Log Entry
        </button>
        <button
          onClick={() => addLog(`Warning ${logCount + 1}`)}
          style={{ marginLeft: '10px' }}
        >
          Add Warning
        </button>
        <button
          onClick={() => addLog(`Error ${logCount + 1}`)}
          style={{ marginLeft: '10px' }}
        >
          Add Error
        </button>
      </div>

      <table>
        <tbody>
          <tr>
            <td>Total Logs Created:</td>
            <td>{logCount}</td>
          </tr>
          <tr>
            <td>Logs Processed:</td>
            <td>{logs.length}</td>
          </tr>
        </tbody>
      </table>

      <div style={{ marginTop: '20px' }}>
        <h3>Processed Logs:</h3>
        <div
          style={{
            maxHeight: '200px',
            overflowY: 'auto',
            border: '1px solid #ccc',
            padding: '10px',
          }}
        >
          {logs.length === 0 ? (
            <p style={{ color: '#666' }}>No logs processed yet...</p>
          ) : (
            logs.map((log) => (
              <div
                key={log.id}
                style={{ marginBottom: '5px', fontSize: '0.9em' }}
              >
                <strong>{log.timestamp.toLocaleTimeString()}</strong>:{' '}
                {log.message}
              </div>
            ))
          )}
        </div>
      </div>

      <p style={{ fontSize: '0.9em', color: '#666' }}>
        Logs are batched - max 3 items or 2 second wait time
      </p>
    </div>
  )
}

interface AnalyticsEvent {
  type: string
  target: string
  timestamp: Date
}

function App2() {
  const [events, setEvents] = useState<AnalyticsEvent[]>([])
  const [totalEvents, setTotalEvents] = useState(0)
  const [batchesProcessed, setBatchesProcessed] = useState(0)

  // Create batched analytics tracker - Stable reference provided by useBatchedCallback
  const trackEvents = useBatchedCallback(
    (events: AnalyticsEvent[]) => {
      console.log('Sending analytics batch:', events)
      setEvents((current) => [...current, ...events])
      setBatchesProcessed((count) => count + 1)
    },
    {
      maxSize: 5, // Send when 5 events collected
      wait: 3000, // Or after 3 seconds
    },
  )

  function trackEvent(type: string, target: string) {
    const event: AnalyticsEvent = {
      type,
      target,
      timestamp: new Date(),
    }
    setTotalEvents((count) => count + 1)
    trackEvents(event)
  }

  return (
    <div>
      <h1>TanStack Pacer useBatchedCallback Example 2</h1>
      <div style={{ marginBottom: '20px' }}>
        <button onClick={() => trackEvent('click', 'button-1')}>
          Track Button Click
        </button>
        <button
          onClick={() => trackEvent('hover', 'card')}
          style={{ marginLeft: '10px' }}
        >
          Track Hover Event
        </button>
        <button
          onClick={() => trackEvent('view', 'page')}
          style={{ marginLeft: '10px' }}
        >
          Track Page View
        </button>
        <button
          onClick={() => trackEvent('form', 'submit')}
          style={{ marginLeft: '10px' }}
        >
          Track Form Submit
        </button>
      </div>

      <table>
        <tbody>
          <tr>
            <td>Total Events Created:</td>
            <td>{totalEvents}</td>
          </tr>
          <tr>
            <td>Events Sent:</td>
            <td>{events.length}</td>
          </tr>
          <tr>
            <td>Batches Processed:</td>
            <td>{batchesProcessed}</td>
          </tr>
        </tbody>
      </table>

      <div style={{ marginTop: '20px' }}>
        <h3>Sent Analytics Events:</h3>
        <div
          style={{
            maxHeight: '200px',
            overflowY: 'auto',
            border: '1px solid #ccc',
            padding: '10px',
          }}
        >
          {events.length === 0 ? (
            <p style={{ color: '#666' }}>No events sent yet...</p>
          ) : (
            events.map((event, index) => (
              <div
                key={index}
                style={{ marginBottom: '5px', fontSize: '0.9em' }}
              >
                <strong>{event.timestamp.toLocaleTimeString()}</strong>:{' '}
                {event.type} - {event.target}
              </div>
            ))
          )}
        </div>
      </div>

      <p style={{ fontSize: '0.9em', color: '#666' }}>
        Analytics events are batched - max 5 events or 3 second wait time
      </p>
    </div>
  )
}

interface ApiRequest {
  id: string
  data: any
}

function App3() {
  const [requests, setRequests] = useState<ApiRequest[]>([])
  const [totalRequests, setTotalRequests] = useState(0)
  const [processedRequests, setProcessedRequests] = useState<ApiRequest[]>([])

  // Create batched API request handler - Stable reference provided by useBatchedCallback
  const batchApiRequests = useBatchedCallback(
    (requests: ApiRequest[]) => {
      console.log('Processing batch of API requests:', requests)
      // Simulate API processing
      setProcessedRequests((current) => [...current, ...requests])
    },
    {
      maxSize: 4, // Process when 4 requests collected
      wait: 1500, // Or after 1.5 seconds
    },
  )

  function makeApiRequest(data: any) {
    const request: ApiRequest = {
      id: `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
      data,
    }
    setTotalRequests((count) => count + 1)
    setRequests((current) => [...current, request])
    batchApiRequests(request)
  }

  return (
    <div>
      <h1>TanStack Pacer useBatchedCallback Example 3</h1>
      <div style={{ marginBottom: '20px' }}>
        <button
          onClick={() => makeApiRequest({ action: 'save', item: 'document' })}
        >
          Save Document
        </button>
        <button
          onClick={() => makeApiRequest({ action: 'update', item: 'profile' })}
          style={{ marginLeft: '10px' }}
        >
          Update Profile
        </button>
        <button
          onClick={() => makeApiRequest({ action: 'delete', item: 'file' })}
          style={{ marginLeft: '10px' }}
        >
          Delete File
        </button>
        <button
          onClick={() => makeApiRequest({ action: 'create', item: 'folder' })}
          style={{ marginLeft: '10px' }}
        >
          Create Folder
        </button>
      </div>

      <table>
        <tbody>
          <tr>
            <td>Total Requests Made:</td>
            <td>{totalRequests}</td>
          </tr>
          <tr>
            <td>Requests Queued:</td>
            <td>{requests.length - processedRequests.length}</td>
          </tr>
          <tr>
            <td>Requests Processed:</td>
            <td>{processedRequests.length}</td>
          </tr>
        </tbody>
      </table>

      <div style={{ marginTop: '20px', display: 'flex', gap: '20px' }}>
        <div style={{ flex: 1 }}>
          <h3>Queued Requests:</h3>
          <div
            style={{
              maxHeight: '150px',
              overflowY: 'auto',
              border: '1px solid #ccc',
              padding: '10px',
            }}
          >
            {requests.filter(
              (req) => !processedRequests.some((p) => p.id === req.id),
            ).length === 0 ? (
              <p style={{ color: '#666' }}>No requests queued...</p>
            ) : (
              requests
                .filter(
                  (req) => !processedRequests.some((p) => p.id === req.id),
                )
                .map((request) => (
                  <div
                    key={request.id}
                    style={{ marginBottom: '5px', fontSize: '0.9em' }}
                  >
                    {request.id}: {JSON.stringify(request.data)}
                  </div>
                ))
            )}
          </div>
        </div>

        <div style={{ flex: 1 }}>
          <h3>Processed Requests:</h3>
          <div
            style={{
              maxHeight: '150px',
              overflowY: 'auto',
              border: '1px solid #ccc',
              padding: '10px',
            }}
          >
            {processedRequests.length === 0 ? (
              <p style={{ color: '#666' }}>No requests processed yet...</p>
            ) : (
              processedRequests.map((request) => (
                <div
                  key={request.id}
                  style={{ marginBottom: '5px', fontSize: '0.9em' }}
                >
                  {request.id}: {JSON.stringify(request.data)}
                </div>
              ))
            )}
          </div>
        </div>
      </div>

      <p style={{ fontSize: '0.9em', color: '#666' }}>
        API requests are batched - max 4 requests or 1.5 second wait time
      </p>
    </div>
  )
}

const root = ReactDOM.createRoot(document.getElementById('root')!)
root.render(
  <div>
    <App1 />
    <hr />
    <App2 />
    <hr />
    <App3 />
  </div>,
)


import { useState } from 'react'
import ReactDOM from 'react-dom/client'
import { useBatchedCallback } from '@tanstack/react-pacer/batcher'

interface LogEntry {
  id: number
  message: string
  timestamp: Date
}

function App1() {
  const [logs, setLogs] = useState<LogEntry[]>([])
  const [logCount, setLogCount] = useState(0)

  // Create batched logger function - Stable reference provided by useBatchedCallback
  const batchedLogger = useBatchedCallback(
    (entries: LogEntry[]) => {
      console.log('Processing batch of logs:', entries)
      setLogs((current) => [...current, ...entries])
    },
    {
      maxSize: 3, // Process when 3 logs collected
      wait: 2000, // Or after 2 seconds
    },
  )

  function addLog(message: string) {
    const newLog: LogEntry = {
      id: Date.now() + Math.random(),
      message,
      timestamp: new Date(),
    }
    setLogCount((c) => c + 1)
    batchedLogger(newLog)
  }

  return (
    <div>
      <h1>TanStack Pacer useBatchedCallback Example 1</h1>
      <div style={{ marginBottom: '20px' }}>
        <button onClick={() => addLog(`Log entry ${logCount + 1}`)}>
          Add Log Entry
        </button>
        <button
          onClick={() => addLog(`Warning ${logCount + 1}`)}
          style={{ marginLeft: '10px' }}
        >
          Add Warning
        </button>
        <button
          onClick={() => addLog(`Error ${logCount + 1}`)}
          style={{ marginLeft: '10px' }}
        >
          Add Error
        </button>
      </div>

      <table>
        <tbody>
          <tr>
            <td>Total Logs Created:</td>
            <td>{logCount}</td>
          </tr>
          <tr>
            <td>Logs Processed:</td>
            <td>{logs.length}</td>
          </tr>
        </tbody>
      </table>

      <div style={{ marginTop: '20px' }}>
        <h3>Processed Logs:</h3>
        <div
          style={{
            maxHeight: '200px',
            overflowY: 'auto',
            border: '1px solid #ccc',
            padding: '10px',
          }}
        >
          {logs.length === 0 ? (
            <p style={{ color: '#666' }}>No logs processed yet...</p>
          ) : (
            logs.map((log) => (
              <div
                key={log.id}
                style={{ marginBottom: '5px', fontSize: '0.9em' }}
              >
                <strong>{log.timestamp.toLocaleTimeString()}</strong>:{' '}
                {log.message}
              </div>
            ))
          )}
        </div>
      </div>

      <p style={{ fontSize: '0.9em', color: '#666' }}>
        Logs are batched - max 3 items or 2 second wait time
      </p>
    </div>
  )
}

interface AnalyticsEvent {
  type: string
  target: string
  timestamp: Date
}

function App2() {
  const [events, setEvents] = useState<AnalyticsEvent[]>([])
  const [totalEvents, setTotalEvents] = useState(0)
  const [batchesProcessed, setBatchesProcessed] = useState(0)

  // Create batched analytics tracker - Stable reference provided by useBatchedCallback
  const trackEvents = useBatchedCallback(
    (events: AnalyticsEvent[]) => {
      console.log('Sending analytics batch:', events)
      setEvents((current) => [...current, ...events])
      setBatchesProcessed((count) => count + 1)
    },
    {
      maxSize: 5, // Send when 5 events collected
      wait: 3000, // Or after 3 seconds
    },
  )

  function trackEvent(type: string, target: string) {
    const event: AnalyticsEvent = {
      type,
      target,
      timestamp: new Date(),
    }
    setTotalEvents((count) => count + 1)
    trackEvents(event)
  }

  return (
    <div>
      <h1>TanStack Pacer useBatchedCallback Example 2</h1>
      <div style={{ marginBottom: '20px' }}>
        <button onClick={() => trackEvent('click', 'button-1')}>
          Track Button Click
        </button>
        <button
          onClick={() => trackEvent('hover', 'card')}
          style={{ marginLeft: '10px' }}
        >
          Track Hover Event
        </button>
        <button
          onClick={() => trackEvent('view', 'page')}
          style={{ marginLeft: '10px' }}
        >
          Track Page View
        </button>
        <button
          onClick={() => trackEvent('form', 'submit')}
          style={{ marginLeft: '10px' }}
        >
          Track Form Submit
        </button>
      </div>

      <table>
        <tbody>
          <tr>
            <td>Total Events Created:</td>
            <td>{totalEvents}</td>
          </tr>
          <tr>
            <td>Events Sent:</td>
            <td>{events.length}</td>
          </tr>
          <tr>
            <td>Batches Processed:</td>
            <td>{batchesProcessed}</td>
          </tr>
        </tbody>
      </table>

      <div style={{ marginTop: '20px' }}>
        <h3>Sent Analytics Events:</h3>
        <div
          style={{
            maxHeight: '200px',
            overflowY: 'auto',
            border: '1px solid #ccc',
            padding: '10px',
          }}
        >
          {events.length === 0 ? (
            <p style={{ color: '#666' }}>No events sent yet...</p>
          ) : (
            events.map((event, index) => (
              <div
                key={index}
                style={{ marginBottom: '5px', fontSize: '0.9em' }}
              >
                <strong>{event.timestamp.toLocaleTimeString()}</strong>:{' '}
                {event.type} - {event.target}
              </div>
            ))
          )}
        </div>
      </div>

      <p style={{ fontSize: '0.9em', color: '#666' }}>
        Analytics events are batched - max 5 events or 3 second wait time
      </p>
    </div>
  )
}

interface ApiRequest {
  id: string
  data: any
}

function App3() {
  const [requests, setRequests] = useState<ApiRequest[]>([])
  const [totalRequests, setTotalRequests] = useState(0)
  const [processedRequests, setProcessedRequests] = useState<ApiRequest[]>([])

  // Create batched API request handler - Stable reference provided by useBatchedCallback
  const batchApiRequests = useBatchedCallback(
    (requests: ApiRequest[]) => {
      console.log('Processing batch of API requests:', requests)
      // Simulate API processing
      setProcessedRequests((current) => [...current, ...requests])
    },
    {
      maxSize: 4, // Process when 4 requests collected
      wait: 1500, // Or after 1.5 seconds
    },
  )

  function makeApiRequest(data: any) {
    const request: ApiRequest = {
      id: `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
      data,
    }
    setTotalRequests((count) => count + 1)
    setRequests((current) => [...current, request])
    batchApiRequests(request)
  }

  return (
    <div>
      <h1>TanStack Pacer useBatchedCallback Example 3</h1>
      <div style={{ marginBottom: '20px' }}>
        <button
          onClick={() => makeApiRequest({ action: 'save', item: 'document' })}
        >
          Save Document
        </button>
        <button
          onClick={() => makeApiRequest({ action: 'update', item: 'profile' })}
          style={{ marginLeft: '10px' }}
        >
          Update Profile
        </button>
        <button
          onClick={() => makeApiRequest({ action: 'delete', item: 'file' })}
          style={{ marginLeft: '10px' }}
        >
          Delete File
        </button>
        <button
          onClick={() => makeApiRequest({ action: 'create', item: 'folder' })}
          style={{ marginLeft: '10px' }}
        >
          Create Folder
        </button>
      </div>

      <table>
        <tbody>
          <tr>
            <td>Total Requests Made:</td>
            <td>{totalRequests}</td>
          </tr>
          <tr>
            <td>Requests Queued:</td>
            <td>{requests.length - processedRequests.length}</td>
          </tr>
          <tr>
            <td>Requests Processed:</td>
            <td>{processedRequests.length}</td>
          </tr>
        </tbody>
      </table>

      <div style={{ marginTop: '20px', display: 'flex', gap: '20px' }}>
        <div style={{ flex: 1 }}>
          <h3>Queued Requests:</h3>
          <div
            style={{
              maxHeight: '150px',
              overflowY: 'auto',
              border: '1px solid #ccc',
              padding: '10px',
            }}
          >
            {requests.filter(
              (req) => !processedRequests.some((p) => p.id === req.id),
            ).length === 0 ? (
              <p style={{ color: '#666' }}>No requests queued...</p>
            ) : (
              requests
                .filter(
                  (req) => !processedRequests.some((p) => p.id === req.id),
                )
                .map((request) => (
                  <div
                    key={request.id}
                    style={{ marginBottom: '5px', fontSize: '0.9em' }}
                  >
                    {request.id}: {JSON.stringify(request.data)}
                  </div>
                ))
            )}
          </div>
        </div>

        <div style={{ flex: 1 }}>
          <h3>Processed Requests:</h3>
          <div
            style={{
              maxHeight: '150px',
              overflowY: 'auto',
              border: '1px solid #ccc',
              padding: '10px',
            }}
          >
            {processedRequests.length === 0 ? (
              <p style={{ color: '#666' }}>No requests processed yet...</p>
            ) : (
              processedRequests.map((request) => (
                <div
                  key={request.id}
                  style={{ marginBottom: '5px', fontSize: '0.9em' }}
                >
                  {request.id}: {JSON.stringify(request.data)}
                </div>
              ))
            )}
          </div>
        </div>
      </div>

      <p style={{ fontSize: '0.9em', color: '#666' }}>
        API requests are batched - max 4 requests or 1.5 second wait time
      </p>
    </div>
  )
}

const root = ReactDOM.createRoot(document.getElementById('root')!)
root.render(
  <div>
    <App1 />
    <hr />
    <App2 />
    <hr />
    <App3 />
  </div>,
)

useAsyncBatcher

useAsyncBatchedCallback

Partners Become a Partner

Code RabbitCode Rabbit CloudflareCloudflare AG GridAG Grid NetlifyNetlify NeonNeon WorkOSWorkOS ClerkClerk ConvexConvex ElectricElectric SentrySentry PrismaPrisma StrapiStrapi UnkeyUnkey

scarf analytics