Skip to content

React Scenarios

Search box (debounce + timeout + retry)

tsx
import { useState } from 'react'
import { debounce, Http } from 'nex-lib'
export default function Search() {
  const [q, setQ] = useState('')
  const run = debounce(async (kw: string) => {
    const data = await Http.get('/api/search', { query: { q: kw }, timeoutMs: 3000, retry: { times: 3, delay: 200 } })
    // setList(data)
  }, 300)
  return <input value={q} onChange={e => { setQ(e.target.value); run(e.target.value) }} />
}

Countdown (TTL + server time)

tsx
import { useEffect, useState } from 'react'
import { nextAt, nowSeconds, formatDuration, Http, StorageUtils } from 'nex-lib'
export default function Countdown() {
  const [remain, setRemain] = useState('00:00:00')
  const cached = StorageUtils.getWithTTL('holiday_target')
  const computedTarget = nextAt(3, 18)
  const target = typeof cached === 'number' ? cached : computedTarget
  StorageUtils.setWithTTL('holiday_target', target, 24*60*60*1000)
  useEffect(() => {
    let t: any
    async function tick() {
      const now = await Http.get('/api/time', { timeoutMs: 3000, retry: 2 })
        .then((r: any) => r.now).catch(() => nowSeconds())
      setRemain(formatDuration(Math.max(0, (target - now) * 1000)))
    }
    t = setInterval(tick, 1000)
    return () => clearInterval(t)
  }, [])
  return <span>{remain}</span>
}

UTM merge + same‑origin + copy

tsx
import { createWURL, StorageUtils, browserUtils } from 'nex-lib'
export function Share({ sku }: { sku: string }) {
  const w = createWURL(location.href)
  const merged = w.replaceParams({ ...w.parseQueryParams(), utm_source: 'web', sku })
  async function copy() {
    if (!w.isSameOrigin(merged)) throw new Error('unsafe')
    StorageUtils.setWithTTL('utm', merged, 7*24*60*60*1000)
    await browserUtils.copyToClipboard(merged)
  }
  return <button onClick={copy}>Copy</button>
}

Released under the ISC License.