【问题标题】:How to use Redirect in version 5 of react-router-dom of Reactjs如何在 Reactjs 的新 react-router-dom 中使用 Redirect
【发布时间】:2017-08-31 00:13:17
【问题描述】:

我正在使用最新版本的 react-router 模块,名为 react-router-dom,它已成为使用 React 开发 Web 应用程序时的默认设置。我想知道如何在 POST 请求后进行重定向。我一直在制作这段代码,但是在请求之后,什么也没有发生。我在网上查看过,但所有数据都是关于以前版本的 react 路由器,而上次更新没有。

代码:

import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { Redirect } from 'react-router'

import SignUpForm from '../../register/components/SignUpForm';
import styles from './PagesStyles.css';
import axios from 'axios';
import Footer from '../../shared/components/Footer';

class SignUpPage extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      errors: {},
      client: {
        userclient: '',
        clientname: '',
        clientbusinessname: '',
        password: '',
        confirmPassword: ''
      }
    };

    this.processForm = this.processForm.bind(this);
    this.changeClient = this.changeClient.bind(this);
  }

  changeClient(event) {
    const field = event.target.name;
    const client = this.state.client;
    client[field] = event.target.value;

    this.setState({
      client
    });
  }

  async processForm(event) {
    event.preventDefault();

    const userclient = this.state.client.userclient;
    const clientname = this.state.client.clientname;
    const clientbusinessname = this.state.client.clientbusinessname;
    const password = this.state.client.password;
    const confirmPassword = this.state.client.confirmPassword;
    const formData = { userclient, clientname, clientbusinessname, password, confirmPassword };

    axios.post('/signup', formData, { headers: {'Accept': 'application/json'} })
      .then((response) => {
        this.setState({
          errors: {}
        });

        <Redirect to="/"/> // Here, nothings happens
      }).catch((error) => {
        const errors = error.response.data.errors ? error.response.data.errors : {};
        errors.summary = error.response.data.message;

        this.setState({
          errors
        });
      });
  }

  render() {
    return (
      <div className={styles.section}>
        <div className={styles.container}>
          <img src={require('./images/lisa_principal_bg.png')} className={styles.fullImageBackground} />
          <SignUpForm 
            onSubmit={this.processForm}
            onChange={this.changeClient}
            errors={this.state.errors}
            client={this.state.client}
          />
          <Footer />
        </div>
      </div>
    );
  }
}

export default SignUpPage;

【问题讨论】:

  • 你的 Redirect 看起来像 JSX,而不是 JS。
  • 能否提供完整的组件代码
  • 是的,我正在使用 JSX。好吧,也许我需要澄清一下。 POST 请求位于发出请求的 REACT 组件中。
  • @KornholioBeavis,当然,现在你可以看到完整的了。我用expressjs做服务器,不知道你是否需要这个数据
  • 你能确认你正在从 axios.post 收到回调响应吗?另外你为什么使用异步函数而不在任何地方等待?

标签: javascript reactjs react-router


【解决方案1】:

您必须使用setState 设置一个属性,该属性将在您的render() 方法中呈现&lt;Redirect&gt;

例如

class MyComponent extends React.Component {
  state = {
    redirect: false
  }

  handleSubmit () {
    axios.post(/**/)
      .then(() => this.setState({ redirect: true }));
  }

  render () {
    const { redirect } = this.state;

     if (redirect) {
       return <Redirect to='/somewhere'/>;
     }

     return <RenderYourForm/>;
}

你也可以在官方文档中看到一个例子:https://reacttraining.com/react-router/web/example/auth-workflow


也就是说,我建议您将 API 调用放在服务或其他东西中。然后您可以使用history 对象以编程方式进行路由。这就是integration with redux 的工作原理。

但我猜你有理由这样做。

【讨论】:

  • @sebastian sebald 你是什么意思:put the API call inside a service or something
  • 在您的组件中拥有这样的(异步)API 调用会增加测试和重用的难度。通常最好创建一个服务然后在componentDidMount 中使用它(例如)。或者更好的是,创建一个“包装”您的 API 的 HOC
  • 注意必须在文件开头包含Redirect才能使用它:import { Redirect } from 'react-router-dom'
  • 是的,在后台Redirect 正在调用history.replace。如果要访问history 对象,请使用withRoutet/Route
  • react-router >=5.1 现在包含挂钩,因此您只需 const history = useHistory(); history.push("/myRoute")
【解决方案2】:

这里有一个小例子作为对标题的回应,因为我认为所有提到的例子都很复杂,官方的例子也很复杂。

您应该知道如何编译 es2015 以及如何让您的服务器能够处理重定向。这是 express 的 sn-p。更多相关信息可以在here找到。

确保将其放在所有其他路线下方。

const app = express();
app.use(express.static('distApp'));

/**
 * Enable routing with React.
 */
app.get('*', (req, res) => {
  res.sendFile(path.resolve('distApp', 'index.html'));
});

这是 .jsx 文件。请注意最长的路径是如何出现的,并且变得更一般。对于最一般的路线,请使用确切属性。

// Relative imports
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';

// Absolute imports
import YourReactComp from './YourReactComp.jsx';

const root = document.getElementById('root');

const MainPage= () => (
  <div>Main Page</div>
);

const EditPage= () => (
  <div>Edit Page</div>
);

const NoMatch = () => (
  <p>No Match</p>
);

const RoutedApp = () => (
  <BrowserRouter >
    <Switch>
      <Route path="/items/:id" component={EditPage} />
      <Route exact path="/items" component={MainPage} />          
      <Route path="/yourReactComp" component={YourReactComp} />
      <Route exact path="/" render={() => (<Redirect to="/items" />)} />          
      <Route path="*" component={NoMatch} />          
    </Switch>
  </BrowserRouter>
);

ReactDOM.render(<RoutedApp />, root); 

【讨论】:

  • 这并不总是有效。如果您有来自home/hello > home/hello/1 的重定向,然后转到home/hello 并按回车键,它不会第一次重定向。任何想法为什么??
  • 我建议您尽可能使用“create-react-app”并遵循 react-router 的文档。使用“create-react-app”一切对我来说都很好。我无法将自己的 react 应用程序调整为新的 react-router。
【解决方案3】:

React Router v5 现在允许您使用 history.push() 简单地重定向,这要归功于 useHistory() hook:

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

function HomeButton() {
  let history = useHistory()

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

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

【讨论】:

  • 现在,我们从react-router-dom 导入所有内容。
【解决方案4】:

只需在您喜欢的任何函数中调用它。

this.props.history.push('/main');

【讨论】:

【解决方案5】:

试试这样的。

import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { Redirect } from 'react-router'

import SignUpForm from '../../register/components/SignUpForm';
import styles from './PagesStyles.css';
import axios from 'axios';
import Footer from '../../shared/components/Footer';

class SignUpPage extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      errors: {},
      callbackResponse: null,
      client: {
        userclient: '',
        clientname: '',
        clientbusinessname: '',
        password: '',
        confirmPassword: ''
      }
    };

    this.processForm = this.processForm.bind(this);
    this.changeClient = this.changeClient.bind(this);
  }

  changeClient(event) {
    const field = event.target.name;
    const client = this.state.client;
    client[field] = event.target.value;

    this.setState({
      client
    });
  }

  processForm(event) {
    event.preventDefault();

    const userclient = this.state.client.userclient;
    const clientname = this.state.client.clientname;
    const clientbusinessname = this.state.client.clientbusinessname;
    const password = this.state.client.password;
    const confirmPassword = this.state.client.confirmPassword;
    const formData = { userclient, clientname, clientbusinessname, password, confirmPassword };

    axios.post('/signup', formData, { headers: {'Accept': 'application/json'} })
      .then((response) => {
        this.setState({
          callbackResponse: {response.data},
        });
      }).catch((error) => {
        const errors = error.response.data.errors ? error.response.data.errors : {};
        errors.summary = error.response.data.message;

        this.setState({
          errors
        });
      });
  }

const renderMe = ()=>{
return(
this.state.callbackResponse
?  <SignUpForm 
            onSubmit={this.processForm}
            onChange={this.changeClient}
            errors={this.state.errors}
            client={this.state.client}
          />
: <Redirect to="/"/>
)}

  render() {
    return (
      <div className={styles.section}>
        <div className={styles.container}>
          <img src={require('./images/lisa_principal_bg.png')} className={styles.fullImageBackground} />
         {renderMe()}
          <Footer />
        </div>
      </div>
    );
  }
}

export default SignUpPage;

【讨论】:

  • 您不应该在组件文件中发出 HTTP 请求
  • 你能分享一下 import SignUpForm from '../../register/components/SignUpForm'; 里面的内容吗?我正在努力从中学习。虽然就我而言,我使用的是 redux 表单
【解决方案6】:

或者,您可以使用withRouter。您可以通过withRouter 高阶组件访问history 对象的属性和最接近的&lt;Route&gt;matchwithRouter 将在渲染时将更新的 matchlocationhistory 属性传递给包装的组件。

import React from "react"
import PropTypes from "prop-types"
import { withRouter } from "react-router"

// A simple component that shows the pathname of the current location
class ShowTheLocation extends React.Component {
  static propTypes = {
    match: PropTypes.object.isRequired,
    location: PropTypes.object.isRequired,
    history: PropTypes.object.isRequired
  }

  render() {
    const { match, location, history } = this.props

    return <div>You are now at {location.pathname}</div>
  }
}
// Create a new component that is "connected" (to borrow redux
// terminology) to the router.
const ShowTheLocationWithRouter = withRouter(ShowTheLocation)

或者只是:

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

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

【讨论】:

  • withRouter 在 v6 中现已弃用
【解决方案7】:

你可以为此编写一个 hoc 并编写一个方法调用重定向,代码如下:

import React, {useState} from 'react';
import {Redirect} from "react-router-dom";

const RedirectHoc = (WrappedComponent) => () => {
    const [routName, setRoutName] = useState("");
    const redirect = (to) => {
        setRoutName(to);
    };


    if (routName) {
        return <Redirect to={"/" + routName}/>
    }
    return (
        <>
            <WrappedComponent redirect={redirect}/>
        </>
    );
};

export default RedirectHoc;

【讨论】:

    【解决方案8】:

    导航到另一个组件的最简单的解决方案是(示例 通过点击图标导航到邮件组件):

    <MailIcon 
      onClick={ () => { this.props.history.push('/mails') } }
    />
    

    【讨论】:

      【解决方案9】:
      "react": "^16.3.2",
      "react-dom": "^16.3.2",
      "react-router-dom": "^4.2.2"
      

      为了导航到另一个页面(在我的例子中是关于页面),我安装了prop-types。然后我将它导入到相应的组件中。我使用了this.context.router.history.push('/about')。它被导航了。

      我的代码是,

      import React, { Component } from 'react';
      import '../assets/mystyle.css';
      import { Redirect } from 'react-router';
      import PropTypes from 'prop-types';
      
      export default class Header extends Component {   
          viewAbout() {
             this.context.router.history.push('/about')
          }
          render() {
              return (
                  <header className="App-header">
                      <div className="myapp_menu">
                          <input type="button" value="Home" />
                          <input type="button" value="Services" />
                          <input type="button" value="Contact" />
                          <input type="button" value="About" onClick={() => { this.viewAbout() }} />
                      </div>
                  </header>
              )
          }
      }
      Header.contextTypes = {
          router: PropTypes.object
        };
      

      【讨论】:

        【解决方案10】:

        或者,您可以使用 React 条件渲染。

        import { Redirect } from "react-router";
        import React, { Component } from 'react';
        
        class UserSignup extends Component {
          constructor(props) {
            super(props);
            this.state = {
              redirect: false
            }
          }
        render() {
         <React.Fragment>
           { this.state.redirect && <Redirect to="/signin" /> }   // you will be redirected to signin route
        }
        </React.Fragment>
        }
        

        【讨论】:

        • 这可行,但需要将“react-router”更改为“react-router-dom”,否则会抛出错误:不变失败:您不应该在 >
        【解决方案11】:

        您好,如果您在此版本中使用 react-router v-6.0.0-beta 或 V6 将更改重定向到像这样导航

        从'react-router-dom'导入{导航}; // 就像 v6 中的这个正确 从'react-router-dom'导入{重定向}; // 像 v5 中的这个 CORRECT

        从'react-router-dom'导入{重定向}; // 像这样在 v6 中是错误的 // 这会在 react-router 和 react-router dom 的 V6 中给你错误

        请确保在 package.json 中使用相同的版本 { "react-router": "^6.0.0-beta.0", //像这样 "react-router-dom": "^6.0.0-beta.0", // 像这样 }

        以上内容仅适用于 React Router Version 6

        【讨论】:

          【解决方案12】:

          我遇到的问题是我有一台现有的 IIS 机器。然后我向它部署一个静态的 React 应用程序。当您使用路由器时,显示的 URL 实际上是虚拟的,而不是真实的。如果你按 F5,它会转到 IIS,而不是 index.js,你的返回将是 404 文件未找到。我如何解决它很简单。我的反应应用程序中有一个公共文件夹。在该公用文件夹中,我创建了与虚拟路由相同的文件夹名称。在此文件夹中,我有一个 index.html,其中包含以下代码:

          <script>
            {
              sessionStorage.setItem("redirect", "/ansible/");
              location.href = "/";
            }
          </script>
          

          现在,这是针对本次会话所做的,我正在添加我希望它通过的“路由”路径。然后在我的 App.js 中执行此操作(注意 ... 是其他代码,但太多了,无法放在这里进行演示):

          import React, { Component } from "react";
          import { Route, Link } from "react-router-dom";
          import { BrowserRouter as Router } from "react-router-dom";
          import { Redirect } from 'react-router';
          import Ansible from "./Development/Ansible";
          import Code from "./Development/Code";
          import Wood from "./WoodWorking";
          import "./App.css";
          
          class App extends Component {
            render() {
              const redirect = sessionStorage.getItem("redirect");
          
              if(redirect) {
                sessionStorage.removeItem("redirect");
              }
          
              return (
                <Router>
                  {redirect ?<Redirect to={redirect}/> : ""}
                  <div className="App">
                  ...
                    <Link to="/">
                      <li>Home</li>
                    </Link>
                    <Link to="/dev">
                      <li>Development</li>
                    </Link>
                    <Link to="/wood">
                      <li>Wood Working</li>
                    </Link>
                  ...
                    <Route
                      path="/"
                      exact
                      render={(props) => (
                        <Home {...props} />
                      )}
                    />
                    <Route
                      path="/dev"
                      render={(props) => (
                        <Code {...props} />
                      )}
                    />
                    <Route
                      path="/wood"
                      render={(props) => (
                        <Wood {...props} />
                      )}
                    />
                    <Route
                      path="/ansible/"
                      exact
                      render={(props) => (
                        <Ansible {...props} checked={this.state.checked} />
                      )}
                    />
                    ...
                </Router>
              );
            }
          }
          
          export default App;
          

          实际使用:chizl.com

          编辑:从 localStorage 更改为 sessionStorage。 sessionStorage 在您关闭选项卡或浏览器时消失,并且无法被浏览器中的其他选项卡读取。

          【讨论】:

            【解决方案13】:

            要导航到另一个组件,您可以使用this.props.history.push('/main');

            import React, { Component, Fragment } from 'react'
            
            class Example extends Component {
            
              redirect() {
                this.props.history.push('/main')
              }
            
              render() {
                return (
                  <Fragment>
                    {this.redirect()}
                  </Fragment>
                );
               }
             }
            
             export default Example
            

            【讨论】:

            • React 抛出警告:Warning: Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state.
            【解决方案14】:

            我发现react-router的redirect complent放在render方法中,但是如果你想在一些验证后重定向,例如,最好的重定向方法是使用旧的可靠的window.location。 href,即:

            evalSuccessResponse(data){
               if(data.code===200){
                window.location.href = urlOneSignHome;
               }else{
                 //TODO Something
               }    
            }
            

            当你在编程时,React Native 永远不需要离开应用程序,打开另一个应用程序的机制完全不同。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2020-12-22
              • 2021-03-15
              • 2018-01-28
              • 2019-07-02
              • 2020-10-04
              • 2021-01-11
              • 2020-11-02
              • 2019-02-05
              相关资源
              最近更新 更多