React.js未按预期重定向

时间:2018-07-09 19:21:49

标签: reactjs react-router

“登录”并尝试执行一些重定向后遇到问题。此问题在API响应之后。我正在将CoreUI Pro与React Router v4一起使用。

在登录组件中重定向时,出现此错误

map1 = Map<MyModel, List<String>>(); map2 = Map<String, String>(); Map<MyModel, List<String>> map3 = Stream.of(map1, map2) .flatMap(map -> map.entrySet().stream()) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v1 ) ); 然后停在那里,不会继续进入仪表板。

当尝试在父组件(应用程序)中重定向时,“什么也没有发生”

登录组件仍将数据发送到App中的handleLogin绑定,并且handleLogin也会执行所需的操作,但不会在子Switch部分中重定向,如下所示。

注意,评论是我到目前为止尝试过的事情。

组件应用(父级)

index.js:2178 Warning: You tried to redirect to the same route you're currently on: "/authenticated"

组件登录(应用程序的子级)

import React, { Component } from 'react';
import { HashRouter, Route, Switch, Redirect } from 'react-router-dom';
import './App.css';
// Styles
// CoreUI Icons Set
import '@coreui/icons/css/coreui-icons.min.css';
// Import Flag Icons Set
import 'flag-icon-css/css/flag-icon.min.css';
// Import Font Awesome Icons Set
import 'font-awesome/css/font-awesome.min.css';
// Import Simple Line Icons Set
import 'simple-line-icons/css/simple-line-icons.css';
// Import Main styles for this application
import './scss/style.css'

// Containers
import { DefaultLayout } from './containers';
// Pages
import { Login, Page404, Page500, Register } from './views/Pages';

class App extends Component {
constructor(props) {
    super(props);
    this.state = {
        authenticated: false
    };
    this.handleLogin = this.handleLogin.bind(this);
}

componentDidUpdate(prevProps, prevState) {
    console.log(prevProps, prevState);
    console.log(localStorage.getItem('authenticated'));
    return localStorage.getItem('authenticated') === true
}

handleLogin(jwtToken, authResult) {
    console.log(jwtToken, authResult);
    localStorage.setItem('jwtToken', jwtToken);
    localStorage.setItem('authenticated', authResult);
    this.setState({ authenticated: true });
}

render() {
    const ProtectedRoute = ({ component: Component, ...rest }) => (
        <Route {...rest} render={(props) => (
            localStorage.getItem('authenticated') === true
                ? <Component {...props} />
                : () => {
                    console.log('failed to login');
                    return <Redirect  to={{
                        pathname: '/login',
                        state: { from: props.location }
                    }} />
                }
        )} />
    );

    return (
        <HashRouter>
            <Switch>
                <Route exact path="/login" name="Login Page" component={Login} />
                <Route exact path="/register" name="Register Page" component={Register} />
                <Route exact path="/404" name="Page 404" component={Page404} />
                <Route exact path="/500" name="Page 500" component={Page500} />
                <Route path="/" name="Login Page" render={(props) => {
                    return(<Login {...props} handleLogin={this.handleLogin}/>)
                }}/>
                <ProtectedRoute exact path="/authenticated" name="Dashboard" component={DefaultLayout} />

                /*{this.state.authenticated ? <Redirect to='/authenticated' /> : ''} */

            </Switch>
        </HashRouter>
    );
}
}

export default App;

编辑

此外,/ authenticated之后,还应该像下面那样呈现仪表板。它不会被渲染。 console.log在import React, { Component } from 'react'; import { Button, Card, CardBody, CardGroup, Col, Container, Input, InputGroup, InputGroupAddon, InputGroupText, Row } from 'reactstrap'; import axios from 'axios'; import { Redirect, Switch } from 'react-router-dom'; //import jwtDecode from 'jwt-decode'; const apiUrl = 'http://localhost:3015'; const emailRegex = 'blah blah blah'; const brandDanger = '#f86c6b'; const errorStyle = { marginLeft: '1em', marginTop: '-1em', color: brandDanger, fontStyle: 'italic', }; class Login extends Component { constructor(props) { super(props); // initial state of things this.state = { email: '', password: '', isValidEmail: null, isValidPassword: null, disableLoginButton: true, authenticated: false }; this.handleChange = this.handleChange.bind(this); this.submitRequest = this.submitRequest.bind(this); } handleChange(e) { this.setState({ [e.target.name]: e.target.value }); if (emailRegex.test(this.state.email) && this.state.password.length > 0) { this.setState({ isValidEmail: true, isValidPassword: true, disableLoginButton: false }); } else { this.setState({ isValidEmail: false, isValidPassword: false, disableLoginButton: true }); } } async submitRequest() { this.setState({disableLoginButton: !this.state.disableLoginButton}); const login = await axios.post(`${apiUrl}/api/auth/login`, {email: this.state.email, password: this.state.password}); try { if (login.data.authentication) { this.props.handleLogin(login.data.token, login.data.authentication); this.setState({ authenticated: true }); } } catch (err) { console.log(err) } } render() { //console.log(`thisprops = \n${JSON.stringify(this.props)}`); if (this.state.authenticated) { return <Redirect to='/authenticated'/> } return ( <div className="app flex-row align-items-center"> <Container> <Row className="justify-content-center"> <Col md="8"> <CardGroup> <Card className="p-4"> <CardBody> <h1>Login</h1> <p className="text-muted">Sign In to your account</p> <InputGroup className="mb-3"> <InputGroupAddon addonType="prepend"> <InputGroupText> <i className="icon-user"></i> </InputGroupText> </InputGroupAddon> <Input type="text" placeholder="Email" name="email" onChange={this.handleChange} /> </InputGroup> {this.state.isValidEmail === null ? '' : !this.state.isValidEmail ? <p style={errorStyle}>Email is not valid.</p> : '' } <InputGroup className="mb-4"> <InputGroupAddon addonType="prepend"> <InputGroupText> <i className="icon-lock"></i> </InputGroupText> </InputGroupAddon> <Input type="password" placeholder="Password" name="password" onChange={this.handleChange} /> </InputGroup> {this.state.isValidPassword === null ? '' : !this.state.isValidPassword ? <p style={errorStyle}>Password is required.</p> : '' } <Row> <Col xs="6"> <Button color="primary" className="px-4" onClick={this.submitRequest} disabled={this.state.disableLoginButton} >Login</Button> </Col> <Col xs="6" className="text-right"> <Button color="link" className="px-0">Forgot password?</Button> </Col> </Row> </CardBody> </Card> <Card className="text-white bg-primary py-5 d-md-down-none" style={{ width: 44 + '%' }}> <CardBody className="text-center"> <div> <h2>Sign up</h2> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p> <Button color="primary" className="mt-3" active>Register Now!</Button> </div> </CardBody> </Card> </CardGroup> </Col> </Row> <Row className="justify-content-center"> <Col md="8"> <span className="ml-1">© </span> </Col> </Row> </Container> </div> ); } } export default Login;

中不会发生

组件DefaultLayout(应用程序的子级?)

class DefaultComponent extends Component {...}

1 个答案:

答案 0 :(得分:0)

在重新构建项目并执行我的较早方法之一后,解决了该问题。

客户端身份验证流的工作方法。

在父级App Component中,应/的请求,响应路由器以PrivateRoute Component进行响应,该协商协商用户是否登录,并以要求/重定向登录或继续进行响应到仪表板。

如果需要登录,则会渲染Login Component并将状态authenticated设置为false。如果来自API的成功登录响应,则将状态authenticated设置为true。这将导致该应用使用<Redirect .../>重新呈现,并再次点击位于父App Component中的PrivateRoute。

从此处开始,协商PrivateRoute中的正确身份验证,然后按预期进行。参见下面的src。

应用组件

import React, { Component } from 'react';
import { HashRouter, Route, Switch, Redirect } from 'react-router-dom';
import jwtDecode from 'jwt-decode';

import ...

class App extends Component {
  render() {
    const checkAuth = () => {
        if (!localStorage.getItem('token') || localStorage.getItem('token') === false) {
            return false;
        }
        else if (jwtDecode(localStorage.getItem('token')).exp < Date.now() / 1000) {
            localStorage.setItem('token', false);
            return false;
        }
        console.log(jwtDecode(localStorage.getItem('token')).exp);
        console.log(Date.now() / 1000);
        console.log(jwtDecode(localStorage.getItem('token')));
        return true;
    };

    const PrivateRoute = ({ component: Component, ...rest }) => (
      <Route {...rest} render={(props) => (
        checkAuth()
          ? <Component {...props} />
          : <Redirect to='/login' />
      )} />
    )

    return (
      <HashRouter>
        <Switch>
          <Route exact path="/login" name="Login Page" component={Login} />
          <Route exact path="/register" name="Register Page" component={Register} />
          <Route exact path="/404" name="Page 404" component={Page404} />
          <Route exact path="/500" name="Page 500" component={Page500} />
          <PrivateRoute path="/" name="Home" component={DefaultLayout} />
        </Switch>
      </HashRouter>
    );
  }
}

export default App;

登录组件

import React, { Component } from 'react';
import axios from 'axios';
import { Redirect } from 'react-router-dom';

import ...

class Login extends Component {
    constructor(props) {
        super(props);
        // initial state of things
        this.state = {

            ...

            authenticated: false // set auth to false. If login request is successful, set to true which will allow the Redirect below to work.

        };
        this.handleChange = this.handleChange.bind(this);
        this.submitRequest = this.submitRequest.bind(this);
    }

    handleChange(e)  {
        this.setState({
            [e.target.name]: e.target.value
        });

        if (emailRegex.test(this.state.email) && this.state.password.length > 0) {
            this.setState({
                isValidEmail: true,
                isValidPassword: true,
                disableLoginButton: false
            });
        } else {
            this.setState({
                isValidEmail: false,
                isValidPassword: false,
                disableLoginButton: true
            });
        }
    }


    submitRequest = async() => {
        this.setState({disableLoginButton: !this.state.disableLoginButton});
        const login = await axios.post(`${apiUrl}/api/auth/login`, {email: this.state.email, password: this.state.password});
        try {
            if (login.data.authentication) {
                localStorage.setItem('token', login.data.token);

                // successful login, set state of authenticated to true
                this.setState({ authenticated: !this.state.authenticated });

            }
        } catch (err) {
            console.log(err)
        }
    }

    render() {
        if (this.state.authenticated) {

            return  <Redirect to='/'/> // Request '/' route from react router if auth'd.

        }

        return (
            <div className="app flex-row align-items-center"> 

                 ... Login Form

            </div>

        );
    }
}

export default Login;

DefaultLayout /仪表板组件

import React, { Component } from 'react';
import { Redirect, Route, Switch } from 'react-router-dom';

import navigation from '../../_nav';
// routes config
import routes from '../../routes';

import ...


class DefaultLayout extends Component {
      render() {
            return (
              <div className="app">
                ...
                <Container fluid>

                      <Switch>
                            {routes.map((route, idx) => {
                                return route.component ? (<Route key={idx} path={route.path} exact={route.exact} name={route.name} render={props => (
                                    <route.component {...props} />
                                      )} />)
                                  : (null);
                                  },
                            )}

                            <Redirect from="/" to="/dashboard" /> // To dashboard!



                      </Switch>
                  ...
                  </div>
      );
   }
}

export default DefaultLayout;