【问题标题】:render() fucntion not working properly in reactrender() 函数在反应中无法正常工作
【发布时间】:2020-07-11 22:47:50
【问题描述】:

我正在使用 MERN 堆栈来开发网站。我使用 passport.js 进行本地身份验证。用户通过前端'/login' 上的登录表单登录。一旦用户单击提交按钮,我将阻止其默认行为并在后端的'/login' 发送 axios 发布请求。用户通过身份验证后,我将用户发送到前端的'/products'。要知道用户是否通过身份验证,我在compoundDidMount() 函数的后端的'/login' 发送一个axios get 请求,如果用户通过身份验证,则将状态属性loggedIn 设置为true,否则false .如果我再次访问前端的'/login' 路由,我应该被重定向到前端的'/products',而不根据render() 函数中的代码呈现else 语句(登录表单)中的代码。但首先,else 语句(登录表单)中的代码被渲染了几分之一秒,然后它在'/products' 上渲染组件。为什么会这样?我不希望登录后在访问前端的'/login' 路由时呈现登录表单。这是我的代码。

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;

后端代码

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'});
    }
});

【问题讨论】:

  • 我会建议保留用户是否登录的信息,而不是在 localStorage 中并且在 componentDidMount 中进行调用之前,检查数据是否存在于本地存储中,如果是,不要直接调用后端重定向 else 调用 backend 。这将减少不必要的后端调用的延迟!

标签: javascript reactjs async-await


【解决方案1】:

建议

向您的状态对象添加一个额外的属性(即加载)以跟踪登录是否应该呈现(并且可能添加一个加载组件)。另见代码注释。

示例:

// 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>
            );
            }
        } 
    }

【讨论】:

    【解决方案2】:

    您可能希望使用isLoading 状态并在请求处理时显示一个微调器。


    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>
                );
            } 
        }
    

    【讨论】:

      【解决方案3】:

      React 组件生命周期方法按以下顺序调用:

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

      每当您进入登录页面时,您的Login 组件的NEW 实例都会被创建。您的“隐式”构造函数使用 state.loggedIn 将新实例初始化为 false

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

      这会导致您的渲染函数显示登录表单并调用componentDidMount 向后端发送请求。当您的组件等待来自后端的响应时 - 登录表单会显示在屏幕上。一旦收到响应 - 您将 state.loggedIn 设置为 true,这会导致另一个 render 调用,这一次您的组件将重定向到 products 页面。

      为了解决您的问题,您需要使用类似 redux 或任何其他方法来管理前端应用程序状态,将 loggedIn 属性从组件状态级别移动到应用程序状态级别。

      【讨论】:

        猜你喜欢
        • 2019-08-04
        • 1970-01-01
        • 2020-04-10
        • 1970-01-01
        • 2017-05-13
        • 2012-03-31
        • 1970-01-01
        • 1970-01-01
        • 2017-11-09
        相关资源
        最近更新 更多