【问题标题】:How to preserve query parameters in react-router v4如何在 react-router v4 中保留查询参数
【发布时间】:2017-09-22 14:43:42
【问题描述】:

用户在登录后重定向到我的应用程序(java 上的服务器),他们有 url,看起来像这样 http://10.8.0.29:8083/html/?locale=RU&token=1c5c71f2-dcda-4a51-8cf6-f8f6ff1031d0&returnTo=http://10.8.0.23:8080/

(带有一些参数,html - 是源所在的文件夹)。在我的应用程序上导航时,我需要保留此参数。到目前为止,除了这个 How to redirect with react-router while preserving initial query parameters? 老问题,我还没有找到任何简单的解决方案,所以我希望再次提出这个问题。提前致谢。

【问题讨论】:

  • 您必须自己提取这些参数并将它们放入您的存储中(redux 或 flex)。
  • 我知道如何提取(window.location.search),我可以将其保存在商店中,但是如何在导航所有路线时将其放回?
  • 只是正常的调度/减速周期。
  • 然后呢?请澄清一下。

标签: javascript reactjs react-router react-router-v4


【解决方案1】:

我已经在对您问题的评论中分享了 my solution for react-router v3。

下面是我的 react-router v4 解决方案。

使用以下createPreserveQueryHistory 函数覆盖history.pushhistory.replace 方法,以便它们保留指定的查询参数:

import queryString from 'query-string';
import {createBrowserHistory} from 'history'

function preserveQueryParameters(history, preserve, location) {
    const currentQuery = queryString.parse(history.location.search);
    if (currentQuery) {
        const preservedQuery = {};
        for (let p of preserve) {
            const v = currentQuery[p];
            if (v) {
                preservedQuery[p] = v;
            }
        }
        if (location.search) {
            Object.assign(preservedQuery, queryString.parse(location.search));
        }
        location.search = queryString.stringify(preservedQuery);
    }
    return location;
}

function createLocationDescriptorObject(location, state) {
    return typeof location === 'string' ? { pathname: location, state } : location;
}

function createPreserveQueryHistory(createHistory, queryParameters) {
    return (options) => {
        const history = createHistory(options);
        const oldPush = history.push, oldReplace = history.replace;
        history.push = (path, state) => oldPush.apply(history, [preserveQueryParameters(history, queryParameters, createLocationDescriptorObject(path, state))]);
        history.replace = (path, state) => oldReplace.apply(history, [preserveQueryParameters(history, queryParameters, createLocationDescriptorObject(path, state))]);
        return history;
    };
}

const history = createPreserveQueryHistory(createBrowserHistory, ['locale', 'token', 'returnTo'])();

然后在你的路由器定义中使用它:

<Router history={history}>
    ...
</Router>

对于那些使用 TypeScript 的人

import {History, LocationDescriptor, LocationDescriptorObject} from 'history'
import queryString from 'query-string'
import LocationState = History.LocationState

type CreateHistory<O, H> = (options?: O) => History & H

function preserveQueryParameters(history: History, preserve: string[], location: LocationDescriptorObject): LocationDescriptorObject {
    const currentQuery = queryString.parse(history.location.search)
    if (currentQuery) {
        const preservedQuery: { [key: string]: unknown } = {}
        for (let p of preserve) {
            const v = currentQuery[p]
            if (v) {
                preservedQuery[p] = v
            }
        }
        if (location.search) {
            Object.assign(preservedQuery, queryString.parse(location.search))
        }
        location.search = queryString.stringify(preservedQuery)
    }
    return location
}

function createLocationDescriptorObject(location: LocationDescriptor, state?: LocationState): LocationDescriptorObject {
    return typeof location === 'string' ? {pathname: location, state} : location
}

export function createPreserveQueryHistory<O, H>(createHistory: CreateHistory<O, H>,
                                                 queryParameters: string[]): CreateHistory<O, H> {
    return (options?: O) => {
        const history = createHistory(options)
        const oldPush = history.push, oldReplace = history.replace
        history.push = (path: LocationDescriptor, state?: LocationState) =>
            oldPush.apply(history, [preserveQueryParameters(history, queryParameters, createLocationDescriptorObject(path, state))])
        history.replace = (path: LocationDescriptor, state?: LocationState) =>
            oldReplace.apply(history, [preserveQueryParameters(history, queryParameters, createLocationDescriptorObject(path, state))])
        return history
    }
}

【讨论】:

  • createLocationDescriptorObject 对我不起作用。我需要用{ ...parsePath(location), state } 替换{pathname: location, state} 部分,其中parsePath 是从历史中导入的。
  • @GennadyDogaev,请在上面重新评论,什么不起作用?我使用了{pathname: location, state},它似乎可以工作,但测试有限。我可能错过了什么?
  • 缺少搜索和哈希?
  • @innek 这是很久以前的事了,所以我不记得它不起作用的确切原因
【解决方案2】:

在 React-Router 4.3 中(不确定早期版本),如果您在上面有一个 &lt;Route&gt;,那么这样的东西应该可以工作:(这是在 Typescript 中)

Route({ path: ..., render: (props) => function() {
  Redirect({ ...,
      to: { pathname: ... search: props.location.search, ... }})
});

说明:你使用&lt;Route&gt;标签的render: (props) =&gt; ....属性,而不是component: ...,因为render给你props,所以在&lt;Redirect&gt;里面你可以使用props.location.search和这种方式访问​​当前的查询参数,并在重定向中重用。

如果上面没有&lt;Route&gt;,也许你不能。我只是在这里问:How preserve query string and hash fragment, in React-Router 4 <Switch><Redirect>?

【讨论】:

  • 这种重定向方法似乎不适用于以下场景。比如说,用户登陆了 mysite.com/home?devmode=true,并且站点导航栏上有一个菜单项,其中包含指向“mysite.com/projects”的链接。当我单击“mysite.com/projects”时,我想阻止查询参数devmode=true。像这样重定向会导致无限循环` `
  • @innek 这是您认为可能发生的事情还是实际发生的事情?我认为to: ... 仅适用于 paths? (不完全记得。)如果您动态构建Route({ ... Redirect({... 列表并排除重定向,如果您已经在mysite.com/projects?devmode=true 呢?
【解决方案3】:

我在这个项目中关闭了哈希路由器,它保留了路由中的所有参数。

【讨论】:

    【解决方案4】:

    它可以与 react-router 的 useLocation 挂钩正常工作,试试下面

    import { Link, useLocation } from 'react-router-dom';
        
    function CustomPage() {
    
          const { search } = useLocation();
        
          return (
            <>
              <p>Preserve the query params?</p>
              <Link to={`/your-next-location${search}`}>Next link</Link>
            </>
          );
     }
    

    或者通过push方法进行路由导航

     import { useHistory, useLocation } from 'react-router-dom';
     /*...
       .
       .
     ...*/
     const history = useHistory();
     const { search } = useLocation();
     /*...
       .
       .
     ...*/
     history.push({pathname:`/your-next-location${search}`});
    

    【讨论】:

      【解决方案5】:

      如果您需要指向 #anchor 的链接,一个选择是使用此库 https://github.com/rafrex/react-router-hash-link 并执行以下操作:

      import { NavHashLink } from 'react-router-hash-link';
      
      ...
      <NavHashLink elementId='targetID' to='' smooth >
    
          my text
      </NavHashLink>
      ...
      

      这也适用于 React-Router v5。

      【讨论】:

        猜你喜欢
        • 2018-10-05
        • 2016-06-20
        • 2017-08-30
        • 1970-01-01
        • 2019-08-07
        • 2017-01-31
        • 2019-03-20
        • 2017-10-23
        • 2018-04-10
        相关资源
        最近更新 更多