如何在 React 中重定向到另一个视图

Posted

技术标签:

【中文标题】如何在 React 中重定向到另一个视图【英文标题】:How to redirect to another view in React 【发布时间】:2020-10-16 18:25:40 【问题描述】:

我正在开发一个需要登录的应用程序,单击登录按钮后,我需要重定向到另一个布局中的另一个视图,我尝试使用 this.props.history.push("/Inicio ") 在登录成功时重定向。在这种情况下,这是路径。


path: "/Inicio",
name: "Inicio",
component: Inicio,
layout: "/admin"
,

这是完整的代码

import React,  Component  from "react";
import 
   Grid,
   Col
 from "react-bootstrap";

import  Card  from "components/Card/Card.jsx";
import  FormInputs  from "components/FormInputs/FormInputs.jsx";
import Button from "components/CustomButton/CustomButton.jsx";

class Login extends Component 
constructor(props) 
  super(props)
  this.state = 
      users: [],
      user: '',
      pass: '',
      msg: '',
      apiResponse:''
  
  this.logChange = this.logChange.bind(this);
  this.handleSubmit = this.handleSubmit.bind(this)


handleSubmit(event) 
  event.preventDefault()
  var data = 
    user: this.state.user,
    pass: this.state.pass,
    msg: this.state.msg,
    apiResponse: this.state.apiResponse
  
  console.log(data)
  fetch("http://localhost:9000/log/Login", 
      method: 'POST',
      headers: 'Content-Type': 'application/json',
      body: JSON.stringify(data)
  ).then(function(response) 
      if (response.status >= 400) 
        throw new Error("Bad response from server");
      
      return response.json();
  ).then((data) => 
    if(data == "success")
      console.log(data) 
      this.setState(users: data);
      this.props.history.push("/Inicio");
      window.location.reload();
    
    else
      if(data == 'El usuario o la contraseña no coinciden')
        this.setState( apiResponse: data )
      
      
    
  ).catch(function(err) 
      console.log(err)
  );
  
  logChange(e) 
  this.setState([e.target.name]: e.target.value);

  

render() 
return (
  <div className="content">
    <p class="col-md-4"></p>
    <Grid >
        <Col md=5>
          <Card
          
            title="Login"
            content=
              <form method='POST' onSubmit= this.handleSubmit>
                <p class="col-md-2"></p>
                <FormInputs
                  ncols=["col-md-7"]
                  properties=[
                    
                      label: "Usuario",
                      type: "text",
                      bsClass: "form-control",
                      placeholder: "Usuario",
                      maxlength: 20 ,
                      name: "user",
                      onChange: this.logChange
                    
                  ]
                />
                <p class="col-md-2"></p>
                <FormInputs
                  ncols=["col-md-7"]
                  properties=[
                    
                      label: "Contraseña",
                      type: "password",
                      bsClass: "form-control",
                      placeholder: "Contraseña",
                      maxlength: 20,
                      name: "pass",
                      onChange: this.logChange
                    
                  ]
                />
                <p >this.state.apiResponse</p>
                <br/>
                <br/>
                <Button bsStyle="info" pullRight fill type="submit">
                  Login
                </Button>
                <Button bsStyle="info" pullLeft fill type="submit">
                  Olvide mi Contraseña
                </Button>
                
                
              </form>
            
          />
        </Col>
    </Grid>
    
 </div>
);



export default Login;

但在 handleSubmit() 中一切正常,除了 this.props.history.push("/Inicio") 因为它什么也没做。

index.js 代码

import React from "react";
import ReactDOM from "react-dom";

import  BrowserRouter, Route, Switch, Redirect  from "react-router-dom";

import "bootstrap/dist/css/bootstrap.min.css";
import "./assets/css/animate.min.css";
import "./assets/sass/light-bootstrap-dashboard-react.scss?v=1.3.0";
import "./assets/css/demo.css";
import "./assets/css/pe-icon-7-stroke.css";

import AdminLayout from "layouts/Admin.jsx";
import LoginLayout from "layouts/LoginLayout.jsx";
import EfoodLayout from "layouts/EFoodLayout.jsx";

ReactDOM.render(
  <BrowserRouter>
    <Switch>
        <Route path="/admin" render=props => <AdminLayout ...props /> />
        <Route path="/login" render=props => <LoginLayout ...props /> />
        <Route path="/Efood" render=props => <EfoodLayout ...props /> />
        <Redirect from="/" to="/login/Login" />
    </Switch>
  </BrowserRouter>,
  document.getElementById("root")
);

登录布局

import React,  Component  from "react";
import  Route, Switch  from "react-router-dom";

import LoginNavbar from "components/Navbars/LoginNavbar";
import Footer from "components/Footer/Footer";


import routes from "routes.js";

class Login extends Component 

getRoutes = routes => 
return routes.map((prop, key) => 
  if (prop.layout === "/login") 
    return (
      <Route
        path=prop.layout + prop.path
        render=props => (
          <prop.component
            ...props
            handleClick=this.handleNotificationClick
          />
        )
        key=key
      />
    );
   else 
    return null;
  
);
;
getBrandText = path => 
return "Bienvenido a E Food";
;

render() 
 return (
   <div className="wrapper">
      <LoginNavbar 
        brandText=this.getBrandText(this.props.location.pathname)
        
      />
      <Switch>this.getRoutes(routes)</Switch>
      <Footer />
      
   </div>
  );
 
 

export default Login;

希望你能帮助我,并感谢所有回答的人。 PD:如果您需要我的代码中的更多内容,请告诉我。

【问题讨论】:

有问题的组件是由RouteRouter 内渲染以接收路由道具,还是用withRouter HOC 装饰?您能否更新整个组件代码,以及您的路由是什么样的? 与此同时,您似乎没有将班级的this 正确绑定到handleSubmit。您将this 分配给变量self 并且当您尝试仍然使用this 时,它正上方self 用于更新状态。将this 保存到变量self 并不是您真正需要在反应中使用的模式。如果您可以使用整个组件和路由器代码更新您的问题,我们将更好地了解正在发生的事情。 感谢您的回答,正如我在下面所说的,我是新来使用 react,我已经从我在 Internet 上找到的模板中检索了我的所有前端,我已经编辑它看起来像我想要,所以我真的不知道它到底是如何工作的,我知道组件是什么,但我真的不知道这是否是我的想法,路由器也是如此,如果你不介意我可以通过 GitHub 或其他方式向您发送整个代码,前提是您当然接受我不想打扰您。 如果您可以在您的问题中发布相关代码,那就太好了,但是指向您的存储库的链接总比没有好。通常不建议使用代码链接,因为内容可能会更改、移动或删除,这样问题就会失去上下文。 非常感谢,我已经用问题的整个代码和 index.js 编辑了帖子,我希望这会有所帮助,如果没有,我会在这里发布我的 repo 链接,当然,当您访问该链接时,我会删除它以避免出现问题。 【参考方案1】:

好的,因为很明显您要在其中进行导航的组件是一个深度嵌套的组件,所以有几个选项。

道具钻孔(不推荐)

prop drilling

道具钻探的缺点是,如果一开始没有传递正确的道具,或者如果任何组件在此过程中忘记传递道具,那么某些子组件将无法接收他们需要什么,并且可能很难追踪丢失的内容或原因。由于现在对 this 组件的任何更改都需要关注它周围的所有其他组件,因此维护起来更加困难。道具钻孔实际上是一种反应反模式。

登录布局

您的LoginLayout 组件似乎使用了一个路由配置对象并动态呈现路由。它需要传递从其父级接收到的路由道具。此处和您要使用 history.pushLogin 之间的任何组件都需要继续向下传递所有道具。

class Login extends Component 
  getRoutes = routes => 
    return routes.map((prop, key) => 
      if (prop.layout === "/login") 
        return (
          <Route
            path=prop.layout + prop.path
            render=props => (
              <prop.component
                ...props
                ...this.props // <-- Pass on all props passed to this component
                handleClick=this.handleNotificationClick
              />
            )
            key=key
          />
        );
       else 
        return null;
      
    );
  ;
  
  ...

  render() 
    return (
      ...
    );
  

使用withRouter高阶组件(推荐)

withRouter

您可以访问 history 对象的属性和最近的 &lt;Route&gt;match 通过 withRouter 高阶组件。 withRouter 将更新的 matchlocationhistory 道具传递给被包装的 组件无论何时呈现。

import React,  Component  from "react";
import  withRouter  from 'react-router-dom'; // <-- import HOC
import  Grid, Col  from "react-bootstrap";

import  Card  from "components/Card/Card.jsx";
import  FormInputs  from "components/FormInputs/FormInputs.jsx";
import Button from "components/CustomButton/CustomButton.jsx";

class Login extends Component 
  constructor(props) 
    ...
  

  handleSubmit(event) 
    event.preventDefault();
    var data = 
      user: this.state.user,
      pass: this.state.pass,
      msg: this.state.msg,
      apiResponse: this.state.apiResponse
    ;
    console.log(data);
    fetch("http://localhost:9000/log/Login", 
      method: "POST",
      headers:  "Content-Type": "application/json" ,
      body: JSON.stringify(data)
    )
      .then(function(response) 
        if (response.status >= 400) 
          throw new Error("Bad response from server");
        
        return response.json();
      )
      .then(data => 
        if (data == "success") 
          console.log(data);
          this.setState( users: data );
          this.props.history.push("/Inicio"); // <-- history prop should now exist
          window.location.reload();
         else 
          if (data == "El usuario o la contraseña no coinciden") 
            this.setState( apiResponse: data );
          
        
      )
      .catch(function(err) 
        console.log(err);
      );
  
  logChange(e) 
    this.setState( [e.target.name]: e.target.value );
  

  render() 
    return (
      <div className="content">
        ...
      </div>
    );
  


export default withRouter(Login); // <-- decorate Login with HOC

【讨论】:

非常感谢您的宝贵时间和帮助!今晚我将尝试使用 withRouther。 :) @FranHerrera 欢迎您。如果此答案充分解决了您的问题,请标记并接受答案,如果您发现它有帮助或信息丰富,那么也请点赞。干杯。【参考方案2】:

您是否使用react-router-dom 来处理您的路由?如果是这样,您可以使用the hooks to navigate。

import  useHistory  from "react-router-dom";
...
const history = useHistory()

...
history.push('/Inicio')

请注意,这仅适用于 React 版本 >= 16.8

您的代码无法运行的原因是绑定。

使用this.props.history.push("/Inicio") 时,this 指的是您所在的函数,而不是组件历史记录。

如果你想保持你的代码那样,你可以简单地将你的函数变成一个箭头函数:


  .then((data) => 
      if(data == "success")
        console.log(data) 
        self.setState(users: data);
        **this.props.history.push("/Inicio")** // now this will be correct
        **window.location.reload();** // no need, react handles the reload
      
      else
        if(data == 'El usuario o la contraseña no coinciden')
          self.setState( apiResponse: data )
        
        
      

不过,我强烈建议使用 react 的最新功能(检查钩子,它真的很有用)。

【讨论】:

React hooks.... 功能组件。 OP 显然在使用基于类的组件。 @DrewReese 这就是为什么我也用他自己的代码回答,但仍然建议他换成功能组件 这就像把你的 X 品牌汽车送到修理工那里修理,修理工说:“好吧,我开的是 Y 品牌,它可以工作,所以你也应该开 Y 品牌的车。”它没有解释为什么 OP 的代码没有按预期工作并且没有开始解决它。不过,您可能会对函数绑定有所了解。 感谢您的回答,您能告诉我在哪里可以看到 react 版本吗?老实说,我是新来使用 react 的,我从模板中检索了所有前端,所以我真的不知道知道我的反应版本。 我已经尝试过使用 '''import useHistory from "react-router-dom"; ... const history = useHistory() ... history.push('/Inicio')''' 但它告诉我这个错误 Attempted import error: 'useHistory' is not export from 'react-路由器域'。

以上是关于如何在 React 中重定向到另一个视图的主要内容,如果未能解决你的问题,请参考以下文章

如何在 React 中重定向

如何在点击时在 React 中重定向?

使用护照进行身份验证后,如何在 React FROM express 中重定向到用户仪表板

如何在PHP中重定向到同一页面

如何在 Django 中重定向到外部 URL?

如何在 Nuxt Vue 应用程序中重定向