If you are using TanStack Pacer in a Solid application, we recommend using the Solid Adapter. The Solid Adapter provides a set of easy-to-use hooks on top of the core Pacer utilities. If you find yourself wanting to use the core Pacer classes/functions directly, the Solid Adapter will also re-export everything from the core package.
npm install @tanstack/solid-pacer
npm install @tanstack/solid-pacer
See the Solid Functions Reference to see the full list of hooks available 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,
})
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 separately
import { debounce, Debouncer } from '@tanstack/solid-pacer' // no need to install the core package separately
If you want a type-safe way to define common options for pacer utilities, TanStack Pacer provides option helpers for each utility. These helpers can be used with Solid 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 { 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 { createQueuer } from '@tanstack/solid-pacer'
import { queuerOptions } from '@tanstack/pacer'
const commonQueuerOptions = queuerOptions({
concurrency: 3,
addItemsTo: 'back',
})
const queuer = createQueuer(
(item: string) => processItem(item),
{ ...commonQueuerOptions, key: 'itemQueuer' }
)
import { createQueuer } from '@tanstack/solid-pacer'
import { queuerOptions } from '@tanstack/pacer'
const commonQueuerOptions = queuerOptions({
concurrency: 3,
addItemsTo: 'back',
})
const queuer = createQueuer(
(item: string) => processItem(item),
{ ...commonQueuerOptions, 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' }
)
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 Solid Adapter provides a PacerProvider component that you can use to provide default options to all instances of pacer utilities within your component tree.
import { PacerProvider } from '@tanstack/solid-pacer'
// Set default options for solid-pacer instances
<PacerProvider
defaultOptions={{
debouncer: { wait: 1000 },
queuer: { concurrency: 3 },
rateLimiter: { limit: 5, window: 60000 },
}}
>
<App />
</PacerProvider>
import { PacerProvider } from '@tanstack/solid-pacer'
// Set default options for solid-pacer instances
<PacerProvider
defaultOptions={{
debouncer: { wait: 1000 },
queuer: { concurrency: 3 },
rateLimiter: { limit: 5, window: 60000 },
}}
>
<App />
</PacerProvider>
All hooks within the provider will automatically use these default options, which can be overridden on a per-hook basis.
The Solid Adapter supports subscribing to state changes in two ways:
Use the Subscribe component to subscribe to state changes deep in your component tree without needing to pass a selector to the hook. This is ideal when you want to subscribe to state in child components.
Note: In Solid, the Subscribe component provides an accessor (signal) to the selected state. You must call state() to access 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>
)
}
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 allows you to specify which state changes will trigger reactive updates at the hook level, optimizing performance by preventing unnecessary updates when irrelevant state changes occur.
By default, hook.state is empty ({}) as the selector is empty by default. You must opt-in to state tracking by providing a selector function.
Note: In Solid, hook.state is an accessor (signal). You must call hook.state() to access the value.
import { createDebouncer } from '@tanstack/solid-pacer'
function SearchComponent() {
// Default behavior - no reactive state subscriptions
const debouncer = createDebouncer(
(query: string) => fetchSearchResults(query),
{ wait: 500 }
)
console.log(debouncer.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..."
/>
)
}
import { createDebouncer } from '@tanstack/solid-pacer'
function SearchComponent() {
// Default behavior - no reactive state subscriptions
const debouncer = createDebouncer(
(query: string) => fetchSearchResults(query),
{ wait: 500 }
)
console.log(debouncer.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 { 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 { createQueuer } from '@tanstack/solid-pacer'
function UploadComponent() {
const queuer = createQueuer(
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 { createQueuer } from '@tanstack/solid-pacer'
function UploadComponent() {
const queuer = createQueuer(
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>
}
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>
}