繁体   English   中英

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

[英]How to properly serialize query params?

为了检索当前的查询参数,我使用了这个:

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 object 以免改变原始查询并在 JSX 中多次调用filterLink时产生不需要的副作用。 我还必须自己添加问号,因为URLSearchParams.prototype.toString()不会添加它。

我想知道为什么我必须自己做? 在使用框架时,我真的不喜欢做这么低级的事情。 我错过了 react-router 中的某些内容吗? 有没有更常见的做法来做我需要的事情?

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

然而react-router-dom@6引入了一些新的钩子和实用函数来帮助处理 queryString 参数。 createSearchParams function 是您可能会发现对这项工作有帮助的一个实用程序。

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

createSearchParams是围绕new URLSearchParams(init)的精简包装器,它增加了对使用具有数组值的对象的支持。 这与useSearchParams在内部用于从URLSearchParamsInit值创建URLSearchParams对象的 function 相同。

根据你的问题和这里的其他答案,我假设你不需要简单地删除以前存在的搜索参数并将它们替换为当前链接,而是你可能希望有条件地将新参数与任何现有参数合并。

创建一个实用程序 function,它采用与Link组件相同的道具to道具 ( string | Partial<Path> )。 这是我们关心并想要覆盖的部分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>
  2. 替换现有参数的链接:

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

我建议更进一步,创建一个自定义Link组件,为您执行路径创建步骤。

基于上述实用程序 function 的示例:

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>
  2. 替换现有参数的链接:

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

演示:

编辑如何正确序列化查询参数

这是我的oneliner解决方案

import encodeurl from "encodeurl";

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

我也不知道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有点方便,但除此之外,他们在设置路线时不使用任何这些。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM