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

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

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


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

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

or

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

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


DimitriDushkin在GitHub上写道:

import { browserHistory } from 'react-router';

/**
 * @param {Object} query
 */
export const addQuery = (query) => {
  const location = Object.assign({}, browserHistory.getCurrentLocation());

  Object.assign(location.query, query);
  // or simple replace location.query if you want to completely change params

  browserHistory.push(location);
};

/**
 * @param {...String} queryNames
 */
export const removeQuery = (...queryNames) => {
  const location = Object.assign({}, browserHistory.getCurrentLocation());
  queryNames.forEach(q => delete location.query[q]);
  browserHistory.push(location);
};

or

import { withRouter } from 'react-router';
import { addQuery, removeQuery } from '../../utils/utils-router';

function SomeComponent({ location }) {
  return <div style={{ backgroundColor: location.query.paintRed ? '#f00' : '#fff' }}>
    <button onClick={ () => addQuery({ paintRed: 1 })}>Paint red</button>
    <button onClick={ () => removeQuery('paintRed')}>Paint white</button>
  </div>;
}

export default withRouter(SomeComponent);

使用react-router v4、redux-thunk和react-router-redux(5.0.0-alpha.6)包的示例。

当用户使用搜索功能时,我希望他能够为相同的查询发送url链接给同事。

import { push } from 'react-router-redux';
import qs from 'query-string';

export const search = () => (dispatch) => {
    const query = { firstName: 'John', lastName: 'Doe' };

    //API call to retrieve records
    //...

    const searchString = qs.stringify(query);

    dispatch(push({
        search: searchString
    }))
}

当你需要一个模块来轻松地解析你的查询字符串时,推荐使用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推送。


我更喜欢你使用下面的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;
                }, {}
            )
        : {}
};

约翰的答案是正确的。当我处理参数时,我还需要URLSearchParams接口:

this.props.history.push({
    pathname: '/client',
    search: "?" + new URLSearchParams({clientId: clientId}).toString()
})

你可能还需要用一个withRouter HOC来包装你的组件。export default with throuter (YourComponent);


对于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"

也可以这样写

this.props.history.push(`${window.location.pathname}&page=${pageNumber}`)

在我的例子中,输入输入字段输出到浏览器的url作为查询字符串,使用React JS功能组件如下所示


import React, { useEffect, useState } from 'react'
import { useHistory } from 'react-router-dom'

const Search = () => {
  const [query, setQuery] = useState('')
  const history = useHistory()

  const onChange = (e) => {
    setQuery(e.target.value)
  }

  useEffect(() => {
    const params = new URLSearchParams()
    if (query) {
      params.append('name', query)
    } else {
      params.delete('name')
    }
    history.push({ search: params.toString() })
  }, [query, history])

  return <input type="text" value={query} onChange={onChange} />
}

export default Search


浏览器URL查询

/搜索吗?name = query_here


您可以使用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} />
}

你可以使用钩子useHistory 确保你使用的是基于函数的组件 在顶部导入这个

import {useHistory} from "react-router-dom"

在你的组件中,

const history = useHistory()
history.push({
    pathname: window.location.pathname,
    search: '?color=blue'
})

就像@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 });

我目前在一个正在运行的项目中使用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];
};


我做了一个简单的钩子来减轻工作。

让我们想象一下你的url是这样的: /搜索吗?起源=主页= 1

function useUrl(param: string) {

    const history = useHistory()
    const { search, pathname } = useLocation()
    const url = new URLSearchParams(search)

    const urlParam = url.get(param)
    const [value, setValue] = useState(urlParam !== null ? urlParam : '')

    function _setValue(val: string){
        url.set(param, val)
        history.replace({ pathname, search: url.toString() }); 
        setValue(val)
    }

    return [value, _setValue]
}

那么实际使用情况:

function SearchPage() {

    const [origin] = useUrl("origin")
    const [page, setPage] = useUrl("page")

    return (
        <div>
            <p>Return to: {origin}</p>
            <p>Current Page: {page}</p>
        </div>
    )
}

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 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只是一个可选的方便助手。


// react-router-dom v6

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

// useSearchParams hook
const [searchParams, setSearchParams] = useSearchParams();

// usage
const params: URLSearchParams = new URLSearchParams();
params.id = '123';
params.color = 'white';

// set new parameters
setSearchParams(params);

! !当心!!这将只更新当前页面上的查询参数,但您将无法导航回(浏览器返回btn)到以前的路由,因为此选项不会更改历史记录。要使此行为到位,请检查之前的答案:https://stackoverflow.com/users/6160270/rakesh-sharma的答案