Skip to content

Commit

Permalink
chore: Update throttling example with user delays
Browse files Browse the repository at this point in the history
  • Loading branch information
franky47 committed Nov 8, 2023
1 parent 943ce9b commit 739ab7a
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 15 deletions.
103 changes: 91 additions & 12 deletions packages/playground/src/app/demos/throttling/client.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,102 @@
'use client'

import { parseAsString, useQueryState } from 'next-usequerystate'
import { useQueryState } from 'next-usequerystate'
import { useRouter } from 'next/navigation'
import React from 'react'
import { delayParser, queryParser } from './parsers'

const autoFillMessage = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor.`

export function Client() {
const [q, setQ] = useQueryState(
'q',
parseAsString
.withOptions({ throttleMs: 350, shallow: false })
.withDefault('')
const [serverDelay, setServerDelay] = useQueryState('serverDelay', {
...delayParser,
shallow: false
})
const [clientDelay, setClientDelay] = useQueryState(
'clientDelay',
delayParser
)
const [q, setQ] = useQueryState('q', {
...queryParser,
throttleMs: clientDelay,
shallow: false
})
const router = useRouter()

const timeoutRef = React.useRef<number>()
const [index, setIndex] = React.useState(0)

React.useEffect(() => {
if (index === 0) {
return
}
setQ(autoFillMessage.slice(0, index))
clearTimeout(timeoutRef.current)
if (index === autoFillMessage.length) {
return
}
timeoutRef.current = window.setTimeout(() => {
setIndex(i => Math.min(i + 1, autoFillMessage.length))
}, 80)
}, [index])

return (
<>
<input
value={q}
onChange={e => setQ(e.target.value)}
placeholder="Search"
/>
<p>Query: {q || <em>empty</em>}</p>
<h2>Client</h2>
<div>
<label>Server latency simulation </label>
<select
value={serverDelay}
onChange={e =>
setServerDelay(parseInt(e.target.value)).then(() =>
router.refresh()
)
}
>
<option value="0">No delay</option>
<option value="100">100ms</option>
<option value="200">200ms</option>
<option value="500">500ms</option>
<option value="1000">1s</option>
</select>
</div>
<div>
<label>Throttle URL updates at </label>
<select
value={clientDelay}
onChange={e => setClientDelay(parseInt(e.target.value))}
>
<option value="50">Default (50ms)</option>
<option value="100">100ms</option>
<option value="200">200ms</option>
<option value="500">500ms</option>
<option value="1000">1s</option>
</select>
</div>
<br />
<div>
<label>Query </label>
<input
value={q}
onChange={e => setQ(e.target.value)}
placeholder="Search"
/>
{timeoutRef.current ? (
<button
onClick={() => {
setIndex(0)
clearTimeout(timeoutRef.current)
timeoutRef.current = undefined
setQ(null)
}}
>
Cancel
</button>
) : (
<button onClick={() => setIndex(1)}>Simulate typing</button>
)}
<p>Client state: {q || <em>empty</em>}</p>
</div>
</>
)
}
30 changes: 27 additions & 3 deletions packages/playground/src/app/demos/throttling/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,35 @@
import { setTimeout } from 'node:timers/promises'
import { Suspense } from 'react'
import { Client } from './client'
import { delayParser, queryParser } from './parsers'

export default function ThottlingDemoPage() {
type PageParams = {
searchParams: {
q?: string | string[]
serverDelay?: string | string[]
}
}

export default async function ThottlingDemoPage({ searchParams }: PageParams) {
const serverDelay = delayParser.parseServerSide(searchParams.serverDelay)
const query = queryParser.parseServerSide(searchParams.q)
await setTimeout(serverDelay)
console.debug('Server query: %s', query)
return (
<>
<h1>Throttled counters</h1>
<p>Note: URL state updated are intentionally slowed down</p>
<h1>Throttling</h1>
<p>
Play with the various delays, and try throttling your network connection
in devtools.
</p>
<p>
When the client is faster to update the URL than the network is to
re-render the server components, the server may hang under the waterfall
of heavy load.
</p>
<h2>Server</h2>
<p>Server delay: {serverDelay} ms</p>
<p>Server query: {query}</p>
<Suspense>
<Client />
</Suspense>
Expand Down
4 changes: 4 additions & 0 deletions packages/playground/src/app/demos/throttling/parsers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { parseAsInteger, parseAsString } from 'next-usequerystate/parsers'

export const delayParser = parseAsInteger.withDefault(0)
export const queryParser = parseAsString.withDefault('')

0 comments on commit 739ab7a

Please sign in to comment.