我似乎找不到如何更新查询参数与反应路由器不使用<Link/>。hashHistory.push(url)似乎没有注册查询参数,而且似乎不能将查询对象或任何东西作为第二个参数传递。

如何将url从/shop/Clothes/dresses更改为/shop/Clothes/dresses?color=blue在反应路由器没有使用<链接>?

onChange函数真的是侦听查询更改的唯一方法吗?为什么不自动检测和响应查询更改-以参数更改的方式?


当前回答

我目前在一个正在运行的项目中使用react-router v5,不容易迁移到v6。 我写了一个钩子,允许读取和修改一个URL参数,同时保持其他URL参数不变。 数组被视为逗号分隔值的列表: magnifying_glass ?产品=管,猎鹿帽

import { useCallback } from 'react';
import { useHistory } from 'react-router';

const getDecodedUrlParam = (name: string, locationSearch: string, _default?: any) => {
  const params = deserialize(locationSearch);
  const param = params[name];

  if (_default && Array.isArray(_default)) {
    return param
      ? param.split(',').map((v: string) => decodeURIComponent(v))
      : _default;
  }

  return param ? decodeURIComponent(param) : _default;
};

const deserialize = (locationSearch: string): any => {
  if (locationSearch.startsWith('?')) {
    locationSearch = locationSearch.substring(1);
  }
  const parts = locationSearch.split('&');
  return Object.fromEntries(parts.map((part) => part.split('=')));
};

const serialize = (params: any) =>
  Object.entries(params)
    .map(([key, value]) => `${key}=${value}`)
    .join('&');

export const useURLSearchParam = (name: string, _default?: any) => {
  const history = useHistory();
  const value: any = getDecodedUrlParam(name, location.search, _default);
  const _update = useCallback(
    (value: any) => {
      const params = deserialize(location.search);
      if (Array.isArray(value)) {
        params[name] = value.map((v) => encodeURIComponent(v)).join(',');
      } else {
        params[name] = encodeURIComponent(value);
      }
      history.replace({ pathname: location.pathname, search: serialize(params) });
    },
    [history, name]
  );
  const _delete = useCallback(() => {
    const params = deserialize(location.search);
    delete params[name];
    history.replace({ pathname: location.pathname, search: serialize(params) });
  }, [history, name]);
  return [value, _update, _delete];
};

其他回答

使用React Router V6,我们可以像这样实现它

import { useNavigate, createSearchParams } from 'react-router-dom';

/* In React Component */
const navigate = useNavigate();
const params = {
  color: 'blue',
};
const options = {
  pathname: '/shop/Clothes/dresses',
  search: `?${createSearchParams(params)}`,
};
navigate(options, { replace: true });

对于React Router v6+,只需使用新的useSearchParams钩子(特别是setSearchParams):

const [searchParams, setSearchParams] = useSearchParams()

setSearchParams(`?${new URLSearchParams({ paramName: 'whatever' })}`)

对于React Router v5使用useHistory:

const history = useHistory()

history.push({
    pathname: '/the-path',
    search: `?${new URLSearchParams({ paramName: 'whatever' })}`
})

URLSearchParams只是一个可选的方便助手。

当你需要一个模块来轻松地解析你的查询字符串时,推荐使用query-string模块。

http://localhost:3000?token=xxx-xxx-xxx

componentWillMount() {
    var query = queryString.parse(this.props.location.search);
    if (query.token) {
        window.localStorage.setItem("jwt", query.token);
        store.dispatch(push("/"));
    }
}

在这里,我从Node.js服务器重定向回我的客户端后,成功的Google-Passport身份验证,这是重定向回令牌作为查询参数。

我用query-string模块解析它,保存它并更新url中的查询参数,从react-router-redux推送。

在hashHistory的push方法中,可以指定查询参数。例如,

history.push({
  pathname: '/dresses',
  search: '?color=blue'
})

or

history.push('/dresses?color=blue')

您可以查看这个存储库以获得有关使用历史记录的其他示例

React-router-dom v5解决方案

  import { useHistory } from 'react-router-dom'; 
  const history = useHistory(); // useHistory hook inside functional component  
    
  history.replace({search: (new URLSearchParams({activetab : 1})).toString()});

建议使用URLSearchParams,因为它可以在编码和解码查询参数时处理查询参数中的空格和特殊字符

    new URLSearchParams({'active tab':1 }).toString() // 'active+tab=1'
    new URLSearchParams('active+tab=1').get('active tab') // 1