简体   繁体   English

如何在React JS中使用Redux进行登录

[英]How to make Login using redux in react js

I am creating login concept using redux in react.js I am getting an error - Cannot read property 'name' of undefined in {this.props.userlogin.name} 我在react.js中使用redux创建登录概念,但出现错误-无法读取{this.props.userlogin.name}中未定义的属性'name'

I have created action and reducer in code. 我已经在代码中创建了动作和减速器。

My header.js File is - 我的header.js文件是-

import React, { Component } from "react";
import { Link, withRouter } from 'react-router-dom';
import './Header.css'
import logo from '../logo.png';
import LoadingSpinner from '../loadingspinner.component';
import Modal from 'react-bootstrap/Modal';
import { loginUser } from "../../Actions/actions";
import PropTypes from "prop-types";
import { connect } from "react-redux";

const emailRegex = RegExp(/^[a-zA-Z0-9_\-\.]+@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/)

const formValid = formErrors => {
    let valid = true;
    Object.values(formErrors).forEach(val => {
        val.length > 0 && (valid = false)
    });
    return valid;
}

class Header extends Component {
    constructor(props) {
        super(props);

        this.state = {
            show: false,
            email: "",
            name: "",
            password: "",
            loading: false,
            message: '',
            formErrors: {
                email: "",
                password: ""
            }
        };

        this.handleShow = () => {
            this.setState({ show: true });
        };

        this.handleHide = () => {
            this.setState({ show: false });
        };

        this.onChange = this.onChange.bind(this);
        this.onSubmit = this.onSubmit.bind(this);
    }

    componentDidMount() {
        // if (localStorage.usertoken && localStorage.usertoken != 'undefined') {
        //     const token = localStorage.usertoken;

        //     const decoded = jwt_decode(token);
        //     console.log(decoded);
        //     this.setState({
        //         name: decoded.name
        //     })
        // }
    }

    onChange(e) {
        const { name, value } = e.target;
        // console.log("name :", name);
        // console.log("value :", value);
        this.setState({ [e.target.name]: e.target.value });
        let formErrors = this.state.formErrors;

        switch (name) {
            case 'email':
                formErrors.email = emailRegex.test(value) ? '' : "Invalid Email Address";
                break;
            case 'password':
                formErrors.password = value.length < 6 ? 'Minimum 6 character required' : "";
                break;
            default: break;
        }
        this.setState({ formErrors, [name]: value }, () => console.log(this.state));
    }

    logOut(e) {
        e.preventDefault();
        localStorage.removeItem("usertoken");
        this.props.history.push("/");
    }

    onSubmit(e) {

        if (formValid(this.state.formErrors)) {
            this.setState({
                loading: true,
            })
            e.preventDefault();
            const user = {
                email: this.state.email,
                password: this.state.password
            };

            this.props.loginUser(user).then((res, err) => {
                // console.log(res);
                if (res.Success == '0') {
                    this.setState({
                        loading: false,
                        message: res.Message
                    })
                }
                else {
                    // if (localStorage.usertoken && localStorage.usertoken != 'undefined') {
                    //     const token = localStorage.usertoken;

                    //     const decoded = jwt_decode(token);
                    //     console.log(decoded);
                    //     this.setState({
                    //         name: decoded.name
                    //     })
                    // }
                    this.handleHide();
                }
            });
        }
        else {
            e.preventDefault();
            console.error('FORM ERROR - DISPLAY ERROR MESSAGE');
        }
    }

    render() {
        const { loading, message } = this.state;
        const { formErrors } = this.state;

        const loginRegLink = (
            <div className="" style={{ display: 'inline-flex' }}>
                <li class="nav-item">
                    <a onClick={this.handleShow} class="nav-link" style={{ cursor: 'pointer' }} >Login&nbsp;<i class="fa fa-user" aria-hidden="true"></i></a>
                </li>
                {/* <li class="nav-item">
                    <a class="nav-link" href="/">SignUp&nbsp;<i class="fa fa-lock" aria-hidden="true"></i></a>
                </li> */}
                <li class="nav-item">
                    <a class="nav-link" href="/">AboutUs</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="/">ContactUs</a>
                </li>
            </div>
        );

        const userLink = (
            <div className="" style={{ display: 'inline-flex' }}>
                <li class="nav-item">

                    <Link className="nav-link" to="/">{this.props.userlogin.name}</Link>

                </li>
                <li class="nav-item">
                    <a href="" onClick={this.logOut.bind(this)} className="nav-link">
                        Logout
          </a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="/">AboutUs</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="/">ContactUs</a>
                </li>
            </div>

        );

        return (
            <nav class="navbar navbar-expand-md navbar-light bg-basic" >
                <Link to="/">
                    <img src={logo} />
                </Link>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarTogglerDemo03" aria-controls="navbarTogglerDemo03" aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="collapse navbar-collapse w-100 flex-md-column" id="navbarTogglerDemo03">
                    <ul class="navbar-nav ml-auto small mb-2 mb-md-0">
                        {/* <li class="nav-item dropdown">
                            <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                                <img className="country-image" src="https://www.countryflags.io/be/shiny/64.png" />&nbsp;English
                        </a>
                            <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
                                <a class="dropdown-item" href="#">Action</a>
                                <a class="dropdown-item" href="#">Another action</a>
                                <a class="dropdown-item" href="#">Something else here</a>
                            </div>
                        </li> */}
                        {localStorage.usertoken && localStorage.usertoken != 'undefined' ? userLink : loginRegLink}
                    </ul>

                </div>


                {/* model popup */}
                <Modal
                    show={this.state.show}
                    onHide={this.handleHide}
                    dialogClassName="modal-90w"
                    aria-labelledby="example-custom-modal-styling-title"
                    centered
                    size="md"
                >
                    <Modal.Header closeButton>
                        <Modal.Title id="example-custom-modal-styling-title text-center">
                            IT Referrals Login
            </Modal.Title>
                    </Modal.Header>
                    <Modal.Body>
                        <div class="form-group" id="sampleTableForEmployee">
                            {message !== '' &&
                                <div class="alert alert-danger alert-dismissible" role="alert">
                                    {message}
                                </div>
                            }
                            <form onSubmit={this.onSubmit}>
                                <div className="row">

                                    <div className="col-md-12">
                                        <div className="input-class-field">
                                            <div className="form-group">
                                                <label htmlFor="email"><b>Email</b></label>
                                                <div className="input-group">
                                                    <span className="input-group-addon">
                                                        <span className="glyphicon glyphicon-envelope" />
                                                    </span>
                                                    <input
                                                        type="email"
                                                        className='form-control'
                                                        id="email"
                                                        name="email"
                                                        style={{ width: '100%' }}
                                                        placeholder="anyone@example.com"
                                                        required="required"
                                                        value={this.state.email}
                                                        onChange={this.onChange}
                                                    />
                                                    {formErrors.email && (
                                                        <span className="errorMessage" style={{ color: 'red', fontSize: '14px' }}>{formErrors.email}</span>
                                                    )}
                                                </div>
                                            </div>
                                            <div className="form-group">
                                                <label htmlFor="password"><b>Password</b></label>
                                                <div className="input-group">
                                                    <span className="input-group-addon">
                                                        <span className="glyphicon glyphicon-envelope" />
                                                    </span>
                                                    <input
                                                        type="password"
                                                        className={formErrors.password.length > 0 ? 'error form-control' : 'form-control'}
                                                        style={{ width: '100%' }}
                                                        id="password"
                                                        name="password"
                                                        placeholder="********"
                                                        required="required"
                                                        value={this.state.password}
                                                        onChange={this.onChange}
                                                    />
                                                    {formErrors.password.length > 0 && (
                                                        <span className="errorMessage" style={{ color: 'red', fontSize: '14px' }}>{formErrors.password}</span>
                                                    )}
                                                </div>
                                            </div>

                                            <div className="form-group">
                                                <button
                                                    type="submit"
                                                    className="btn btn-primary btn-block pull-right"
                                                    id="btnContactUs"
                                                >
                                                    {loading ? <LoadingSpinner /> : "Login"}
                                                </button><br /><br />
                                                {/* <p className="forgetpassword"><a href="">Forget my password ?</a></p> */}
                                                {/* <p className="signup">Don't have an account? <Link to="/register"> Create Now</Link> </p> */}
                                            </div>
                                        </div>
                                    </div>


                                </div>
                            </form>
                        </div>
                        <hr />

                    </Modal.Body>
                </Modal>
                {/* end modal popup */}
            </nav >
        )
    }
}

Header.propTypes = {
    loginUser: PropTypes.func.isRequired,
    userlogin: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
    userlogin: state.userlogin
});
export default connect(
    mapStateToProps,
    { loginUser }
)(Header);

My reducer code is - 我的减速器代码是-

import { SET_CURRENT_USER } from "../Actions/actions";

export default function userlogin(state = [], action = {}) {
  switch (action.type) {
    case SET_CURRENT_USER:
      return action.userlogin;
    default:
      return state;
  }
}

My action code is - 我的动作代码是-

// code to login user
export const SET_CURRENT_USER = "SET_CURRENT_USER";

export function loginUser(user) {
  return dispatch => {
    return axios
      .post("http://localhost:4000/login", {
        email: user.email,
        password: user.password
      })
      .then(res => {
        // Set token to localStorage
        localStorage.setItem("usertoken", res.data.token);
        // Decode token to get user data
        const decoded = jwt_decode(res.data.token);
        // Set current user
        dispatch(setCurrentUser(decoded));
      })
      .catch(err => {
        console.log(err.response.data.msg);
      });
  };
}

export function setCurrentUser(userlogin) {
  return {
    type: SET_CURRENT_USER,
    userlogin
  };
}

How to resolve TypeError: Cannot read property 'name' of undefined error in header.js file.. How can we make login ? 如何解决TypeError:无法读取header.js文件中未定义错误的属性“名称”。我们如何进行登录?

i guess the problem is at here: 我猜问题出在这里:

const userLink = (
            <div className="" style={{ display: 'inline-flex' }}>
                <li class="nav-item">
                    // here, because when render this const will run once and try to find the userLogin.name, but because u haven't login, it doesn't exist
                    <Link className="nav-link" to="/">{this.props.userlogin.name}</Link>

                </li>
                <li class="nav-item">
                    <a href="" onClick={this.logOut.bind(this)} className="nav-link">
                        Logout
          </a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="/">AboutUs</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="/">ContactUs</a>
                </li>
            </div>

        );

Try to create by function 尝试按功能创建

const userLink = () => (
            <div className="" style={{ display: 'inline-flex' }}>
                <li class="nav-item">

                    <Link className="nav-link" to="/">{this.props.userlogin.name}</Link>

                </li>
                <li class="nav-item">
                    <a href="" onClick={this.logOut.bind(this)} className="nav-link">
                        Logout
          </a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="/">AboutUs</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="/">ContactUs</a>
                </li>
            </div>

        );

and use it like 并像这样使用

                        {localStorage.usertoken && localStorage.usertoken != 'undefined' ? userLink() : loginRegLink}

hope this will work 希望这会工作

Based on your code I would expect state.userlogin to start off as an empty array. 根据您的代码,我希望state.userlogin从一个空数组开始。 Since you are setting your reducer to have an initial state of empty array: 由于您将减速器设置为具有空数组的初始状态:

export default function userlogin(state = [], action = {}) {}

And you link userlogin from your store to your component in here: userlogin将商店中的用户userlogin链接到此处的组件:

const mapStateToProps = state => ({
    userlogin: state.userlogin
});

However userlogin seems to be undefined instead, which makes me believe you haven't mapped your reducer inside your rootreducer correctly. 但是, userlogin似乎是未定义的,这使我相信您尚未在rootreducer内正确映射reducer。 (perhaps you used camelcase there?) (也许您在那儿使用过驼峰箱?)

If you have, then perhaps the correct store is not provided to your app or you may have changed the state of userlogin to undefined after initialisation. 如果已注册,则可能未将正确的存储提供给您的应用程序,或者您可能已在初始化后将用户userlogin状态更改为undefined

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

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