reactjs 如何正确序列化查询参数?

qojgxg4l  于 2023-01-25  发布在  React
关注(0)|答案(3)|浏览(125)

bounty将于明天过期。此问题的答案可获得+100的声誉奖励。Guerric P正在寻找此问题的最新答案

为了检索当前的查询参数,我使用以下代码:

import { useLocation } from 'react-router-dom';

function useQuery() {
    return new URLSearchParams(useLocation().search);
}

然后在功能组件中:

const query = useQuery();

但是,除了一个新值之外,我没有找到任何集成的解决方案可以轻松地将Link设置为相同的查询参数。
以下是我目前的解决方案:

const filterLink = query => param => value => {
  const clone = new URLSearchParams(query.toString());
  clone.set(param, value);
  return `?${clone.toString()}`;
}

return (
  <>
    <Link to={filterLink(query)('some-filter')('false')}>False</Link>
    <Link to={filterLink(query)('some-filter')('true')}>True</Link>
  </>
)

我必须克隆query对象,以免在JSX中多次调用filterLink时改变原始对象并产生不必要的副作用。我还必须自己添加问号,因为URLSearchParams.prototype.toString()没有添加它。
我想知道为什么我必须自己去做?我真的不喜欢在使用框架时做这么低级的事情。我错过了react-router中的什么吗?有没有更常见的实践来做我需要做的事情?

ht4b089n

ht4b089n1#

Angular是一个框架,而React通常被认为仍然是一个库。因此,React更像是自己动手(DYI)。React不关心URL查询字符串,而react-router主要关心用于路由匹配和渲染的URL路径。

但是react-router-dom@6引入了一些新的钩子和实用函数来帮助处理queryString参数。createSearchParams函数是一个有用的实用函数。

declare function createSearchParams(
  init?: URLSearchParamsInit
): URLSearchParams;

createSearchParamsnew URLSearchParams(init)的一个精简 Package 器,它增加了对使用带有数组值的对象的支持。这与useSearchParams内部用于从URLSearchParamsInit值创建URLSearchParams对象的函数相同。
根据您的问题和其他人的回答,我假设您不只是需要清除以前存在的搜索参数并用当前链接替换它们,而是可能需要有条件地将新参数与任何现有参数合并。
创建一个实用函数,它使用与Link组件的to prop(string | Partial<Path>)相同的prop,我们关心并想要覆盖的是部分Path类型。

import { createSearchParams, To } from "react-router-dom";

interface CreatePath {
  pathname: string;
  search?: {
    [key: string]: string | number;
  };
  hash?: string;
  merge?: boolean;
}

const createPath = ({
  hash,
  merge = true,
  pathname,
  search = {}
}: CreatePath): To => {
  const searchParams = createSearchParams({
    ...(merge
      ? (Object.fromEntries(createSearchParams(window.location.search)) as {})
      : {}),
    ...search
  });

  return { pathname, search: searchParams.toString(), hash };
};

用法:
1.将参数与现有queryString参数合并的链接:

<Link to={createPath({ pathname: "/somePage", search: { a: 1 } })}>
  Some Page
</Link>

1.替换现有参数的链接:

<Link
  to={createPath({ pathname: "/somePage", search: { b: 2 }, merge: false })}
>
  Some Page
</Link>

我建议您更进一步,创建一个定制的Link组件,为您执行路径创建步骤。
基于上述效用函数的示例:

import { Link as LinkBase, LinkProps as BaseLinkProps } from "react-router-dom";

// Override the to prop
interface LinkProps extends Omit<BaseLinkProps, "to"> {
  to: CreatePath;
}

// Use our new createPath utility
const Link = ({ to, ...props }: LinkProps) => (
  <LinkBase to={createPath(to)} {...props} />
);

用法与上面相同,但现在直接传递to属性:
1.将参数与现有queryString参数合并的链接:

<Link to={{ pathname: "/somePage", search: { a: 1 } }}>
  Some Page
</Link>

1.替换现有参数的链接:

<Link to={{ pathname: "/somePage", search: { b: 2 }, merge: false }}>
  Some Page
</Link>

演示:

1wnzp6jl

1wnzp6jl2#

我也不知道react-router和查询有什么关系,这是我之前设置它的代码。

const _encode = v => {
  if (v === undefined || v === null) return ''
  return encodeURIComponent(v)
}

const queryString = params => Object
  .keys(params)
  .map(key => (_encode(key) + '=' + _encode(params[key])))
  .join('&')

就像你说的,我也必须添加?
我的两分钱,路由器实际上并不支持这些参数。也许useQuery只是有点方便,但除此之外,他们在设置路由时不使用任何参数。

4ioopgfo

4ioopgfo3#

这是我的一线解决方案

import encodeurl from "encodeurl";

Object.entries(inputObject)
    .map(([key, value]) => `${key}=${encodeurl(value)}`)
    .join("&");

相关问题