简体   繁体   English

渲染()功能在反应中无法正常工作

[英]render() fucntion not working properly in react

I am using the MERN stack for developing a website.我正在使用 MERN 堆栈来开发网站。 I used passport.js for local authentication.我使用 passport.js 进行本地身份验证。 The user logins through a login form on '/login' on the frontend.用户通过前端'/login'上的登录表单登录。 Once the user clicks on the submit button I prevent its default behaviour and send an axios post request at '/login' on the backend.一旦用户单击提交按钮,我将阻止其默认行为并在后端的'/login'处发送 axios 发布请求。 Once the user is authenticated I send the user to '/products' on the frontend.用户通过身份验证后,我将用户发送到前端'/products' To know if the user is authenticated or not, I send an axios get request at '/login' at the backend in the compoundDidMount() function which sets the state property loggedIn to true if user is authenticated, else false . To know if the user is authenticated or not, I send an axios get request at '/login' at the backend in the compoundDidMount() function which sets the state property loggedIn to true if user is authenticated, else false . If I once again visit '/login' route on the frontend I should be redirected to '/products' on the frontend without rendering the code in else statement (login form) based on the code in the render() funtion.如果我再次访问前端'/login'路由,我应该被重定向到前端'/products' ,而不需要根据render()函数中的代码在else语句(登录表单)中呈现代码。 But first, the code in the else statement (login form) is getting rendered for a fraction of a second and then it's rendering the component on '/products' .但首先, else语句(登录表单)中的代码会在几分之一秒内呈现,然后它会在'/products'上呈现组件。 Why is this happening?为什么会这样? I don't want the login form to be rendered once I am logged in, on visiting the '/login' route on the frontend.我不希望在登录后在访问前端的'/login'路由时呈现登录表单。 Here is my code.这是我的代码。

login.js (Login component) login.js (登录组件)

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

class Login extends Component {
    state = {
        email: "",
        password: "",
        loggedIn: false
    }
    
    handleLogin = event => {
        event.preventDefault();
        const data = {
            email: this.state.email, 
            password: this.state.password
        };
        axios.post('/login', data)
        .then(response => {
            // console.log("response status code: ", response.status);
            if(response.status === 200) {
                // this.setState({loggedIn: true});
                this.props.history.push('/products');
            }
        })
        .catch(error => console.log('error is :', error));
    }

    handleChange = event => {
        const property  = event.target.name,
              value     = event.target.value;
        this.setState({[property]: value});
    }

    componentDidMount() {
        this.getLoggedInStatus();
    }

    getLoggedInStatus = () => {
        axios.get('/login')
        .then(response => {
            console.log("response.data is: ", response.data.loggedIn);
            this.setState({loggedIn: response.data.loggedIn});
            // if(response.data.loggedIn)
            //     this.props.history.push('/products');
        })
        .catch(error => console.log("error is : ", error));
        // return loggedIn;
    }

    render() { 
        // this.getLoggedInStatus();
        // console.log("loggedIn is: ", this.state.loggedIn);
        if(this.state.loggedIn) {
            console.log('Working');
            return <Redirect to="/products" />
        }
        else {
            console.log('not working');
            return (
                <div className="container d-flex justify-content-center mt-5">
                    <form className="w-50 mt-2" action="/login" method="POST" onSubmit={this.handleLogin}>
                        <div className="form-group">
                            <label for="exampleInputEmail1">Email address</label>
                            <input type="email" className="form-control" name="email" onChange={this.handleChange} id="exampleInputEmail1" aria-describedby="emailHelp" required/>
                            <small id="emailHelp" className="form-text text-muted">We'll never share your email with anyone else.</small>
                        </div>
                        <div className="form-group">
                            <label for="exampleInputPassword1">Password</label>
                            <input type="password" className="form-control" name="password" onChange={this.handleChange} id="exampleInputPassword1" required/>
                        </div>
                        <button type="submit" className="btn btn-primary">Submit</button>
                    </form>
                </div>
            );
        } 
    }
}
 
export default Login;

backend code后端代码

router.get('/login', (request, response) => {
    response.json({loggedIn: request.isAuthenticated()});
});

router.post('/login', passport.authenticate('local'), (request, response) => {
    if(request.isAuthenticated())
        // response.json('successful login');
        response.status(200).send({message: 'successful login'});
    else {
        console.log('Not authenticated');
        response.status(404).send({message: 'unsuccessful login'});
    }
});

You may want to use isLoading state and show a spinner while the request is in process.您可能希望使用isLoading state 并在请求处理时显示微调器。


state = {
        email: "",
        password: "",
        loggedIn: false
        idLoading: false
    }

...

getLoggedInStatus = () => {
        this.setState({ isLoading: true });
        axios.get('/login')
        .then(response => {
            console.log("response.data is: ", response.data.loggedIn);
            this.setState({loggedIn: response.data.loggedIn, isLoading: false});
            // if(response.data.loggedIn)
            //     this.props.history.push('/products');
        })
        .catch(error => console.log("error is : ", error));
        // return loggedIn;
    }

...

render() { 
        // this.getLoggedInStatus();
        // console.log("loggedIn is: ", this.state.loggedIn);
        if(this.state.loggedIn) {
            console.log('Working');
            return <Redirect to="/products" />
        }
        else {
            if (this.state.isLoading) {
              <div>Loading...</div>
            }
            return (
                <div className="container d-flex justify-content-center mt-5">
                    <form className="w-50 mt-2" action="/login" method="POST" onSubmit={this.handleLogin}>
                        <div className="form-group">
                            <label for="exampleInputEmail1">Email address</label>
                            <input type="email" className="form-control" name="email" onChange={this.handleChange} id="exampleInputEmail1" aria-describedby="emailHelp" required/>
                            <small id="emailHelp" className="form-text text-muted">We'll never share your email with anyone else.</small>
                        </div>
                        <div className="form-group">
                            <label for="exampleInputPassword1">Password</label>
                            <input type="password" className="form-control" name="password" onChange={this.handleChange} id="exampleInputPassword1" required/>
                        </div>
                        <button type="submit" className="btn btn-primary">Submit</button>
                    </form>
                </div>
            );
        } 
    }

React component life-cycle methods are called in the following sequence: React 组件生命周期方法按以下顺序调用:

Constructor -> componentWillMount -> render -> componentDidMount构造函数 -> componentWillMount -> 渲染 -> componentDidMount

Every time when you go to login page a NEW instance of your Login component gets created.每次当您 go 登录页面时,都会创建一个Login组件实例。 Your "implicit" constructor initializes a new instance with state.loggedIn to false by您的“隐式”构造函数使用state.loggedIn将新实例初始化为false

state = {
        email: "",
        password: "",
        loggedIn: false
    }

This causes your render function to show login form and call componentDidMount which sends a request to the backend.这会导致您的渲染 function 显示登录表单并调用向后端发送请求的componentDidMount While your component is waiting for a response from the backend - login form is shown on the screen.当您的组件正在等待来自后端的响应时 - 登录表单会显示在屏幕上。 Once response comes in - you set state.loggedIn to true which causes another render call and this time your component redirects to a products page.一旦响应进来 - 您将state.loggedIn设置为 true ,这会导致另一个render调用,这一次您的组件将重定向到products页面。

In order to fix your problem you need to move loggedIn property from component state level to application state level by using something like redux or any other approach to manage front-end application state. In order to fix your problem you need to move loggedIn property from component state level to application state level by using something like redux or any other approach to manage front-end application state.

Suggestion建议

Add an extra property (ie loading) to your state object to track if the login should render or not (and perhaps adding a loading component).添加一个额外的属性(即加载)到您的 state object 以跟踪登录是否应该呈现(并且可能添加一个加载组件)。 See code comment as well.另请参阅代码注释。

Example:例子:

// Your component state
state = {
        email: "",
        password: "",
        loggedIn: false,
        loading: true // default state
};


// Your getLoggedInStatus code

 getLoggedInStatus = () => {
    axios.get('/login')
    .then(response => {
        console.log("response.data is: ", response.data.loggedIn);
        this.setState({loggedIn: response.data.loggedIn, loading: false}); // update loading state to false
    })
    .catch(error => console.log("error is : ", error));
    // return loggedIn;
}


// Your render code

render() { 
        // this.getLoggedInStatus();
        // console.log("loggedIn is: ", this.state.loggedIn);
        if(this.state.loggedIn) {
            console.log('Working');
            return <Redirect to="/products" />
        }
        else {
            if(this.state.loading) {
               return(<div> Loading...</div>); // Have something more fancy here
            } else {
              return (
                <div className="container d-flex justify-content-center mt-5">
                    <form className="w-50 mt-2" action="/login" method="POST" onSubmit={this.handleLogin}>
                        <div className="form-group">
                            <label for="exampleInputEmail1">Email address</label>
                            <input type="email" className="form-control" name="email" onChange={this.handleChange} id="exampleInputEmail1" aria-describedby="emailHelp" required/>
                            <small id="emailHelp" className="form-text text-muted">We'll never share your email with anyone else.</small>
                        </div>
                        <div className="form-group">
                            <label for="exampleInputPassword1">Password</label>
                            <input type="password" className="form-control" name="password" onChange={this.handleChange} id="exampleInputPassword1" required/>
                        </div>
                        <button type="submit" className="btn btn-primary">Submit</button>
                    </form>
                </div>
            );
            }
        } 
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM