import { LitElement, html, nothing } from 'lit'
import { TanStackDevtoolsCore } from '@tanstack/devtools'
import { pacerDevtoolsPlugin } from '@tanstack/pacer-devtools'
import { createAsyncThrottler } from '@tanstack/lit-pacer/async-throttler'
interface SearchResult {
id: number
title: string
}
class Demo extends LitElement {
static properties = {
searchTerm: { state: true },
results: { state: true },
error: { state: true },
}
fakeApi = async (term: string): Promise<Array<SearchResult>> => {
await new Promise((resolve) => setTimeout(resolve, 500))
return [
{ id: 1, title: `${term} result ${Math.floor(Math.random() * 100)}` },
{ id: 2, title: `${term} result ${Math.floor(Math.random() * 100)}` },
{ id: 3, title: `${term} result ${Math.floor(Math.random() * 100)}` },
]
}
searchTerm = ''
results: Array<SearchResult> = []
error: Error | null = null
handleSearch = async (term: string) => {
if (!term) {
this.results = []
return
}
const data = await this.fakeApi(term)
this.results = data
this.error = null
return data
}
setSearchAsyncThrottler = createAsyncThrottler(
this,
this.handleSearch,
() => ({
key: 'createAsyncThrottler',
wait: 1000,
onError: (cause) => {
console.error('Search failed:', cause)
this.error = cause as Error
this.results = []
},
}),
(state) => state,
)
handleSearchThrottled = this.setSearchAsyncThrottler.maybeExecute
onSearchChange = async (e: Event) => {
const newTerm = (e.target as HTMLInputElement).value
this.searchTerm = newTerm
const result = await this.handleSearchThrottled(newTerm)
console.log('result', result)
}
override createRenderRoot() {
return this
}
override render() {
return html`<div>
<h1>TanStack Pacer createAsyncThrottler Example</h1>
<div>
<input
autofocus
type="search"
.value=${this.searchTerm}
@input=${this.onSearchChange}
placeholder="Type to search..."
style="width: 100%"
autocomplete="new-password"
/>
</div>
<div style="margin-top: 10px">
<button @click=${() => this.setSearchAsyncThrottler.flush()}>
Flush
</button>
</div>
${this.error ? html`<div>Error: ${this.error.message}</div>` : nothing}
<div>
<p>
API calls made: ${this.setSearchAsyncThrottler.state.successCount}
</p>
${
this.results.length > 0
? html`<ul>
${this.results.map((item) => html`<li>${item.title}</li>`)}
</ul>`
: nothing
}${this.setSearchAsyncThrottler.state.isPending ? html`<p>Pending...</p>` : html`${this.setSearchAsyncThrottler.state.isExecuting ? html`<p>Executing...</p>` : html``}`}
</div>
<pre style="margin-top: 20px">
${JSON.stringify(this.setSearchAsyncThrottler.state, null, 2)}</pre>
</div>`
}
}
customElements.define('pacer-demo', Demo)
class Example extends LitElement {
private devtools?: TanStackDevtoolsCore
private target?: HTMLDivElement
override createRenderRoot() {
return this
}
override connectedCallback() {
super.connectedCallback()
if (!import.meta.env.DEV) return
this.target = document.createElement('div')
document.body.append(this.target)
this.devtools = new TanStackDevtoolsCore({
plugins: [pacerDevtoolsPlugin()],
})
this.devtools.mount(this.target)
}
override disconnectedCallback() {
this.devtools?.unmount()
this.target?.remove()
this.devtools = undefined
this.target = undefined
super.disconnectedCallback()
}
override render() {
return html`<div><pacer-demo></pacer-demo></div>`
}
}
customElements.define('pacer-example', Example)
document.getElementById('app')!.append(document.createElement('pacer-example'))