@@ -6,30 +6,44 @@ import { PacerProvider } from '@tanstack/react-pacer/provider'
66function App1 ( ) {
77 // Use your state management library of choice
88 const [ processedBatches , setProcessedBatches ] = useState <
9- Array < Array < number > >
9+ Array < Array < string > >
1010 > ( [ ] )
11+ const [ log , setLog ] = useState < string [ ] > ( [ ] )
1112
1213 // The function that will process a batch of items
13- function processBatch ( items : Array < number > ) {
14+ function processBatch ( items : Array < string > ) {
1415 setProcessedBatches ( ( prev ) => [ ...prev , items ] )
16+ setLog ( ( prev ) => [ ...prev , `Processed batch: [${ items . join ( ', ' ) } ]` ] )
1517 console . log ( 'processing batch' , items )
1618 }
1719
1820 const batcher = useBatcher (
1921 processBatch ,
2022 {
21- // started: false, // true by default
22- maxSize : 5 , // Process in batches of 5 (if comes before wait time)
23- wait : 3000 , // wait up to 3 seconds before processing a batch (if time elapses before maxSize is reached)
24- getShouldExecute : ( items , _batcher ) => items . includes ( 42 ) , // or pass in a custom function to determine if the batch should be processed
23+ maxSize : 5 ,
24+ wait : 3000 ,
25+ // Enable in-batch deduplication
26+ deduplicateItems : true ,
27+ deduplicateStrategy : 'keep-first' , // or 'keep-last'
2528 } ,
26- // Alternative to batcher.Subscribe: pass a selector as 3rd arg to cause re-renders and subscribe to state
27- // (state) => state,
2829 )
2930
31+ const addItem = ( item : string ) => {
32+ const result = batcher . addItem ( item )
33+ if ( result ) {
34+ setLog ( ( prev ) => [ ...prev , `Added: ${ item } ` ] )
35+ } else {
36+ setLog ( ( prev ) => [ ...prev , `Duplicate ignored: ${ item } ` ] )
37+ }
38+ }
39+
3040 return (
31- < div >
32- < h1 > TanStack Pacer useBatcher Example 1</ h1 >
41+ < div style = { { padding : '20px' , fontFamily : 'sans-serif' } } >
42+ < h1 > TanStack Pacer - In-Batch Deduplication Test</ h1 >
43+ < p style = { { color : '#666' } } >
44+ When < code > deduplicateItems: true</ code > , duplicate items within the same batch are ignored.
45+ </ p >
46+
3347 < batcher . Subscribe
3448 selector = { ( state ) => ( {
3549 size : state . size ,
@@ -39,59 +53,93 @@ function App1() {
3953 >
4054 { ( { size, executionCount, totalItemsProcessed } ) => (
4155 < >
42- < div > Batch Size: { size } </ div >
43- < div > Batch Max Size: { 3 } </ div >
44- < div > Batch Items: { batcher . peekAllItems ( ) . join ( ', ' ) } </ div >
45- < div > Batches Processed: { executionCount } </ div >
46- < div > Items Processed: { totalItemsProcessed } </ div >
47- < div >
48- Processed Batches:{ ' ' }
49- { processedBatches . map ( ( b , i ) => (
50- < >
51- < span key = { i } > [{ b . join ( ', ' ) } ]</ span > ,{ ' ' }
52- </ >
53- ) ) }
56+ < div style = { { background : '#f5f5f5' , padding : '15px' , borderRadius : '8px' , marginBottom : '20px' } } >
57+ < div > < strong > Batch Size:</ strong > { size } </ div >
58+ < div > < strong > Current Batch Items:</ strong > [{ batcher . peekAllItems ( ) . join ( ', ' ) } ]</ div >
59+ < div > < strong > Batches Processed:</ strong > { executionCount } </ div >
60+ < div > < strong > Total Items Processed:</ strong > { totalItemsProcessed } </ div >
5461 </ div >
55- < div
56- style = { {
57- display : 'grid' ,
58- gridTemplateColumns : 'repeat(2, 1fr)' ,
59- gap : '8px' ,
60- maxWidth : '600px' ,
61- margin : '16px 0' ,
62- } }
63- >
64- < button
65- onClick = { ( ) => {
66- const nextNumber = batcher . peekAllItems ( ) . length
67- ? batcher . peekAllItems ( ) [
68- batcher . peekAllItems ( ) . length - 1
69- ] + 1
70- : 1
71- batcher . addItem ( nextNumber )
72- } }
73- >
74- Add Number
75- </ button >
76- < button
77- disabled = { size === 0 }
78- onClick = { ( ) => {
79- batcher . flush ( )
80- } }
81- >
82- Flush Current Batch
83- </ button >
62+
63+ < div style = { { marginBottom : '20px' } } >
64+ < h3 > Test Deduplication</ h3 >
65+ < p style = { { fontSize : '14px' , color : '#666' } } >
66+ Click the same button multiple times - duplicates within the batch will be ignored.
67+ </ p >
68+ < div style = { { display : 'flex' , gap : '8px' , flexWrap : 'wrap' , marginBottom : '10px' } } >
69+ < button onClick = { ( ) => addItem ( 'apple' ) } style = { { padding : '8px 16px' } } >
70+ Add "apple"
71+ </ button >
72+ < button onClick = { ( ) => addItem ( 'banana' ) } style = { { padding : '8px 16px' } } >
73+ Add "banana"
74+ </ button >
75+ < button onClick = { ( ) => addItem ( 'cherry' ) } style = { { padding : '8px 16px' } } >
76+ Add "cherry"
77+ </ button >
78+ < button onClick = { ( ) => addItem ( 'apple' ) } style = { { padding : '8px 16px' , background : '#ffcccc' } } >
79+ Add "apple" (duplicate test)
80+ </ button >
81+ </ div >
82+ < div style = { { display : 'flex' , gap : '8px' } } >
83+ < button
84+ disabled = { size === 0 }
85+ onClick = { ( ) => batcher . flush ( ) }
86+ style = { { padding : '8px 16px' , background : '#4CAF50' , color : 'white' , border : 'none' , borderRadius : '4px' } }
87+ >
88+ Flush Batch
89+ </ button >
90+ < button
91+ onClick = { ( ) => {
92+ batcher . reset ( )
93+ setProcessedBatches ( [ ] )
94+ setLog ( [ ] )
95+ } }
96+ style = { { padding : '8px 16px' , background : '#f44336' , color : 'white' , border : 'none' , borderRadius : '4px' } }
97+ >
98+ Reset All
99+ </ button >
100+ </ div >
101+ </ div >
102+
103+ < div style = { { display : 'grid' , gridTemplateColumns : '1fr 1fr' , gap : '20px' } } >
104+ < div >
105+ < h4 > Processed Batches</ h4 >
106+ < div style = { { background : '#e8f5e9' , padding : '10px' , borderRadius : '4px' , minHeight : '100px' } } >
107+ { processedBatches . length === 0 ? (
108+ < span style = { { color : '#999' } } > No batches processed yet</ span >
109+ ) : (
110+ processedBatches . map ( ( b , i ) => (
111+ < div key = { i } > Batch #{ i + 1 } : [{ b . join ( ', ' ) } ]</ div >
112+ ) )
113+ ) }
114+ </ div >
115+ </ div >
116+ < div >
117+ < h4 > Activity Log</ h4 >
118+ < div style = { { background : '#fff3e0' , padding : '10px' , borderRadius : '4px' , minHeight : '100px' , maxHeight : '200px' , overflow : 'auto' } } >
119+ { log . length === 0 ? (
120+ < span style = { { color : '#999' } } > No activity yet</ span >
121+ ) : (
122+ log . map ( ( entry , i ) => (
123+ < div key = { i } style = { { fontSize : '12px' , fontFamily : 'monospace' } } > { entry } </ div >
124+ ) )
125+ ) }
126+ </ div >
127+ </ div >
84128 </ div >
85129 </ >
86130 ) }
87131 </ batcher . Subscribe >
88- < batcher . Subscribe selector = { ( state ) => state } >
89- { ( state ) => (
90- < pre style = { { marginTop : '20px' } } >
91- { JSON . stringify ( state , null , 2 ) }
92- </ pre >
93- ) }
94- </ batcher . Subscribe >
132+
133+ < details style = { { marginTop : '20px' } } >
134+ < summary style = { { cursor : 'pointer' , fontWeight : 'bold' } } > Debug: Full State</ summary >
135+ < batcher . Subscribe selector = { ( state ) => state } >
136+ { ( state ) => (
137+ < pre style = { { marginTop : '10px' , padding : '10px' , background : '#f1f3f5' , borderRadius : '4px' , overflow : 'auto' } } >
138+ { JSON . stringify ( state , null , 2 ) }
139+ </ pre >
140+ ) }
141+ </ batcher . Subscribe >
142+ </ details >
95143 </ div >
96144 )
97145}
0 commit comments