快速开始

Decurl 的核心使用方式是:先定义一组 Search Fields,再在 hooks 或 URLSearchParams codec 中复用同一份规则。

安装

pnpm add @guanriyue/decurl

使用默认 hooks 时,@guanriyue/decurl 支持 React 18 和 React 19,并要求使用 React Router 7。对于已有的 React Router 应用,只需要添加 Decurl 依赖。

定义字段

import { createURLSearchParamsCodec, defineFields, field } from '@guanriyue/decurl/codec';
import { elementOf, min, pipe, shape, toNumber, trim } from '@guanriyue/decurl/decode';

const searchFields = defineFields({
  q: field({
    decode: pipe(trim, shape(/.+/)),
  }),
  page: field({
    name: ['page', 'p'],
    decode: pipe(trim, shape.integer, toNumber, min(1)),
    defaultValue: 1,
  }),
  sort: field({
    decode: elementOf(['relevance', 'latest']),
    defaultValue: 'relevance',
  }),
});

这里用到了几个 API:

  • field 固化单个 FieldCodec 的类型。
  • defineFields 定义一组 Search Fields,并为没有显式 name 的字段使用对象 key。
  • pipeshapeelementOf 等 decode primitive 用于组合常见解析逻辑。

解析 URLSearchParams

const codec = createURLSearchParamsCodec(searchFields);

const values = codec.decode(new URLSearchParams('?q=router&p=2&sort=latest'));

// values:
// {
//   q: 'router',
//   page: 2,
//   sort: 'latest',
// }

如果 canonical key 缺失,Decurl 会尝试 legacy alias。上面的 URL 使用的是 p=2,但 decode 后得到的是业务字段 page

序列化 URLSearchParams

const nextSearch = codec.encode(
  { page: 3 },
  { base: '?q=router&p=2&sort=latest' },
);

nextSearch.toString();
// q=router&sort=latest&page=3

encode 默认是 patch 语义:

  • 只处理 patch 中出现的字段。
  • 保留 base 中未触碰的字段。
  • 写入 alias 字段时使用 canonical key。
  • 写入 default value 时默认删除对应 key。

更多选项见 createURLSearchParamsCodec

在 React Router 中使用

React Router hooks 可以直接使用同一套 Search Fields。默认 hooks 不需要额外 Provider。

import { useSearchValues } from '@guanriyue/decurl';

const SearchPanel = () => {
  const [values, setValues] = useSearchValues(searchFields);

  return (
    <button onClick={() => setValues({ page: values.page + 1 })}>
      Next page
    </button>
  );
};

只读取单个字段时可以使用 useSearchValue。如果需要显式提供 store、配置 flush 策略,或者减少组件对 React Router useLocation 的直接依赖,可以继续看 Provided Runtime

继续阅读: