【问题标题】:Reactjs not redirecting as intendedReactjs没有按预期重定向
【发布时间】:2018-07-09 19:21:48
【问题描述】:

我在“登录”并尝试执行一些重定向后遇到问题。此问题在 API 响应之后。我正在使用 CoreUI pro 和 react 路由器 v4。

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

index.js:2178 Warning: You tried to redirect to the same route you're currently on: "/authenticated" 并停在那里,并没有进入仪表板。

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

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

注意,cmets 是我迄今为止尝试过的东西。

组件应用(父级)

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;

组件登录(应用的子级)

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;

编辑

此外,在 /authenticated 之后,它应该呈现如下所示的仪表板。它不会被渲染。 console.log 不会发生在class DefaultComponent extends Component {...}

组件默认布局(应用的子级?)

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

import {
    AppAside,
    AppBreadcrumb,
    AppFooter,
    AppHeader,
    AppSidebar,
    AppSidebarFooter,
    AppSidebarForm,
    AppSidebarHeader,
    AppSidebarMinimizer,
    AppSidebarNav,
} from '@coreui/react';
// sidebar nav config
import navigation from '../../_nav';
// routes config
import routes from '../../routes';

import DefaultAside from './DefaultAside';
import DefaultFooter from './DefaultFooter';
import DefaultHeader from './DefaultHeader';

class DefaultLayout extends Component {
render() {
    //console.log(localStorage.getItem('jwtToken'));
    console.log(`default layout props:\n ${this.props}`);
    return (
        <div className="app">
            <AppHeader fixed>
                <DefaultHeader />
            </AppHeader>
            <div className="app-body">
                <AppSidebar fixed display="lg">
                    <AppSidebarHeader />
                    <AppSidebarForm />
                    <AppSidebarNav navConfig={navigation} {...this.props} />
                    <AppSidebarFooter />
                    <AppSidebarMinimizer />
                </AppSidebar>
                <main className="main">
                    <AppBreadcrumb appRoutes={routes}/>
                    <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 exact from='/authenticated' to='/dashboard'/>

                        </Switch>
                    </Container>
                </main>
                <AppAside fixed hidden>
                    <DefaultAside />
                </AppAside>
            </div>
            <AppFooter>
                <DefaultFooter />
            </AppFooter>
        </div>
    );
}
}

export default DefaultLayout;

【问题讨论】:

    标签: reactjs react-router


    【解决方案1】:

    在重新构建我的项目并执行我早期的方法之一后修复了该问题。

    客户端认证流程的工作方式。

    在父App Component 中,应/ 的请求,react-router 以PrivateRoute Component 进行响应,该PrivateRoute Component 协商用户是否登录,并以要求/重定向登录或继续访问仪表板进行响应。

    如果需要登录,Login Component 将被渲染并且状态 authenticated 设置为 false。如果来自 API 的成功登录响应,则状态 authenticatedgets 设置为 true。这将导致应用重新渲染&lt;Redirect .../&gt;,并再次访问位于父级App Component 中的PrivateRoute。

    从这里开始,在PrivateRoute 中协商正确的身份验证,然后按预期进行。源代码见下文。

    应用组件

    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;
    

    默认布局/仪表板组件

    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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-11
      • 2019-12-04
      • 2020-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-15
      相关资源
      最近更新 更多