mcpField
U
url-state-patterns

url-state-patterns

github.com/andrelandgraf开发2397 次安装20 周前更新
代码仓库

关于 url-state-patterns

面向 React 开发者的 nuqs 技能,用于将应用状态同步到 URL 查询参数。内容涵盖解析器、Suspense 包装、清除参数及可通过链接访问的对话框。

主要功能

  1. 01将状态同步到查询参数
  2. 02使用类型化查询解析器
  3. 03用 Suspense 包装组件
  4. 04以 null 清除参数
  5. 05在 URL 中保存对话框状态

适用场景

  1. 01让搜索内容随 URL 分享
  2. 02用解析后的查询值表示筛选条件
  3. 03通过深层链接打开指定条目的对话框

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/andrelandgraf/fullstackrecipes --skill url-state-patterns

安装后在 Claude Code 中输入/url-state-patterns确认已加载。

详细介绍

URL 状态模式

使用 nuqs 将 React 状态同步到 URL 查询参数。

前置条件

请先完成以下设置指南:

  • 使用 nuqs 管理 URL 状态
Suspense 包装器

nuqs 会读取 useSearchParams,因此需要 Suspense 边界。通过导出一个会挂起内部客户端组件的公共包装器,将 Suspense 边界放在组件附近,这样使用者就无需自行添加 Suspense。

import { Suspense } from "react";

type SearchInputProps = { placeholder?: string };

export function SearchInput(props: SearchInputProps) {
  return (
    <Suspense fallback={<input placeholder={props.placeholder} disabled />}>
      <SearchInputClient {...props} />
    </Suspense>
  );
}
"use client";

import { useQueryState, parseAsString } from "nuqs";

function SearchInputClient({ placeholder = "Search..." }: SearchInputProps) {
  const [search, setSearch] = useQueryState("q", parseAsString.withDefault(""));

  return (
    <input
      value={search}
      onChange={(e) => setSearch(e.target.value || null)}
      placeholder={placeholder}
    />
  );
}
解析器

使用解析器和 useQueryState 替换 useState。使用 .withDefault() 读取回退值,同时保持 URL 简洁。

"use client";

import {
  useQueryState,
  parseAsString,
  parseAsBoolean,
  parseAsArrayOf,
} from "nuqs";

const [search, setSearch] = useQueryState("q", parseAsString.withDefault(""));
const [showArchived, setShowArchived] = useQueryState(
  "archived",
  parseAsBoolean.withDefault(false),
);
const [tags, setTags] = useQueryState(
  "tags",
  parseAsArrayOf(parseAsString).withDefault([]),
);
清除

将值设为 null,即可从 URL 中移除该值。使用 .withDefault() 时,参数会被清除,但读取结果仍为默认值。

setSearch(null);

function clearFilters() {
  setSearch(null);
  setTags(null);
  setShowArchived(null);
}
可通过深层链接访问的对话框

通过 URL 参数控制对话框的显示状态,使其可分享并在前进/后退导航时保留状态。使用相同的 Suspense 模式进行包装。

import { Suspense } from "react";

type DeleteDialogProps = { onDelete: (id: string) => Promise<void> };

export function DeleteDialog(props: DeleteDialogProps) {
  return (
    <Suspense fallback={null}>
      <DeleteDialogClient {...props} />
    </Suspense>
  );
}
"use client";

import { useQueryState, parseAsString } from "nuqs";
import { AlertDialog, AlertDialogContent } from "@/components/ui/alert-dialog";

function DeleteDialogClient({ onDelete }: DeleteDialogProps) {
  const [deleteId, setDeleteId] = useQueryState("delete", parseAsString);

  async function handleDelete() {
    if (!deleteId) return;
    await onDelete(deleteId);
    setDeleteId(null);
  }

  return (
    <AlertDialog open={!!deleteId} onOpenChange={(open) => !open && setDeleteId(null)}>
      <AlertDialogContent>
        <Button onClick={handleDelete}>Delete</Button>
      </AlertDialogContent>
    </AlertDialog>
  );
}

只需设置参数,即可从任意位置打开它——setDeleteId("item-123") 会生成深层链接 /items?delete=item-123。

function ItemRow({ item }: { item: Item }) {
  const [, setDeleteId] = useQueryState("delete", parseAsString);
  return (
    <Button variant="ghost" onClick={() => setDeleteId(item.id)}>
      Delete
    </Button>
  );
}

参考资料

评论

支持 Markdown