TypeError: Cannot read property 'name' of null in react with redux

The error happens every time I leave one user and I want to enter another.

When I automatically log in, the user and the profile of the user are cleaned, so I don’t know what problem causes that every time I change the user that happens.

If I delete the “Clear_user”, when I log in and log in again the new user still has the information from the previous one until I refresh the page.

This error stops coming after I reload the page.

Imgur

components/perfil/Perfil.js

import React, {useEffect, Fragment, useState} from 'react';
import PropTypes from 'prop-types';
import {getCurrentProfile, deleteAccount} from '../../actions/profile';
import {connect} from 'react-redux';
import {logout} from '../../actions/auth';
import Spinner from '../layout/Spinner';
import {Link, withRouter} from 'react-router-dom';
import InputSelector from '../util/InputSelector';
import {getUser, editUser} from '../../actions/user';

const Perfil = ({ user:{user,loading}, getUser, editUser, deleteAccount, getCurrentProfile, profile: {profile}, logout,
    history }) => {
        const [formData, setFormData] = useState({
            name: '',
            email: '',
            avatar:''
        });

        useEffect(()=>{
            getCurrentProfile();
            getUser();
            setFormData({
                name: loading || !user.name ? '' : user.name,
                email: loading || !user.email ? '' : user.email,
                avatar: loading || !user.avatar ? '' : user.avatar,
            });
        }, [loading]);

        const {
            name,
            email,
            avatar
        } = formData;

    const hasPerfil = (
        <div>hola</div>
    );

    const hasNotPerfil = (
        <div className="text-center">
            <p>Aun no has establecido tu perfil, porfavor agrega algo de información.</p>
            <Link to="/crear-perfil" className="btn btn-primary my-1"> Crear un perfil</Link>
        </div>
      );

      const onSubmit = async e => {
        e.preventDefault();
        editUser(formData, history, true);
        }; 

      const onChange = e => setFormData({...formData,[e.target.name]: e.target.value});
    return loading && profile === null ? <Spinner/> : <Fragment>
            <div className="container">
                <div className="card user-con-col mb-4">
                    <div className="card-body">
                        <div className="d-flex align-items-center justify-content-between">
                        <h5 className="card-title mb-0"><i className="fas fa-user"></i> Usuario: {user && user.name}</h5>
                        <button onClick={logout} className="btn btn-info my-1"><i class="fas fa-sign-out-alt"></i> Salir</button>
                        </div>
                        </div>
                </div>
                <div className="card user-con-col mb-4">
                    <div className="card-body user-con-col-1">
                        <div className="container">
                        <div className="row">
                        <div className="col-md-12 text-center mb-3">
                            <div className="card">
                                    <div className="card-body">
                                    <div className="Botones">
                        <Link className="btn btn-primary my-1 mr-1" to="/perfiles"><i class="fas fa-border-all"></i> Más perfiles</Link>
                        <Link className="btn btn-primary my-1 mr-1" to="/editar-perfil"><i className="fas fa-pen"></i> Editar Perfil</Link>
                        </div>
                                    </div>
                            </div>
                        </div>
                        {profile !== null ? hasPerfil : hasNotPerfil }
                        <div className="col-md-12 mb-3">
        <div className="card">
            <div className="card-body">
                <div className="row">
                    <div className="col-md-3 d-flex align-items-center">
                    <div className="img">
                    <img className="img-fluid" src={avatar} />
                </div>
                    </div>
                <div className="col-md-9">
                <form onSubmit={e => onSubmit(e)}>
                    <div className="form-group">
                        <label><i className="fas fa-user"></i> Username</label>
                        <input 
                        type="text" 
                        name="name"
                        className="form-control" 
                        placeholder="Edita tu nombre de usuario"
                        value={name}
                        onChange={e => onChange(e)}
                        />
                    </div>
                    <div className="form-group">
                        <label><i className="fas fa-envelope"></i> Email</label>
                        <input 
                        type="text" 
                        name="email"
                        className="form-control" 
                        placeholder="Edita tu email"
                        value={email}
                        onChange={e => onChange(e)}
                        />
                    </div>
                    <div className="form-group" >
                    <label><i class="fas fa-upload"></i> Imagen De Perfil</label>
                <InputSelector/>
                </div>
                <div className="col-md-12 text-center">
                <button className="btn btn-primary btn-block"><i class="fas fa-check"></i> Guardar</button>
                </div>
                </form> 
                </div>
                </div>
            </div>
        </div>
    </div>
                        <div className="col-md-12 text-center">
                            <div className="card">
                                    <div className="card-body">
                                    <div className="Botones">
                        <button onClick={() => deleteAccount()} className="btn btn-danger my-1 mr-1"><i class="fas fa-sign-out-alt"></i> Borrar cuenta</button>
                        </div>
                                    </div>
                            </div>
                        </div>
                        </div>
                        </div>
                    </div>
                    </div>
            </div>
        </Fragment>;
};

Perfil.propTypes = {
    getCurrentProfile: PropTypes.func.isRequired,
    logout: PropTypes.func.isRequired,
    deleteAccount: PropTypes.func.isRequired,
    profile: PropTypes.object.isRequired,
    editUser:PropTypes.func.isRequired,
    getUser: PropTypes.func.isRequired,
    user: PropTypes.object.isRequired
}

const mapStateToProps = state =>({
    profile: state.profile,
    user: state.user
});

export default connect(mapStateToProps, {getCurrentProfile, getUser, editUser, logout, deleteAccount})(withRouter(Perfil));

reducer/user.js

import {GET_USER, USER_ERROR, CLEAR_USER, UPDATE_USER} from '../actions/types';

const initialState = {
    user: null,
    loading: true,
    error: {}
}

export default function(state = initialState, action) {
    const {type, payload} = action;
    switch(type){
        case GET_USER:
        case UPDATE_USER:
        return{
            ...state,
            loading:false,
            user:payload
        };
        case USER_ERROR:
            return{
            ...state,
            error:payload,
            loading: false
        };
        case CLEAR_USER:
            return {
            ...state,
            loading:false,
            user:null
        }
        default:
            return state;
    }
}

actions/user.js

import axios from 'axios';
import {setAlert} from './alert';

import {GET_USER, USER_ERROR} from './types';

//Get current users profile
export const getUser = () => async dispatch => {
    try {
        const res = await axios.get('/api/users/me');

        dispatch({
            type: GET_USER,
            payload: res.data
        });
    } catch (err) {
        dispatch({
            type:USER_ERROR,
            payload:{msg: err.response.statusText, status: err.response.status}
        });
    }
};

//Create or update user
export const editUser = (formData, history, edit = false) => async dispatch => {
    try {
        const config = {
            headers: {
                'Content-Type': 'application/json',
            }
        }

        const res = await axios.post('/api/usersedit', formData, config);

        dispatch({
            type: GET_USER,
            payload: res.data
        });

        dispatch(setAlert(edit ? 'User update' : 'User created', 'success'));

        if(!edit){
            history.push('/perfil');
        }
    } catch (err) {
        const errors = err.response.data.errors;
        if(errors){
            errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
        }
        dispatch({
            type:USER_ERROR,
            payload:{msg: err.response.statusText, status: err.response.status}
        });
    }
};

route/api/users.js

const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const config = require('config');
const {check, validationResult} = require('express-validator');
const auth = require('../../middlewares/auth');
const User = require('../../models/User');

//@Route    GET api/users
//@desc     Test route
//@access   Public
router.get('/', (req, res) => res.send('User Route'));

//@Route    GET api/users/me
//@desc     Get Current User
//@access   Private
router.get('/me', auth, async (req, res) => {
    try {
        const user = await User.findOne({_id: req.user.id});
        if(!user){
            return res.status(400).json({msg: 'There is no user'});
        }
        res.json(user);
    } catch (err) {
        console.error(err.message);
        res.status(500).send('Server Error');
    }
});

//@Route    POST api/users
//@desc     Register user
//@access   Public
router.post('/', [
    check('name', 'Name is required').not().isEmpty(),
    check('email', 'Please enter an email').isEmail(),
    check('password', 'Please enter a password with 6 or more characters').isLength({min: 6})
    ], async (req, res) => {
    const errors = validationResult(req);
    if(!errors.isEmpty()){
        return res.status(400).json({errors: errors.array()});
    }

    const {name, password, email} = req.body;

    //See if user exists
    try {
        let user = await User.findOne({email});

        if(user){
            return res.status(400).json({errors: [{msg: 'User already exists'}]});
        }

    user = new User({
        name,
        email,
        avatar:'/uploads/noImg.jpg',
        password
    });

    //Encrypt password
    const salt = await bcrypt.genSalt(10);

    user.password = await bcrypt.hash(password, salt);

    await user.save();

    //Return jsonwebtoken
    const payload = {
        user:{
            id: user.id
        }
    };

    jwt.sign(payload, config.get('jwtSecret'),{expiresIn: 360000}, (err, token) =>{
        if(err) throw err;
        res.json({token});
        }
    );

    } catch (err) {
        console.error(err.message);
        res.status(500).send('Server error');
    }

});

module.exports = router;

It seems that it is because the name object is empty or null but I can’t find a solution, please help.

Upfront note: I did not read all of your code, just the bit in your error message.

It’s not a robust solution, but you could use
!!user && !!user.name
to first check if user has a truthy value (eg. null or empty string will result in false) and then conditionally check if user.name is truthy. You’ll have to change the position of your ternary results.

name: loading || (!!user && !!user.name) ? user.name : '',

A better solution would be to validate your parameters if they

  • might be null and
  • null values are invalid

The error keeps happening. I tried changing the position of the results in the condition but the error continues.

Did you only change the positions, or did you update the predicate (bold below) as well?
(!!user && !!user.name) ? user.name : '',

The error message you’ve posted says to me that user is null at that point in execution (not user.name, which doesn’t exist at all if user is null). Null doesn’t have a name property so it throws when you try to access it.

The
!!
I suggested will mean your predicate always returns a boolean result. If you did make that change, you shouldn’t be receiving the same null value error in the location depicted in your original screenshot. If the error message has changed, please let us know.

forgive the delay.
Imgur