ChatGPT解决这个技术问题 Extra ChatGPT

使用 React 路由器以编程方式导航

使用 react-router,我可以使用 Link 元素创建由 react 路由器本地处理的链接。

我在内部看到它调用 this.context.transitionTo(...)

我想做一个导航。不是来自链接,而是来自下拉选择(例如)。我怎样才能在代码中做到这一点? this.context 是什么?

我看到了 Navigation mixin,但是没有 mixins 我可以这样做吗?

这是 react router v4 官方文档中教程的链接:reacttraining.com/react-router/web/guides/scroll-restoration
你可以检查这个答案stackoverflow.com/questions/44127739/…

T
TankorSmash

带有钩子的 React Router v5.1.0

如果您使用 React >16.8.0 和功能组件,React Router >5.1.0 中有一个新的 useHistory 钩子。

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

function HomeButton() {
  const history = useHistory();

  function handleClick() {
    history.push("/home");
  }

  return (
    <button type="button" onClick={handleClick}>
      Go home
    </button>
  );
}

反应路由器 v4

使用 React Router v4,您可以采用三种方法在组件内进行编程路由。

使用 withRouter 高阶组件。使用合成并渲染一个 使用上下文。

React Router 主要是对 history 库的封装。 history 使用浏览器的浏览器和哈希历史记录为您处理与浏览器的 window.history 的交互。它还提供了一个内存历史记录,这对于没有全局历史记录的环境很有用。这在移动应用程序开发 (react-native) 和使用 Node.js 的单元测试中特别有用。

history 实例有两种导航方法:pushreplace。如果您将 history 视为已访问位置的数组,则 push 将向数组中添加一个新位置,而 replace 将用新位置替换数组中的当前位置。通常,您在导航时会希望使用 push 方法。

在早期版本的 React Router 中,您必须创建自己的 history 实例,但在 v4 中,<BrowserRouter><HashRouter><MemoryRouter> 组件将为您创建浏览器、哈希和内存实例。 React Router 使与您的路由器关联的 history 实例的属性和方法可通过上下文在 router 对象下使用。

1.使用withRouter高阶组件

withRouter 高阶组件将注入 history 对象作为组件的 prop。这允许您访问 pushreplace 方法,而无需处理 context

import { withRouter } from 'react-router-dom'
// this also works with react-router-native

const Button = withRouter(({ history }) => (
  <button
    type='button'
    onClick={() => { history.push('/new-location') }}
  >
    Click Me!
  </button>
))

2. 使用合成并渲染一个

<Route> 组件不仅仅用于匹配位置。您可以渲染一条无路径路线,并且它将始终与当前位置匹配<Route> 组件传递与 withRouter 相同的属性,因此您将能够通过 history 属性访问 history 方法。

import { Route } from 'react-router-dom'

const Button = () => (
  <Route render={({ history}) => (
    <button
      type='button'
      onClick={() => { history.push('/new-location') }}
    >
      Click Me!
    </button>
  )} />
)

3. 使用上下文*

但你可能不应该

最后一个选项是只有在您对使用 React 的 context 模型感到满意时才应该使用的选项(React 的 Context API 从 v16 开始是稳定的)。

const Button = (props, context) => (
  <button
    type='button'
    onClick={() => {
      // context.history.push === history.push
      context.history.push('/new-location')
    }}
  >
    Click Me!
  </button>
)

// you need to specify the context type so that it
// is available within the component
Button.contextTypes = {
  history: React.PropTypes.shape({
    push: React.PropTypes.func.isRequired
  })
}

1 和 2 是实现起来最简单的选择,因此对于大多数用例来说,它们是您最好的选择。


我尝试以这种方式使用方法1 withRouter(( { history } ) => { console.log("hhhhhhhh"); history.push('/bets') });但它从未与路由器 4 一起使用
什么!?我可以只使用 withRouter 而不是将 history 传递给我的所有组件?? Gahh 我需要花更多时间阅读文档......
您如何在不将该行为附加到 Button 或其他 DOM 元素的情况下只运行 history.push('/new-location')
从 react 16 起,context 不再是实验性的。
更新:对于那些使用 eact-router-dom v6 的人应该使用 useNavigate() 而不是 useHistory()。有关更多详细信息,请参阅以下答案。 stackoverflow.com/a/66971821/12572265
D
Deepak

React-Router v6+ 答案

您可以使用新的 useNavigate 挂钩。 useNavigate 钩子返回一个可用于编程导航的函数。来自反应路由器 documentaion 的示例

import { useNavigate } from "react-router-dom";

function SignupForm() {
  let navigate = useNavigate();

  async function handleSubmit(event) {
    event.preventDefault();
    await submitForm(event.target);
    navigate("../success", { replace: true });
  }

  return <form onSubmit={handleSubmit}>{/* ... */}</form>;
}

React-Router 5.1.0+ 答案(使用钩子和 React >16.8)

您可以在功能组件上使用 useHistory 挂钩并以编程方式导航:

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

function HomeButton() {
  let history = useHistory();
  // use history.push('/some/path') here
};

React-Router 4.0.0+ 答案

在 4.0 及更高版本中,使用历史记录作为组件的道具。

class Example extends React.Component {
   // use `this.props.history.push('/some/path')` here
};

注意:如果 <Route> 未呈现您的组件,则 this.props.history 不存在。您应该使用 <Route path="..." component={YourComponent}/> 在 YourComponent 中拥有 this.props.history

React-Router 3.0.0+ 答案

在 3.0 及更高版本中,使用路由器作为组件的道具。

class Example extends React.Component {
   // use `this.props.router.push('/some/path')` here
};

React-Router 2.4.0+ 答案

在 2.4 及更高版本中,使用更高阶的组件来获取路由器作为组件的道具。

import { withRouter } from 'react-router';

class Example extends React.Component {
   // use `this.props.router.push('/some/path')` here
};

// Export the decorated class
var DecoratedExample = withRouter(Example);

// PropTypes
Example.propTypes = {
  router: React.PropTypes.shape({
    push: React.PropTypes.func.isRequired
  }).isRequired
};

React-Router 2.0.0+ 答案

此版本向后兼容 1.x,因此无需升级指南。仅仅通过示例就足够了。

也就是说,如果您想切换到新模式,路由器内部有一个 browserHistory 模块,您可以使用它访问

import { browserHistory } from 'react-router'

现在您可以访问浏览器历史记录,因此您可以执行推送、替换等操作……例如:

browserHistory.push('/some/path')

进一步阅读:HistoriesNavigation

React-Router 1.xx 答案

我不会详细介绍升级细节。您可以在 Upgrade Guide

这里关于问题的主要变化是从 Navigation mixin 到 History 的变化。现在它正在使用浏览器 historyAPI 来更改路由,所以从现在开始我们将使用 pushState()

下面是一个使用 Mixin 的例子:

var Example = React.createClass({
  mixins: [ History ],
  navigateToHelpPage () {
    this.history.pushState(null, `/help`);
  }
})

请注意,此 History 来自 rackt/history 项目。不是来自 React-Router 本身。

如果您出于某种原因不想使用 Mixin(可能是因为 ES6 类),那么您可以从 this.props.history 访问从路由器获得的历史记录。只有路由器渲染的组件才能访问它。因此,如果您想在任何子组件中使用它,则需要通过 props 作为属性向下传递。

您可以在他们的 1.0.x documentation 上阅读有关新版本的更多信息

这里是a help page specifically about navigating outside your component

它建议获取参考 history = createHistory() 并在其上调用 replaceState

React-Router 0.13.x 答案

我遇到了同样的问题,只能使用 react-router 附带的 Navigation mixin 找到解决方案。

我是这样做的

import React from 'react';
import {Navigation} from 'react-router';

let Authentication = React.createClass({
  mixins: [Navigation],

  handleClick(e) {
    e.preventDefault();

    this.transitionTo('/');
  },

  render(){
    return (<div onClick={this.handleClick}>Click me!</div>);
  }
});

我能够调用 transitionTo() 而无需访问 .context

或者你可以试试花哨的 ES6 class

import React from 'react';

export default class Authentication extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(e) {
    e.preventDefault();

    this.context.router.transitionTo('/');
  }

  render(){
    return (<div onClick={this.handleClick}>Click me!</div>);
  }
}

Authentication.contextTypes = {
  router: React.PropTypes.func.isRequired
};

React-Router-Redux 注意:如果你使用的是 Redux,还有另一个名为 React-Router-Redux 的项目为你提供了 ReactRouter 的 redux 绑定,使用的方法与 React-Redux 的做法有些相同

React-Router-Redux 有一些可用的方法允许从内部动作创建者进行简单的导航。这些对于在 React Native 中拥有现有架构的人特别有用,并且他们希望在 React Web 中以最小的样板开销使用相同的模式。

探索以下方法:

推(位置)

替换(位置)

去(数)

回去()

直走()

以下是使用 Redux-Thunk 的示例:

./actioncreators.js

import { goBack } from 'react-router-redux'

export const onBackPress = () => (dispatch) => dispatch(goBack())

./viewcomponent.js

<button
  disabled={submitting}
  className="cancel_button"
  onClick={(e) => {
    e.preventDefault()
    this.props.onBackPress()
  }}
>
  CANCEL
</button>

太感谢了。文档很难搜索,即使您知道要查找的内容,在 useNavigate 函数中使用 replace 的简单和有用的功能也很难找到。
我希望 useNavigate 是解决方案,但 6.2.1 版本似乎忽略了 { replace: true } 并且不刷新页面。
docs 不清楚包含第二个可选参数 replace: state 的目的或预期行为。
有没有不使用钩子的解决方案?
D
David Schumann

反应路由器 v2

对于最新版本 (v2.0.0-rc5),推荐的导航方法是直接推送到历史单例。您可以在 Navigating outside of Components doc 中看到这一点。

相关摘录:

import { browserHistory } from 'react-router';
browserHistory.push('/some/path');

如果使用较新的 react-router API,您需要在组件内部使用 this.props 中的 history,以便:

this.props.history.push('/some/path');

它还提供 pushState,但根据记录的警告已弃用。

如果使用 react-router-redux,它会提供一个 push 函数,您可以像这样调度:

import { push } from 'react-router-redux';
this.props.dispatch(push('/some/path'));

但是,这可能仅用于更改 URL,而不是实际导航到页面。


不要忘记较新的 API 不使用 import { browserHistory } from './react-router',而是使用 import createBrowserHistory from 'history/lib/createBrowserHistory' 创建历史记录。稍后,您可以从 components 属性访问 historythis.props.history('/some/path')
P
Peter Mortensen

React-Router 4.x 答案

就我而言,我喜欢拥有一个甚至可以在外部组件中携带的历史对象。我喜欢有一个单独的 history.js 文件,我可以按需导入,然后对其进行操作。

您只需将 BrowserRouter 更改为 Router,并指定 history 属性。这对您没有任何改变,只是您拥有自己的历史对象,您可以根据需要进行操作。

您需要安装 react-router 使用的库 history

示例用法,ES6 表示法:

历史.js

import createBrowserHistory from 'history/createBrowserHistory'
export default createBrowserHistory()

基本组件.js

import React, { Component } from 'react';
import history from './history';

class BasicComponent extends Component {

    goToIndex(e){
        e.preventDefault();
        history.push('/');
    }

    render(){
        return <a href="#" onClick={this.goToIndex}>Previous</a>;
    }
}

如果您必须从实际从 Route 组件呈现的组件导航,您还可以从 props 访问历史记录,如下所示:

基本组件.js

import React, { Component } from 'react';

class BasicComponent extends Component {

    navigate(e){
        e.preventDefault();
        this.props.history.push('/url');
    }

    render(){
        return <a href="#" onClick={this.navigate}>Previous</a>;
    }
}

D
David Schumann

以下是使用 react-router v2.0.0ES6 执行此操作的方法。 react-router 已远离 mixins。

import React from 'react';

export default class MyComponent extends React.Component {
  navigateToPage = () => {
    this.context.router.push('/my-route')
  };

  render() {
    return (
      <button onClick={this.navigateToPage}>Go!</button>
    );
  }
}

MyComponent.contextTypes = {
  router: React.PropTypes.object.isRequired
}

D
David Schumann

对于这个,谁不控制服务器端,因此使用哈希路由器 v2:

将您的 history 放入单独的文件(例如 app_history.js ES6):

import { useRouterHistory } from 'react-router'
import { createHashHistory } from 'history'
const appHistory = useRouterHistory(createHashHistory)({ queryKey: false });

export default appHistory;

并在任何地方使用它!

react-router (app.js ES6) 的入口点:

import React from 'react'
import { render } from 'react-dom'
import { Router, Route, Redirect } from 'react-router'
import appHistory from './app_history'
...
const render((
  <Router history={appHistory}>
  ...
  </Router>
), document.querySelector('[data-role="app"]'));

您在任何组件中的导航(ES6):

import appHistory from '../app_history'
...
ajaxLogin('/login', (err, data) => {
  if (err) {
    console.error(err); // login failed
  } else {
    // logged in
    appHistory.replace('/dashboard'); // or .push() if you don't need .replace()
  }
})

P
Peter Mortensen

反应路由器 v6

我有一段时间没有接触 React,但要感谢并强调 the comment below by Shimrit Snapir

在 React-Router 6.0 上 更改为

反应路由器 V4

tl:博士;

if (navigate) {
  return <Redirect to="/" push={true} />
}

简单而明确的答案是您需要将 <Redirect to={URL} push={boolean} />setState() 结合使用

push: boolean - 如果为 true,重定向会将新条目推送到历史记录中,而不是替换当前条目。

import { Redirect } from 'react-router'

class FooBar extends React.Component {
  state = {
    navigate: false
  }

  render() {
    const { navigate } = this.state

    // Here is the important part
    if (navigate) {
      return <Redirect to="/" push={true} />
    }
   // ^^^^^^^^^^^^^^^^^^^^^^^

    return (
      <div>
        <button onClick={() => this.setState({ navigate: true })}>
          Home
        </button>
      </div>
    )
  }
}

一个完整的例子是 here。阅读更多here

PS。该示例使用 ES7+ Property Initializers 来初始化状态。如果您有兴趣,也可以看看 here


C
Community

警告:此答案仅涵盖 1.0 之前的 ReactRouter 版本,之后我将使用 1.0.0-rc1 用例更新此答案!

你也可以在没有 mixins 的情况下做到这一点。

let Authentication = React.createClass({
  contextTypes: {
    router: React.PropTypes.func
  },
  handleClick(e) {
    e.preventDefault();
    this.context.router.transitionTo('/');
  },
  render(){
    return (<div onClick={this.handleClick}>Click me!</div>);
  }
});

上下文的问题是除非您在类上定义 contextTypes,否则它是不可访问的。

至于什么是上下文,它是一个对象,就像 props 一样,从 parent 传给 child,但它是隐式传递的,不需要每次都重新声明 props。请参阅https://www.tildedave.com/2014/11/15/introduction-to-contexts-in-react-js.html


P
Peter Mortensen

这是最简单和最干净的方法,大约是当前的 React-Router 3.0.0 和 ES6

带有 ES6 的 React-Router 3.xx:

import { withRouter } from 'react-router';

class Example extends React.Component {
   // use `this.props.router.push('/some/path')` here
};

// Export the decorated class
export default withRouter(Example);

或者,如果它不是您的默认类,则导出如下:

withRouter(Example);
export { Example };

请注意,在 3.xx 中,<Link> 组件本身正在使用 router.push,因此您可以传递任何传递 <Link to= 标记的内容,例如:

   this.props.router.push({pathname: '/some/path', query: {key1: 'val1', key2: 'val2'})'

D
David Schumann

要以编程方式进行导航,您需要将新的 history 推送到 component 中的 props.history,这样可以为您完成工作:

//using ES6
import React from 'react';

class App extends React.Component {

  constructor(props) {
    super(props)
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick(e) {
    e.preventDefault()
    /* Look at here, you can add it here */
    this.props.history.push('/redirected');
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>
          Redirect!!!
        </button>
      </div>
    )
  }
}

export default App;

C
Community

对于 ES6 + React 组件,以下解决方案对我有用。

我跟随 Felippe skinner,但添加了端到端的解决方案来帮助像我这样的初学者。

以下是我使用的版本:

“反应路由器”:“^2.7.0” “反应”:“^15.3.1”

下面是我使用 react-router 编程导航的反应组件:

import React from 'react';

class loginComp extends React.Component {
   constructor( context) {
    super(context);
    this.state = {
      uname: '',
      pwd: ''
    };
  }

  redirectToMainPage(){
        this.context.router.replace('/home');
  }

  render(){
    return <div>
           // skipping html code 
             <button onClick={this.redirectToMainPage.bind(this)}>Redirect</button>
    </div>;
  }
};

 loginComp.contextTypes = {
    router: React.PropTypes.object.isRequired
 }

 module.exports = loginComp;

下面是我的路由器的配置:

 import { Router, Route, IndexRedirect, browserHistory } from 'react-router'

 render(<Router history={browserHistory}>
          <Route path='/' component={ParentComp}>
            <IndexRedirect to = "/login"/>
            <Route path='/login' component={LoginComp}/>
            <Route path='/home' component={HomeComp}/>
            <Route path='/repair' component={RepairJobComp} />
            <Route path='/service' component={ServiceJobComp} />
          </Route>
        </Router>, document.getElementById('root'));

P
Peter Mortensen

这可能不是最好的方法,但是......使用 react-router v4,下面的 TypeScript 代码可以为一些人提供一个想法。

在下面呈现的组件中,例如 LoginPagerouter 对象是可访问的,只需调用 router.transitionTo('/homepage') 即可导航。

使用导航代码 from

"react-router": "^4.0.0-2", "react": "^15.3.1",

从 'react-router/BrowserRouter' 导入路由器;从'react-history/BrowserHistory'导入{历史};从“历史/createBrowserHistory”导入 createHistory;常量历史 = createHistory(); interface MatchWithPropsInterface { component: typeof React.Component, router: Router, history: History, 究竟是什么?: any, pattern: string } class MatchWithProps extends React.Component { render() { return( ( React.createElement(this.props.component, this.props) )} /> ) } } ReactDOM.render( {({ router }) => (

)} , 文档.getElementById('app') );


s
saiful619945

在 React Router v4 中,我遵循这两种方式以编程方式进行路由。

this.props.history.push("/something/something") this.props.history.replace("/something/something")

第二

替换历史堆栈上的当前条目

要获取 props 中的历史记录,您可能必须使用

带路由器

在 React 路由器 v6 中

import { useNavigate } from "react-router-dom";

function Invoices() {
  let navigate = useNavigate();
  return (
    <div>
      <NewInvoiceForm
        onSubmit={async event => {
          let newInvoice = await createInvoice(event.target);
          navigate(`/invoices/${newInvoice.id}`);
        }}
      />
    </div>
  );
}

Getting Started with React Router v6


H
Hossein

在 React-Router v4 和 ES6 中

您可以使用 withRouterthis.props.history.push

import {withRouter} from 'react-router-dom';

class Home extends Component {

    componentDidMount() {
        this.props.history.push('/redirect-to');
    }
}

export default withRouter(Home);

J
Janos

要将 withRouter 与基于类的组件一起使用,请尝试以下类似操作。不要忘记将导出语句更改为使用 withRouter

import { withRouter } from 'react-router-dom'

class YourClass extends React.Component {
  yourFunction = () => {
    doSomeAsyncAction(() =>
      this.props.history.push('/other_location')
    )
  }

  render() {
    return (
      <div>
        <Form onSubmit={ this.yourFunction } />
      </div>
    )
  }
}

export default withRouter(YourClass);

P
Peter Mortensen

随着 React-Router v4 的出现,现在有一种新的方法可以做到这一点。

import { MemoryRouter, BrowserRouter } from 'react-router';

const navigator = global && global.navigator && global.navigator.userAgent;
const hasWindow = typeof window !== 'undefined';
const isBrowser = typeof navigator !== 'undefined' && navigator.indexOf('Node.js') === -1;
const Router = isBrowser ? BrowserRouter : MemoryRouter;

<Router location="/page-to-go-to"/>

react-lego 是一个显示 how to use/update react-router 的示例应用程序,它包含导航应用程序的示例功能测试。


这对于从渲染函数导航非常有用,尽管我想知道如何从生命周期钩子或 redux 之类的东西导航?
P
Peter Mortensen

基于之前的 answers from José Antonio Postigo and Ben Wheeler

新奇之处?用 TypeScript 编写并使用装饰器或静态属性/字段

import * as React from "react";
import Component = React.Component;
import { withRouter } from "react-router";

export interface INavigatorProps {
    router?: ReactRouter.History.History;
}

/**
 * Note: goes great with mobx
 * @inject("something") @withRouter @observer
 */
@withRouter
export class Navigator extends Component<INavigatorProps, {}>{
    navigate: (to: string) => void;
    constructor(props: INavigatorProps) {
        super(props);
        let self = this;
        this.navigate = (to) => self.props.router.push(to);
    }
    render() {
        return (
            <ul>
                <li onClick={() => this.navigate("/home")}>
                    Home
                </li>
                <li onClick={() => this.navigate("/about")}>
                    About
                </li>
            </ul>
        )
    }
}

/**
 * Non decorated
 */
export class Navigator2 extends Component<INavigatorProps, {}> {

    static contextTypes = {
        router: React.PropTypes.object.isRequired,
    };

    navigate: (to: string) => void;
    constructor(props: INavigatorProps, context: any) {
        super(props, context);
        let s = this;
        this.navigate = (to) =>
            s.context.router.push(to);
    }
    render() {
        return (
            <ul>
                <li onClick={() => this.navigate("/home")}>
                    Home
                </li>
                <li onClick={() => this.navigate("/about")}>
                    About
                </li>
            </ul>
        )
    }
}

今天安装了任何 npm。

“反应路由器”:“^3.0.0”和“@types/反应路由器”:“^2.0.41”


z
zilijonas

对于那些已经在使用 React Router v6 的人,这可以使用 react-router 提供的 useNavigate 钩子来完成。

使用这个钩子导航非常简单:

import { generatePath, useNavigate } from 'react-router';

navigate(-1); // navigates back
navigate('/my/path'); // navigates to a specific path
navigate(generatePath('my/path/:id', { id: 1 })); // navigates to a dynamic path, generatePath is very useful for url replacements

D
David Schumann

对于当前的 React 版本 (15.3),this.props.history.push('/location'); 对我有用,但它显示以下警告:

browser.js:49 警告:[react-router] props.history 和 context.history 已被弃用。请使用 context.router。

我使用 context.router 解决了这个问题:

import React from 'react';

class MyComponent extends React.Component {

    constructor(props) {
        super(props);
        this.backPressed = this.backPressed.bind(this);
    }

    backPressed() {
        this.context.router.push('/back-location');
    }

    ...
}

MyComponent.contextTypes = {
    router: React.PropTypes.object.isRequired
};

export default MyComponent;

Z
Zaman Afzal

如果您使用的是哈希或浏览器历史记录,那么您可以这样做

hashHistory.push('/login');
browserHistory.push('/login');

P
Peter Mortensen

带有钩子的 React Router v6

import {useNavigate} from 'react-router-dom';
let navigate = useNavigate();
navigate('home');

并浏览浏览器历史记录,

navigate(-1); ---> Go back
navigate(1);  ---> Go forward
navigate(-2); ---> Move two steps backward.

P
Peter Mortensen

反应路由器 V4

如果您使用的是版本 4,那么您可以使用我的库(无耻插件),您只需在其中发送一个动作,一切正常!

dispatch(navigateTo("/aboutUs"));

trippler


P
Peter Mortensen

那些在 React Router v4 中实现这一点时遇到问题的人。

这是从 redux 操作浏览 React 应用程序的有效解决方案。

文件 history.js

import createHistory from 'history/createBrowserHistory'

export default createHistory()

文件 App.js/Route.jsx

import { Router, Route } from 'react-router-dom'
import history from './history'
...
<Router history={history}>
 <Route path="/test" component={Test}/>
</Router>

文件 *another_file.js 或 redux 文件

import history from './history'

history.push('/test') // This should change the URL and rerender Test component

感谢 GitHub 上的这条评论:ReactTraining issues comment


P
Peter Mortensen

您还可以在无状态组件中使用 useHistory 挂钩。文档中的示例:

import { useHistory } from "react-router"

function HomeButton() {
  const history = useHistory()

  return (
    <button type="button" onClick={() => history.push("/home")}>
      Go home
    </button>
  )
}

注意:在 react-router@5.1.0 中添加了钩子,需要 react@>=16.8


好电话,你能注意哪个版本的 react-router 和 react 指的是哪个版本?这是一个并不总是可用的新变化
H
Hassan Saeed

对于最新的 react-router-dom v6

useHistory() 替换为 useNavigate()

你需要使用:

import { useNavigate } from 'react-router-dom';
const navigate = useNavigate();
navigate('/your-page-link');

P
Peter Mortensen

以编程方式在基于类的组件中导航。

import { Redirect } from "react-router-dom";

class MyComponent extends React.Component{
    state = {rpath: null}

    const goTo = (path) => this.setState({rpath: path});

    render(){
        if(this.state.rpath){
            return <Redirect to={this.state.rpath}/>
        }
        .....
        .....
    }
}

D
David Schumann

在撰写本文时,正确答案对我来说是

this.context.router.history.push('/');

但是您需要将 PropTypes 添加到您的组件中

Header.contextTypes = {
  router: PropTypes.object.isRequired
}
export default Header;

不要忘记导入 PropTypes

import PropTypes from 'prop-types';

P
Peter Mortensen

在我的回答中,有三种不同的方式可以以编程方式重定向到路由。一些解决方案已经介绍过,但以下解决方案仅针对具有附加演示应用程序的功能组件。

使用以下版本:

反应:16.13.1 反应域:16.13.1 反应路由器:5.2.0 反应路由器域:5.2.0 打字稿:3.7.2

配置:

所以首先解决方案是使用HashRouter,配置如下:

<HashRouter>
    // ... buttons for redirect

    <Switch>
      <Route exact path="/(|home)" children={Home} />
      <Route exact path="/usehistory" children={UseHistoryResult} />
      <Route exact path="/withrouter" children={WithRouterResult} />
      <Route exact path="/redirectpush" children={RedirectPushResult} />
      <Route children={Home} />
    </Switch>
</HashRouter>

the documentation<HashRouter>

使用 URL 的散列部分(即 window.location.hash)来使您的 UI 与 URL 保持同步。

解决方案:

使用 使用 useState 推送:

在功能组件(我的存储库中的 RedirectPushAction 组件)中使用时,我们可以使用 useState 来处理重定向。棘手的部分是一旦发生重定向,我们需要将 redirect 状态设置回 false。通过使用 setTimeOut0 延迟,我们等待 React 将 Redirect 提交到 DOM,然后取回按钮以便下次使用它。

请在下面找到我的示例:

const [redirect, setRedirect] = useState(false);
const handleRedirect = useCallback(() => {
    let render = null;
    if (redirect) {
        render = <Redirect to="/redirectpush" push={true} />

        // In order wait until committing to the DOM
        // and get back the button for clicking next time
        setTimeout(() => setRedirect(false), 0);
    }
    return render;
}, [redirect]);

return <>
    {handleRedirect()}
    <button onClick={() => setRedirect(true)}>
        Redirect push
    </button>
</>

来自 <Redirect> 文档:

渲染 将导航到新位置。新位置将覆盖历史堆栈中的当前位置,就像服务器端重定向 (HTTP 3xx) 一样。

使用 useHistory 钩子:

在我的解决方案中有一个名为 UseHistoryAction 的组件,它代表以下内容:

let history = useHistory();

return <button onClick={() => { history.push('/usehistory') }}>
    useHistory redirect
</button>

useHistory 钩子让我们可以访问历史对象,这有助于我们以编程方式导航或更改路线。

使用 withRouter,从 props 中获取历史记录:

创建了一个名为 WithRouterAction 的组件,显示如下:

const WithRouterAction = (props:any) => {
    const { history } = props;

    return <button onClick={() => { history.push('/withrouter') }}>
        withRouter redirect
    </button>
}

export default withRouter(WithRouterAction);

withRouter 文档中读取:

您可以通过 withRouter 高阶组件访问历史对象的属性和最近的 匹配项。 withRouter 将在渲染时将更新的匹配、位置和历史道具传递给包装的组件。

演示:

为了更好地表示我已经用这些示例构建了一个 GitHub 存储库,请在下面找到它:

React Router Programmatically Redirect Examples


P
Peter Mortensen

也许不是最好的解决方案,但它可以完成工作:

import { Link } from 'react-router-dom';

// Create functional component Post
export default Post = () => (
    <div className="component post">

        <button className="button delete-post" onClick={() => {
            // ... delete post
            // then redirect, without page reload, by triggering a hidden Link
            document.querySelector('.trigger.go-home').click();
        }}>Delete Post</button>

        <Link to="/" className="trigger go-home hidden"></Link>

    </div>
);

基本上,与一个动作相关的逻辑(在这种情况下是删除后)最终会调用重定向触发器。这并不理想,因为您将在标记中添加一个 DOM 节点“触发器”,以便在需要时方便地调用它。此外,您将直接与 DOM 交互,这在 React 组件中可能是不希望的。

尽管如此,这种类型的重定向并不经常需要。因此,组件标记中的一两个额外的隐藏链接不会造成太大伤害,尤其是如果您给它们起有意义的名称。


P
Peter Mortensen

如果您碰巧通过 react-router-redux 将 RR4 与 redux 配对,那么使用来自 react-router-redux 的路由操作创建器也是一种选择。

import { push, replace, ... } from 'react-router-redux'

class WrappedComponent extends React.Component {
  handleRedirect(url, replaceState = true) {
    replaceState
      ? this.props.dispatch(replace(url))
      : this.props.dispatch(push(url))
  }
  render() { ... }
}

export default connect(null)(WrappedComponent)

如果您使用 redux thunk/saga 来管理异步流,则在 redux 操作中导入上述操作创建者并使用 mapDispatchToProps 挂钩到 React 组件可能会更好。