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

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

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


当前回答

您可以使用replace功能,而不是在每次更改时推送一个新路由

import React from 'react';
import { useHistory, useLocation } from 'react-router';

const MyComponent = ()=>{
   const history = useHistory();
   const location = useLocation();

   const onChange=(event)=>{
     const {name, value} = event?.target;
     const params = new URLSearchParams({[name]: value });
     history.replace({ pathname: location.pathname, search: params.toString() });       
   }

   return <input name="search" onChange={onChange} />
}

这保留了历史,而不是在每一个变化上都推一条新的道路

更新- 2022年2月(V6)

正如Matrix Spielt指出的那样,useHistory被usenavate取代来进行更改。还有一个方便的方法叫做useSearchParams,我只需要阅读文档,没有运行这个,但这应该可以工作

import React from 'react';
import { useSearchParams } from 'react-router-dom';
// import from react-router should also work but following docs
// import { useSearchParams } from 'react-router';

const MyComponent = ()=>{
   const [searchParams, setSearchParams] = useSearchParams();

   const onChange=(event)=>{
     const {name, value} = event?.target;
     setSearchParams({[name]: value})       
   }

   return <input name="search" onChange={onChange} />
}

其他回答

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

对于react-router v4.3

const addQuery = (key, value) => {
  let pathname = props.location.pathname;
  // returns path: '/app/books'
  let searchParams = new URLSearchParams(props.location.search);
  // returns the existing query string: '?type=fiction&author=fahid'
  searchParams.set(key, value);
  this.props.history.push({
    pathname: pathname,
    search: searchParams.toString()
  });
};

const removeQuery = (key) => {
  let pathname = props.location.pathname;
  // returns path: '/app/books'
  let searchParams = new URLSearchParams(props.location.search);
  // returns the existing query string: '?type=fiction&author=fahid'
  searchParams.delete(key);
  this.props.history.push({
    pathname: pathname,
    search: searchParams.toString()
  });
};
function SomeComponent({ location }) {
  return <div>
    <button onClick={ () => addQuery('book', 'react')}>search react books</button>
    <button onClick={ () => removeQuery('book')}>remove search</button>
  </div>;
}

要了解更多关于URLSearchParams:

var paramsString = "q=URLUtils.searchParams&topic=api";
var searchParams = new URLSearchParams(paramsString);

//Iterate the search parameters.
for (let p of searchParams) {
  console.log(p);
}

searchParams.has("topic") === true; // true
searchParams.get("topic") === "api"; // true
searchParams.getAll("topic"); // ["api"]
searchParams.get("foo") === null; // true
searchParams.append("topic", "webdev");
searchParams.toString(); // "q=URLUtils.searchParams&topic=api&topic=webdev"
searchParams.set("topic", "More webdev");
searchParams.toString(); // "q=URLUtils.searchParams&topic=More+webdev"
searchParams.delete("topic");
searchParams.toString(); // "q=URLUtils.searchParams"

使用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 });

就像@Craques解释的那样,我们可以使用替换功能,而不是每次更改都推送一个新路由。然而,在react-router的第6版中,useHistory()被useNavigate()取代,它只返回一个函数。你可以将选项传递给函数,以达到与旧的location.replace()相同的效果:

import { useLocation, useNavigate } from 'react-router-dom';
const to = { pathname: location.pathname, search: newParams.toString() };
navigate(to, { replace: true });

我更喜欢你使用下面的ES6风格的函数:

getQueryStringParams = query => {
    return query
        ? (/^[?#]/.test(query) ? query.slice(1) : query)
            .split('&')
            .reduce((params, param) => {
                    let [key, value] = param.split('=');
                    params[key] = value ? decodeURIComponent(value.replace(/\+/g, ' ')) : '';
                    return params;
                }, {}
            )
        : {}
};