In a Solid application, use the Solid Adapter. Its hooks wrap the core Pacer utilities with lifecycle cleanup and reactive state. The adapter also re-exports everything from the core package, so you can import the plain classes and functions from the same place.
npm install @tanstack/solid-pacerSee the Solid Functions Reference for the full list of hooks in the Solid Adapter.
Import a Solid-specific hook from the Solid Adapter.
import { createDebouncedValue } from '@tanstack/solid-pacer'
import { createSignal } from 'solid-js'
const [instantValue, setInstantValue] = createSignal(0)
const [debouncedValue, debouncer] = createDebouncedValue(instantValue, {
wait: 1000,
})Or import a core Pacer class/function that is re-exported from the Solid Adapter.
import { debounce, Debouncer } from '@tanstack/solid-pacer' // no need to install the core package separatelyOption helpers define shared options with full type checking, so you can declare them once and reuse them across hooks.
import { createDebouncer } from '@tanstack/solid-pacer'
import { debouncerOptions } from '@tanstack/pacer'
const commonDebouncerOptions = debouncerOptions({
wait: 1000,
leading: false,
trailing: true,
})
const debouncer = createDebouncer(
(query: string) => fetchSearchResults(query),
{ ...commonDebouncerOptions, key: 'searchDebouncer' }
)import { createAsyncQueuer } from '@tanstack/solid-pacer'
import { asyncQueuerOptions } from '@tanstack/pacer'
const commonAsyncQueuerOptions = asyncQueuerOptions({
concurrency: 3,
addItemsTo: 'back',
})
const queuer = createAsyncQueuer(
async (item: string) => processItem(item),
{ ...commonAsyncQueuerOptions, key: 'itemQueuer' }
)import { createRateLimiter } from '@tanstack/solid-pacer'
import { rateLimiterOptions } from '@tanstack/pacer'
const commonRateLimiterOptions = rateLimiterOptions({
limit: 5,
window: 60000,
windowType: 'sliding',
})
const rateLimiter = createRateLimiter(
(data: string) => sendApiRequest(data),
{ ...commonRateLimiterOptions, key: 'apiRateLimiter' }
)The PacerProvider component sets default options for every Pacer utility instance in its component tree.
import { PacerProvider } from '@tanstack/solid-pacer'
// Set default options for solid-pacer instances
<PacerProvider
defaultOptions={{
debouncer: { wait: 1000 },
asyncQueuer: { concurrency: 3 },
rateLimiter: { limit: 5, window: 60000 },
}}
>
<App />
</PacerProvider>Hooks inside the provider use these defaults. Options passed to an individual hook override them.
The Solid Adapter supports subscribing to state changes in two ways:
Use the Subscribe component to read state deep in the component tree without passing a selector to the hook.
In Solid, the Subscribe component provides an accessor (signal) to the selected state, so call state() to read the value.
import { createRateLimiter } from '@tanstack/solid-pacer'
function ApiComponent() {
const rateLimiter = createRateLimiter(
(data: string) => {
return fetch('/api/endpoint', {
method: 'POST',
body: JSON.stringify({ data }),
})
},
{ limit: 5, window: 60000 }
)
return (
<div>
<button onClick={() => rateLimiter.maybeExecute('some data')}>
Submit
</button>
<rateLimiter.Subscribe selector={(state) => ({ rejectionCount: state.rejectionCount })}>
{(state) => (
<div>Rejections: {state().rejectionCount}</div>
)}
</rateLimiter.Subscribe>
</div>
)
}The selector parameter controls which state changes trigger reactive updates. State you do not select never causes an update.
Without a selector, hook.state is an empty object ({}). Pass a selector function to opt in to state tracking.
In Solid, hook.state is an accessor (signal), so call hook.state() to read the value.
import { createDebouncer } from '@tanstack/solid-pacer'
function SearchComponent() {
// Default behavior - no reactive state subscriptions
const untrackedDebouncer = createDebouncer(
(query: string) => fetchSearchResults(query),
{ wait: 500 }
)
console.log(untrackedDebouncer.state()) // {}
// Opt-in to track isPending changes
const debouncer = createDebouncer(
(query: string) => fetchSearchResults(query),
{ wait: 500 },
(state) => ({ isPending: state.isPending })
)
console.log(debouncer.state().isPending) // Reactive value
return (
<input
onInput={(e) => debouncer.maybeExecute(e.target.value)}
placeholder="Search..."
/>
)
}For more details on state management and available state properties, see the individual guide pages for each utility (e.g., Rate Limiting Guide, Debouncing Guide).
import { createDebouncer } from '@tanstack/solid-pacer'
function SearchComponent() {
const debouncer = createDebouncer(
(query: string) => {
console.log('Searching for:', query)
// Perform search
},
{ wait: 500 }
)
return (
<input
onInput={(e) => debouncer.maybeExecute(e.currentTarget.value)}
placeholder="Search..."
/>
)
}import { createAsyncQueuer } from '@tanstack/solid-pacer'
function UploadComponent() {
const queuer = createAsyncQueuer(
async (file: File) => {
await uploadFile(file)
},
{ concurrency: 3 }
)
const handleFileSelect = (files: FileList) => {
Array.from(files).forEach((file) => {
queuer.addItem(file)
})
}
return (
<input
type="file"
multiple
onChange={(e) => {
if (e.target.files) {
handleFileSelect(e.target.files)
}
}}
/>
)
}import { createRateLimiter } from '@tanstack/solid-pacer'
function ApiComponent() {
const rateLimiter = createRateLimiter(
(data: string) => {
return fetch('/api/endpoint', {
method: 'POST',
body: JSON.stringify({ data }),
})
},
{
limit: 5,
window: 60000,
windowType: 'sliding',
onReject: () => {
alert('Rate limit reached. Please try again later.')
},
}
)
const handleSubmit = () => {
const remaining = rateLimiter.getRemainingInWindow()
if (remaining > 0) {
rateLimiter.maybeExecute('some data')
}
}
return <button onClick={handleSubmit}>Submit</button>
}