关于 using-nuqs
面向 React 开发者的 nuqs 使用指南,用于将界面状态同步到 URL 查询参数。内容涵盖 Suspense 边界、解析器、清除状态和可分享的对话框。
主要功能
- 01将 React 状态同步到 URL 参数
- 02使用解析器和默认值
- 03清除单个或多个参数
- 04构建可深链访问的对话框
- 05就近设置 Suspense 边界
适用场景
- 01创建可分享的搜索和筛选链接
- 02通过链接打开对话框
- 03从 URL 清除筛选项
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ andrelandgraf/ fullstackrecipes --skill using-nuqs安装后在 Claude Code 中输入/using-nuqs确认已加载。
详细介绍
使用 nuqs
使用 nuqs 管理 URL 查询参数中的 React 状态。涵盖 Suspense 边界、解析器、清除状态以及可通过深层链接打开的对话框。
实现使用 nuqs
使用 nuqs 管理 URL 查询参数中的 React 状态,以实现可分享的筛选条件、搜索和可通过深层链接打开的对话框。
参见:
- 资源:Fullstack Recipes 中的
using-nuqs - URL:https://fullstackrecipes.com/recipes/using-nuqs
Suspense 边界模式
nuqs 在底层使用 useSearchParams,因此需要 Suspense 边界。通过包装组件使用 Suspense 包裹使用 nuqs 的组件,使边界与组件保持在一起:
import { Suspense } from "react";
type SearchInputProps = {
placeholder?: string;
};
// Public component with built-in Suspense
export function SearchInput(props: SearchInputProps) {
return (
<Suspense fallback={<input placeholder={props.placeholder} disabled />}>
<SearchInputClient {...props} />
</Suspense>
);
}
"use client";
import { useQueryState, parseAsString } from "nuqs";
// Internal client component that uses 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}
/>
);
}
使用此模式后,使用该组件的组件可以直接使用 SearchInput,无需自行添加 Suspense。
将状态同步到 URL 查询参数
将 useState 替换为 useQueryState,即可将状态同步到 URL:
"use client";
import {
useQueryState,
parseAsString,
parseAsBoolean,
parseAsArrayOf,
} from "nuqs";
// String state (search, filters)
const [search, setSearch] = useQueryState("q", parseAsString.withDefault(""));
// Boolean state (toggles)
const [showArchived, setShowArchived] = useQueryState(
"archived",
parseAsBoolean.withDefault(false),
);
// Array state (multi-select)
const [tags, setTags] = useQueryState(
"tags",
parseAsArrayOf(parseAsString).withDefault([]),
);
清除状态
设为 null 即可从 URL 中移除:
// Clear single param
setSearch(null);
// Clear all filters
function clearFilters() {
setSearch(null);
setTags(null);
setShowArchived(null);
}
使用 .withDefault() 时,设为 null 会清除 URL 参数,但会返回默认值。
可通过深层链接打开的对话框
使用 URL 参数控制对话框的显示状态,以便分享链接:
import { Suspense } from "react";
type DeleteDialogProps = {
onDelete: (id: string) => Promise<void>;
};
// Public component with built-in Suspense
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>
{/* Confirmation UI */}
<Button onClick={handleDelete}>Delete</Button>
</AlertDialogContent>
</AlertDialog>
);
}
以编程方式打开对话框:
// Open delete dialog for specific item
setDeleteId("item-123");
// Deep link: /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