如何使用 react-router 重定向到另一条路由?

Posted

技术标签:

【中文标题】如何使用 react-router 重定向到另一条路由?【英文标题】:How to do a redirect to another route with react-router? 【发布时间】:2016-04-16 14:11:06 【问题描述】:

我正在尝试使用 react-router(version ^1.0.3)做一个简单的重定向到另一个视图,我只是累了。

import React from 'react';
import Router, Route, Link, RouteHandler from 'react-router';


class HomeSection extends React.Component 

  static contextTypes = 
    router: PropTypes.func.isRequired
  ;

  constructor(props, context) 
    super(props, context);
  

  handleClick = () => 
    console.log('HERE!', this.contextTypes);
    // this.context.location.transitionTo('login');
  ;

  render() 
    return (
      <Grid>
        <Row className="text-center">          
          <Col md=12 xs=12>
            <div className="input-group">
              <span className="input-group-btn">
                <button onClick=this.handleClick type="button">
                </button>
              </span>
            </div>
          </Col>
        </Row>
      </Grid>
    );
  
;

HomeSection.contextTypes = 
  location() 
    React.PropTypes.func.isRequired
  


export default HomeSection;

我只需要将使用发送到“/login”就可以了。

我能做什么?

控制台错误:

Uncaught ReferenceError: PropTypes is not defined

包含我的路线的文件

// LIBRARY
/*eslint-disable no-unused-vars*/
import React from 'react';
/*eslint-enable no-unused-vars*/
import Route, IndexRoute from 'react-router';

// COMPONENT
import Application from './components/App/App';
import Contact from './components/ContactSection/Contact';
import HomeSection from './components/HomeSection/HomeSection';
import NotFoundSection from './components/NotFoundSection/NotFoundSection';
import TodoSection from './components/TodoSection/TodoSection';
import LoginForm from './components/LoginForm/LoginForm';
import SignupForm from './components/SignupForm/SignupForm';

export default (
    <Route component=Application path='/'>
      <IndexRoute component=HomeSection />
      <Route component=HomeSection path='home' />
      <Route component=TodoSection path='todo' />
      <Route component=Contact path='contact' />
      <Route component=LoginForm path='login' />
      <Route component=SignupForm path='signup' />
      <Route component=NotFoundSection path='*' />
    </Route>
);

【问题讨论】:

嗨!您能否发布您的routes 定义,以及是否有理由不使用Link 组件?另外,请提及您遇到的错误。 而不是按钮,&lt;Link to="/login"&gt;Log In&lt;/Link&gt;? 另外你使用的是什么版本的 react-router?程序重定向的代码在主要版本之间发生了变化。 对于Uncaught ReferenceError,你调用的是PropTypes,但你不导入它,你需要导入PropTypes本身或使用React.PropTypes @JoshDavidMiller 好点,但我不会感到惊讶 react-router api 在 5 分钟内更改.. 哈哈开玩笑,但只是部分 【参考方案1】:

1) react-router > V5 useHistory hook:

如果您有React &gt;= 16.8 和功能组件,您可以使用useHistory hook from react-router。

import React from 'react';
import  useHistory  from 'react-router-dom';

const YourComponent = () => 
    const history = useHistory();

    const handleClick = () => 
        history.push("/path/to/push");
    

    return (
        <div>
            <button onClick=handleClick type="button" />
        </div>
    );


export default YourComponent;

2) 反应路由器 > V4 withRouter HOC:

正如 @ambar 在 cmets 中提到的,React-router 自 V4.0 以来已经改变了他们的代码库。这是文档 - official, withRouter

import React,  Component  from 'react';
import  withRouter  from "react-router-dom";

class YourComponent extends Component 
    handleClick = () => 
        this.props.history.push("path/to/push");
    

    render() 
        return (
            <div>
                <button onClick=this.handleClick type="button">
            </div>
        );
    ;


export default withRouter(YourComponent);

3) React-router browserHistory

您可以使用 react-router BrowserHistory 实现此功能。代码如下:

import React,  Component  from 'react';
import  browserHistory  from 'react-router';

export default class YourComponent extends Component 
    handleClick = () => 
        browserHistory.push('/login');
    ;

    render() 
        return (
            <div>
                <button onClick=this.handleClick type="button">
            </div>
        );
    ;

4) Redux connected-react-router

如果你已经用 redux 连接了你的组件,并且已经配置了 connected-react-router 你所要做的就是 this.props.history.push("/new/url"); 即,您不需要withRouter HOC 将history 注入到组件道具中。

// reducers.js
import  combineReducers  from 'redux';
import  connectRouter  from 'connected-react-router';

export default (history) => combineReducers(
    router: connectRouter(history),
    ... // rest of your reducers
);


// configureStore.js
import  createBrowserHistory  from 'history';
import  applyMiddleware, compose, createStore  from 'redux';
import  routerMiddleware  from 'connected-react-router';
import createRootReducer from './reducers';
...
export const history = createBrowserHistory();

export default function configureStore(preloadedState) 
    const store = createStore(
        createRootReducer(history), // root reducer with router state
        preloadedState,
        compose(
            applyMiddleware(
                routerMiddleware(history), // for dispatching history actions
                // ... other middlewares ...
            ),
        ),
    );

    return store;



// set up other redux requirements like for eg. in index.js
import  Provider  from 'react-redux';
import  Route, Switch  from 'react-router';
import  ConnectedRouter  from 'connected-react-router';
import configureStore,  history  from './configureStore';
...
const store = configureStore(/* provide initial state if any */)

ReactDOM.render(
    <Provider store=store>
        <ConnectedRouter history=history>
            <>  /* your usual react-router v4/v5 routing */ 
                <Switch>
                    <Route exact path="/yourPath" component=YourComponent />
                </Switch>
            </>
        </ConnectedRouter>
    </Provider>,
    document.getElementById('root')
);


// YourComponent.js
import React,  Component  from 'react';
import  connect  from 'react-redux';
...

class YourComponent extends Component 
    handleClick = () => 
        this.props.history.push("path/to/push");
    

    render() 
        return (
          <div>
            <button onClick=this.handleClick type="button">
          </div>
        );
      
    ;



export default connect(mapStateToProps = , mapDispatchToProps = )(YourComponent);

【讨论】:

似乎 'browserHistory' 不再是 react-router 的一部分了。 BrowserRouter没有推送功能 @ambar @johnnyodonnell react-router-dom 确实 这是最好的答案。您应该将此标记为正确的。 对于 useHistory --> 是否需要先在某处指定路径? DOM 应该如何知道要针对哪个路由渲染哪个组件?【参考方案2】:

对于简单的答案,您可以使用来自react-routerLink 组件,而不是button。有一些方法可以改变 JS 中的路线,但似乎你在这里不需要。

<span className="input-group-btn">
  <Link to="/login" />Click to login</Link>
</span>

要在 1.0.x 中以编程方式执行此操作,您可以在 clickHandler 函数中这样做:

this.history.pushState(null, 'login');

取自升级文档here

您应该将this.historyreact-router 放置在您的路由处理程序组件上。如果它是routes 定义中提到的子组件,您可能需要进一步传递它

【讨论】:

这是一个很酷的解决方案,但我不使用它的原因是因为我需要先做一种验证,所以我需要把它放在一个函数中,比如:@987654330 @ 所以这就是为什么我把它放在一个 onClick 函数中 你也可以在 JSX 中这样做:validation &amp;&amp; &lt;Link to="/login" /&gt;Click to login&lt;/Link&gt;。如果验证为假,则不会呈现任何内容。 我知道你的意思,但我需要按钮在那里,如果验证为真,则重定向,否则会出现错误消息。 @TheUnnamed 我更新了答案以展示如何在 JS 中做到这一点 >Uncaught TypeError: Cannot read property 'pushState' of undefined【参考方案3】:

如何使用 react-router 重定向到另一个路由?

例如,当用户点击链接 &lt;Link to="/" /&gt;Click to route&lt;/Link&gt; 时,react-router 将寻找 /,您可以使用 Redirect to 并将用户发送到其他地方,例如登录路由。

从docs 到ReactRouterTraining:

渲染&lt;Redirect&gt; 将导航到新位置。新的 location 将覆盖历史堆栈中的当前位置,例如 服务器端重定向 (HTTP 3xx) 可以。

import  Route, Redirect  from 'react-router'

<Route exact path="/" render=() => (
  loggedIn ? (
    <Redirect to="/dashboard"/>
  ) : (
    <PublicHomePage/>
  )
)/>

to: 字符串,要重定向到的 URL。

<Redirect to="/somewhere/else"/>

to:对象,要重定向到的位置。

<Redirect to=
  pathname: '/login',
  search: '?utm=your+face',
  state:  referrer: currentLocation 
/>

【讨论】:

提供的解决方案抛出错误&lt;Redirect&gt; elements are for router configuration only and should not be rendered【参考方案4】:

最简单的网络解决方案!

2020 年最新版本 确认与:

"react-router-dom": "^5.1.2"
"react": "^16.10.2"

使用useHistory() 钩子!

import React from 'react';
import  useHistory  from "react-router-dom";


export function HomeSection() 
  const history = useHistory();
  const goLogin = () => history.push('login');

  return (
    <Grid>
      <Row className="text-center">          
        <Col md=12 xs=12>
          <div className="input-group">
            <span className="input-group-btn">
              <button onClick=goLogin type="button" />
            </span>
          </div>
        </Col>
      </Row>
    </Grid>
  );

【讨论】:

太棒了,正在寻找钩子的方法来做到这一点!即使我的 IDE 显示“无法解析符号 ...”警告,它确实有效! 太棒了,这就是我一直在寻找的,它在这里工作【参考方案5】:

我知道这是一个老问题,但对于 2021 年及之后的 React Router V6 来到这里的人来说,useHistory 不再从 react-router-dom 导出,您必须改为导入 useNavigate。示例代码如下:

import  useNavigate  from "react-router-dom"

在你的反应类或功能组件中:

const navigate = useNavigate()
navigate("/404")

【讨论】:

【参考方案6】:

使用 react-router v2.8.1(可能还有其他 2.x.x 版本,但我还没有测试过),您可以使用此实现进行路由器重定向。

import  Router  from 'react-router';

export default class Foo extends Component 

  static get contextTypes() 
    return 
      router: React.PropTypes.object.isRequired,
    ;
  

  handleClick() 
    this.context.router.push('/some-path');
  

【讨论】:

有时:this.context.router.history.push('/some-path');【参考方案7】:

最简单的解决方案是:

import  Redirect  from 'react-router';

<Redirect to='/componentURL' />

【讨论】:

但我收到一个错误:不变式失败:您不应该在 之外使用 你尝试换行了吗?

以上是关于如何使用 react-router 重定向到另一条路由?的主要内容,如果未能解决你的问题,请参考以下文章

从 Symfony2 中的 routing.yml 将一条路由重定向(301)到另一条路由

承诺后如何使用react-router重定向到另一个url?

react-router:从组件或存储更改路由

使用 React-Router 4 和 Redux-Promise 重定向用户

如何在 Spring 中重定向到另一台主机

如何以角度将数据从一条路线传输到另一条路线? [复制]