import { useState } from 'octane'
import { createRoot } from 'octane'
import { useBatchedCallback } from '@tanstack/octane-pacer/batcher'
interface LogEntry {
id: number
message: string
timestamp: Date
}
function App1() {
const [logs, setLogs] = useState<LogEntry[]>([])
const [logCount, setLogCount] = useState(0)
const batchedLogger = useBatchedCallback(
(entries: LogEntry[]) => {
console.log('Processing batch of logs:', entries)
setLogs((current) => [...current, ...entries])
},
{
maxSize: 3,
wait: 2000,
},
)
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)
const trackEvents = useBatchedCallback(
(events: AnalyticsEvent[]) => {
console.log('Sending analytics batch:', events)
setEvents((current) => [...current, ...events])
setBatchesProcessed((count) => count + 1)
},
{
maxSize: 5,
wait: 3000,
},
)
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[]>([])
const batchApiRequests = useBatchedCallback(
(requests: ApiRequest[]) => {
console.log('Processing batch of API requests:', requests)
setProcessedRequests((current) => [...current, ...requests])
},
{
maxSize: 4,
wait: 1500,
},
)
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>
)
}
function PacerExample() {
return (
<div>
<App1 />
<hr />
<App2 />
<hr />
<App3 />
</div>
)
}
createRoot(document.getElementById('app')!).render(PacerExample)