From 30f909172511f798f28df04d9f3be3245efc2ae7 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Wed, 1 Nov 2023 14:08:36 +0100 Subject: [PATCH] chore: Update throttling example with user delays --- .../src/app/demos/throttling/client.tsx | 103 ++++++++++++++++-- .../src/app/demos/throttling/page.tsx | 30 ++++- .../src/app/demos/throttling/parsers.ts | 4 + 3 files changed, 122 insertions(+), 15 deletions(-) create mode 100644 packages/playground/src/app/demos/throttling/parsers.ts diff --git a/packages/playground/src/app/demos/throttling/client.tsx b/packages/playground/src/app/demos/throttling/client.tsx index 8b0192f7a..1893bb020 100644 --- a/packages/playground/src/app/demos/throttling/client.tsx +++ b/packages/playground/src/app/demos/throttling/client.tsx @@ -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() + 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 ( <> - setQ(e.target.value)} - placeholder="Search" - /> -

Query: {q || empty}

+

Client

+
+ + +
+
+ + +
+
+
+ + setQ(e.target.value)} + placeholder="Search" + /> + {timeoutRef.current ? ( + + ) : ( + + )} +

Client state: {q || empty}

+
) } diff --git a/packages/playground/src/app/demos/throttling/page.tsx b/packages/playground/src/app/demos/throttling/page.tsx index 3b1e8434e..7f77f0a2b 100644 --- a/packages/playground/src/app/demos/throttling/page.tsx +++ b/packages/playground/src/app/demos/throttling/page.tsx @@ -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 ( <> -

Throttled counters

-

Note: URL state updated are intentionally slowed down

+

Throttling

+

+ Play with the various delays, and try throttling your network connection + in devtools. +

+

+ 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. +

+

Server

+

Server delay: {serverDelay} ms

+

Server query: {query}

diff --git a/packages/playground/src/app/demos/throttling/parsers.ts b/packages/playground/src/app/demos/throttling/parsers.ts new file mode 100644 index 000000000..cbf955c66 --- /dev/null +++ b/packages/playground/src/app/demos/throttling/parsers.ts @@ -0,0 +1,4 @@ +import { parseAsInteger, parseAsString } from 'next-usequerystate/parsers' + +export const delayParser = parseAsInteger.withDefault(0) +export const queryParser = parseAsString.withDefault('')