Agent Skillssimstudioai/sim › you-might-not-need-url-state

you-might-not-need-url-state

GitHub

分析并修复前端 URL 状态管理反模式,强制使用 nuqs 库替代手动 useSearchParams 读取、手写查询字符串拼接及 useState 同步,确保 URL 作为视图状态单一事实来源。

.agents/skills/you-might-not-need-url-state/SKILL.md simstudioai/sim

Trigger Scenarios

审查前端代码中 URL/查询参数状态的使用 检查是否违规使用 useSearchParams 读取视图状态 检测手写 query string 或 router.replace 修改参数 发现 URL 状态与 store/useState 重复同步

Install

npx skills add simstudioai/sim --skill you-might-not-need-url-state -g -y
More Options

Non-standard path

npx skills add https://github.com/simstudioai/sim/tree/main/.agents/skills/you-might-not-need-url-state -g -y

Use without installing

npx skills use simstudioai/sim@you-might-not-need-url-state

指定 Agent (Claude Code)

npx skills add simstudioai/sim --skill you-might-not-need-url-state -a claude-code -g -y

安装 repo 全部 skill

npx skills add simstudioai/sim --all -g -y

预览 repo 内 skill

npx skills add simstudioai/sim --list

SKILL.md

Frontmatter
{
    "name": "you-might-not-need-url-state",
    "description": "Analyze and fix URL\/query-param state anti-patterns — manual useSearchParams reads, hand-built query mutations, view-state trapped in useState, and objects in the URL",
    "argument-hint": "[scope] [fix=true|false]"
}

You Might Not Need URL State

Arguments:

  • scope: what to analyze (default: your current changes). Examples: "diff to main", "PR #123", "app/workspace/[workspaceId]/tables/", "whole codebase"
  • fix: whether to apply fixes (default: true). Set to false to only propose changes.

User arguments: $ARGUMENTS

Context

Shareable client view-state (active tab/panel, filters, search query, sort, pagination, selected-entity id, an open "view" modal/drawer that is a destination) lives in the URL via nuqs — driven by a co-located search-params.ts, never read via useSearchParams().get(...) and never mutated by hand-built query strings. Remote data stays in React Query; high-frequency / large / ephemeral / socket-synced state stays in Zustand; purely local UI stays in useState.

Shared helpers own the two repeated wirings — never hand-roll them inline:

  • Sort: createSortParams from @/lib/url-state (in search-params.ts) + useUrlSort from @/hooks/use-url-sort (in the component) — defaulted mode for lists with a fixed default ordering, nullable mode when "no active sort" is distinct from the default column.
  • Debounced search: useDebouncedSearchSetter from @/hooks/use-debounced-search-setter (grouped or single-param); settings list search boxes use useSettingsSearch() from settings/components/use-settings-search. Never write a trimmed value to a param that controls the input — trim on read.

.claude/rules/sim-url-state.md is the source of truth — read it first.

References

Read these before analyzing:

  1. .claude/rules/sim-url-state.md — the decision framework, conventions, debounced-input pattern, sort convention, selected-entity deep-link pattern, and the workflow-editor carve-out
  2. https://nuqs.dev/docs/parsers — parsers (parseAsString/parseAsInteger/parseAsBoolean/parseAsStringLiteral/parseAsArrayOf/createParser)
  3. https://nuqs.dev/docs/optionswithDefault, history, shallow, clearOnDefault
  4. https://nuqs.dev/docs/server-sidecreateSearchParamsCache for server reads

Anti-patterns to detect

  1. Manual param reads for state: useSearchParams().get(...) or new URLSearchParams(window.location.search) used to read view-state. Replace with useQueryState/useQueryStates bound to a search-params.ts. (Read-once auth/invite/redirect tokens — token, callbackUrl, redirect, error, invite_flow, code — are NOT view-state; leave them on useSearchParams.)
  2. Hand-built query mutation: constructing a query string + router.replace/router.push to change a param on the current path. Use a nuqs setter. (A router.push that changes the route path is fine; an outbound new URLSearchParams building an href/window.open/download/API URL is fine.)
  3. window.history.replaceState/pushState to mutate a param.
  4. URL state duplicated into a store/useState + synced with an effect (or a popstate listener). The URL is the single source of truth; derive from it, don't mirror it.
  5. Objects in the URL: serializing a TableDefinition/SkillDefinition/etc. Store the id and derive the object from the loaded list (items.find(i => i.id === id)).
  6. High-frequency / large state in the URL: cursor, pan/zoom, un-debounced keystrokes, big JSON blobs. Debounce text search via useDebouncedSearchSetter (never a local useState mirror + reconcile effect, and never inline limitUrlUpdates wiring); keep canvas/presence/resize state in Zustand.
  7. Shareable view-state trapped in useState: a tab/filter/sort/pagination/selected-entity that should be a link but lives in local state. Migrate it to the URL.
  8. Missing Suspense boundary: a component newly calling useQueryState/useQueryStates whose page entry has no <Suspense> wrapper (Next.js requires it for useSearchParams). Add one with a real-chrome fallback.
  9. import { z } for param validation in client code: use nuqs parsers instead.
  10. Re-implemented shared wiring: a hand-rolled SORT_DIRECTIONS/default-sort constants/activeSort derivation instead of createSortParams + useUrlSort, or an inline debounced-search setter instead of useDebouncedSearchSetter/useSettingsSearch.

Steps

  1. Read .claude/rules/sim-url-state.md and the nuqs docs above to understand the guidelines
  2. Analyze the specified scope for the anti-patterns listed above
  3. For each finding, decide the correct home using the decision table — do not force URL state onto ephemeral/high-frequency/socket-synced state
  4. If fix=true, apply the fixes (co-locate a search-params.ts, wire useQueryState(s) — sort via createSortParams + useUrlSort, search via useDebouncedSearchSetter — add the Suspense boundary, delete the replaced state + sync effects). If fix=false, propose the fixes without applying.

Version History

  • ceda457 Current 2026-08-20 15:30

Same Skill Collection

.agents/skills/add-block-preview/SKILL.md
.agents/skills/add-block/SKILL.md
.agents/skills/add-column-type/SKILL.md
.agents/skills/add-connector/SKILL.md
.agents/skills/add-enrichment/SKILL.md
.agents/skills/add-feature-flag/SKILL.md
.agents/skills/add-hosted-key/SKILL.md
.agents/skills/add-integration/SKILL.md
.agents/skills/add-managed-cli/SKILL.md
.agents/skills/add-model/SKILL.md
.agents/skills/add-tools/SKILL.md
.agents/skills/add-trigger/SKILL.md
.agents/skills/babysit/SKILL.md
.agents/skills/cleanup/SKILL.md
.agents/skills/council/SKILL.md
.agents/skills/db-migrate/SKILL.md
.agents/skills/design-taste-frontend/SKILL.md
.agents/skills/emcn-design-review/SKILL.md
.agents/skills/emil-design-eng/SKILL.md
.agents/skills/make-interfaces-feel-better/SKILL.md
.agents/skills/memory-load-check/SKILL.md
.agents/skills/react-query-best-practices/SKILL.md
.agents/skills/ship/SKILL.md
.agents/skills/tool-registry-boundary/SKILL.md
.agents/skills/v2-api-conventions/SKILL.md
.agents/skills/validate-connector/SKILL.md
.agents/skills/validate-integration/SKILL.md
.agents/skills/validate-model/SKILL.md
.agents/skills/validate-trigger/SKILL.md
.agents/skills/you-might-not-need-a-callback/SKILL.md
.agents/skills/you-might-not-need-a-comment/SKILL.md
.agents/skills/you-might-not-need-a-memo/SKILL.md
.agents/skills/you-might-not-need-an-effect/SKILL.md
.agents/skills/you-might-not-need-state/SKILL.md
.claude/skills/add-settings-page/SKILL.md
helm/sim/.claude/skills/sim-helm/SKILL.md
.agents/skills/migrate-application-operation/SKILL.md

Metadata

Files
0
Version
ceda457
Hash
d8e604ff
Indexed
2026-08-20 15:30

- 위키
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-25 11:41
浙ICP备14020137号-1 $방문자$