3

I am new to react and redux so I am not able to solve this bug easily after doing plenty of research. I am trying to display profiles of users in a separate page in form of cards but I am getting an error:

TypeError: Cannot read property 'name' of null
ProfileItem.render
src/components/profiles/Profileitem.js:15
  12 | <div className="row">
  13 |   
  14 |   <div className="col-lg-6 col-md-4 col-8">
> 15 |     <h3>{profile.user.name}</h3>
  16 |     <p>
  17 |       {profile.status}{' '}
  18 |       {isEmpty(profile.company) ? null : (

▶ 22 stack frames were collapsed.
(anonymous function)
src/actions/userprofileAction.js:77
  74 | dispatch(profileLoading());
  75 | axios
  76 |   .get('/api/userprofile/all')
> 77 |   .then(res =>
  78 |     dispatch({
  79 |       type: GET_PROFILES,
  80 |       payload: res.data

//this is the back-end of the userprofile userprofile.js

const express = require('express');
const router = express.Router();
const mongoose=require('mongoose');
const passport=require('passport');

//loading validation after creating the userprofie valdiation
const validateProfileInput=require('../../validation/userprofile');
const validateExperienceInput=require('../../validation/experience');
//bring profile schema model

const Profile=require('../../models/Profile');

//bringing user schema model
const User=require('../../models/User');

//testing this api 
router.get('/demo', (req, res) => res.json({ msg: 'Profile Works' }));
//get request
//now need to check for the user who is trying to login
router.get('/',passport.authenticate('jwt', { session: false }),(req, res) => {
    //initializing this as empty because need to add error msg   
    const errors = {};
//fetch current user's profile and finding from profile model
//findone is a mongoose method which will find a specifc{single} thing
        Profile.findOne({ user: req.user.id }) .populate('user', ['name']).then(profile => {
           //if not found display error msg
            if (!profile) {
              errors.noprofile = 'no profile exists for this person';
              return res.status(404).json(errors);
            }
            //if found then show proifle
            res.json(profile);
          })
          .catch(err => res.status(404).json(err));
      }
    )
//to see all profiles at api/userprofile/all
    router.get('/all',(req,res)=>{
        Profile.find()
        .populate('user',['name'])
        .then(profiles=>{
            if(!profiles){
                errors.noprofile='no profiles';
                return res.status(404).json(errors);
            }
            res.json(profiles);
        })
        .catch(err=>res.status(404).json({profile:'no profiles'}));
    })
//getting profile by name
    router.get('/profilename/:profilename',(req,res)=>{
        Profile.findOne({profiename:req.params.profiename})
        .populate('user',['name'])
        .then(profile=>{
            if(!profile){
                errors.noprofile='there is no profile';
                res.status(400).json(errors);
            }
            res.json(profile);
        })
        .catch(err=>res.status(404).json(err));
    })
//getting profile by id
    router.get('/users/:users_id',(req,res)=>{
        Profile.findOne({profiename:req.params.profiename})
        .populate('user',['name'])
        .then(profile=>{
            if(!profile){
                errors.noprofile='there is no profile';
                res.status(400).json(errors);
            }
            res.json(profile);
        })
        .catch(err=>res.status(404).json(err));
    })
//post request
    router.post(
        '/',
        passport.authenticate('jwt', { session: false }),
        (req, res) => {
        const {errors,isValid}=validateProfileInput(req.body);

        //check validation
        if(!isValid){
            return res.status(400).json(errors);
        }
        //getting fields and adding in an obj
        const fields={};
        fields.user=req.user.id;

        //checking if its sent from handle
        if(req.body.profilename)fields.profilename=req.body.profilename;
        if(req.body.company)fields.company=req.body.company;
        if(req.body.location)fields.location=req.body.location;

        //so splitting skills into an array when seperated by ','
        if(typeof req.body.skills!=='undefined')
            fields.skills=req.body.skills.split(',');

//searching by id and if profile has then update

        Profile.findOne({user:req.user.id}).then(profile=>{
            if(profile){
                Profile.findOneAndUpdate({user:req.user.id},{$set:fields},{new:true})
                .then(profile=>res.json(profile));
            }
            else{
                //checking if there
                Profile.findOne({profiename:fields.profilename}).then(profile=>{
                    if(profile){
                        errors.profiename='profile already there'
                        res.status(400).json(errors);
                    }
                    //saving  and making new if not
                    new Profile(fields).save().then(profile=>res.json(profile));
                })
            }
        })
          }
        );

//post req to add exp
router.post(
    '/experience',
    passport.authenticate('jwt', { session: false }),
    (req, res) => {
      const { errors, isValid } = validateExperienceInput(req.body);

      // Check Validation
      if (!isValid) {
        // Return any errors with 400 status
        return res.status(400).json(errors);
      }
  //to add new experience
      Profile.findOne({ user: req.user.id }).then(profile => {
        const newExperience = {
          title: req.body.title,
          company: req.body.company,
          location: req.body.location,
          from: req.body.from,
          to: req.body.to,

          description: req.body.description
        };

        // Add to exp array
        profile.experience.unshift(newExperience);

        profile.save().then(profile => res.json(profile));
      });
    }
  );

  //after adding if user wants to delete the experience
  router.delete(
    '/experience/:exp_id',
    passport.authenticate('jwt', { session: false }),
    (req, res) => {
      const { errors, isValid } = validateExperienceInput(req.body);

      // Check Validation
      if (!isValid) {
        // Return any errors with 400 status
        return res.status(400).json(errors);
      }

      Profile.findOne({ user: req.user.id }).then(profile => {
        const remove=profile.experience
        .map(item=>item.id)
        .indexof(req.params.exp_id);
        //splicing out of array at index 1
        profile.experience.splice(remove,1)

        //saving
        profile.save().then(profile=>res.json(profile));
      })
      .catch(err=>res.status(404).json(err));
    }
  );


module.exports = router;

userprofileaction.js

import axios from 'axios';
import {GET_USERPROFILE,PROFILE_LOADING,GET_ERRORS,CLEAR_CURRENT_PROFILE,GET_PROFILES} from './types';

//getting current profile
export const getProfile=()=>dispatch=>{
    //dispatching loading state before req
    dispatch(profileLoading());
    axios.get('/api/userprofile')
    .then(res=>
    dispatch({
        type:GET_USERPROFILE,
        payload:res.data
    }))
    .catch(err=>
    dispatch({
        type:GET_USERPROFILE,
        payload:{}
    }))
}


 // Create Profile
export const createProfile = (profileData, history) => dispatch => {
    axios
      .post('/api/userprofile', profileData)
      .then(res => history.push('/dashboard'))
      .catch(err =>
        dispatch({
          type: GET_ERRORS,
          payload: err.response.data
        })
      );
  };
  export const addExp=(experienceData,history)=>dispatch=>{
      axios.post('/api/userprofile/experience',experienceData)
      .then(res=>history.push('/dashboard'))
      .catch(err=>dispatch({
          type:GET_ERRORS,
          payload:err.response.data
      }))
  }

  export const deleteExperience = id => dispatch => {
    axios
      .delete(`/api/userprofile/experience/${id}`)
      .then(res =>
        dispatch({
          type: GET_USERPROFILE,
          payload: res.data
        })
      )
      .catch(err =>
        dispatch({
          type: GET_ERRORS,
          payload: err.response.data
        })
      );
  };
//loading the profile
export const profileLoading=()=>{
    return{
        type:PROFILE_LOADING
    }
}
//clearing profile
export const clearcurrentprofile=()=>{
    return{
        type:CLEAR_CURRENT_PROFILE
    }
}

//getting profiles
export const getProfiles = () => dispatch => {
    dispatch(profileLoading());
    axios
      .get('/api/userprofile/all')
      .then(res =>
        dispatch({
          type: GET_PROFILES,
          payload: res.data
        })
      )
      .catch(err =>
        dispatch({
          type: GET_PROFILES,
          payload: null
        })
      );
  };

profileItem.js

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import isEmpty from '../../validation/is-empty';

class ProfileItem extends Component {
  render() {
    const { profile } = this.props;

    return (
      <div className="card card-body bg-light mb-3">
        <div className="row">

          <div className="col-lg-6 col-md-4 col-8">
            <h3>{profile.user.name}</h3>
            <p>
              {profile.status}{' '}
              {isEmpty(profile.company) ? null : (
                <span>at {profile.company}</span>
              )}
            </p>
            <p>
              {isEmpty(profile.location) ? null : (
                <span>{profile.location}</span>
              )}
            </p>
            <Link to={`/userprofile/${profile.profilename}`} className="btn btn-info">
              View Profile
            </Link>
          </div>
          <div className="col-md-4 d-none d-md-block">
            <h4>Skill Set</h4>
            <ul className="list-group">
              {profile.skills.slice(0, 4).map((skill, index) => (
                <li key={index} className="list-group-item">
                  <i className="fa fa-check pr-1" />
                  {skill}
                </li>
              ))}
            </ul>
          </div>
        </div>
      </div>
    );
  }
}

ProfileItem.propTypes = {
  profile: PropTypes.object.isRequired
};

export default ProfileItem;

Profiles.js

import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';


import ProfileItem from './ProfileItem';
import { getProfiles } from '../../actions/userprofileAction';

class Profiles extends Component {
  componentDidMount() {
    this.props.getProfiles();
  }

  render() {
    const { profiles, loading } = this.props.profile;
    let profileItems;

    if (profiles === null || loading) {
      profileItems = <h3>Profiles are loading..........</h3>;
    } else {
      if (profiles.length > 0) {

        profileItems = profiles.map(profile => (
          <ProfileItem key={profile._id} profile={profile} />
        ));
      } else {
        profileItems = <h4>No profiles found.....</h4>;
      }
    }

    return (
      <div className="profiles">
        <div className="container">
          <div className="row">
            <div className="col-md-12">
              <h1 className="display-4 text-center">Job Seeker's profiles</h1>
              <p className="lead text-center">
                Explore and get in touch with a Job seeker for free!
              </p>
              {profileItems}
            </div>
          </div>
        </div>
      </div>
    );
  }
}

Profiles.propTypes = {
  getProfiles: PropTypes.func.isRequired,
  profile: PropTypes.object.isRequired
};

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

export default connect(mapStateToProps, { getProfiles })(Profiles);

userprofileReducer.js

import {GET_USERPROFILE,PROFILE_LOADING,CLEAR_CURRENT_PROFILE,GET_PROFILES} from '../actions/types';
//import { stat } from 'fs';
const initialstate={
    //will have profile
    profile:null,
    profiles:null,
    loading:false
}

export default function(state=initialstate, action){
    switch(action.type){
        case PROFILE_LOADING:
        return{
            ...state,
            loading:true
        }
        case GET_USERPROFILE:
        return{
            ...state,
            profile:action.payload,
            loading:false
        }
        case GET_PROFILES:
        return{
            ...state,
            profiles:action.payload,
            loading:false
        }
        case CLEAR_CURRENT_PROFILE:
        return{
            ...state,
            profile:null
        }
        default:
        return state;

    }
}

6 Answers 6

4

You first need to check profile whether it’s undefined or null and only then access its keys. You will be mostly using either ternary or && operator for such cases.

Below code should work for you

  class ProfileItem extends Component {
     render() {
         const { profile } = this.props;
         return (
          <div className="card card-body bg-light mb-3">
               <div className="row">
               {profile && (
               <div className="col-lg-6 col-md-4 col-8">
                   <h3>{profile.user && profile.user.name}</h3>
                   <p>
                   {profile.status}{' '}
                   {isEmpty(profile.company) ? null : (
                   <span>at {profile.company}</span>
                    )}
                  </p>
                  <p>
                  {isEmpty(profile.location) ? null : (
                     <span>{profile.location}</span>
                   )}
                  </p>
                  <Link to={`/userprofile/${profile.profilename}`} className="btn btn-info">
          View Profile
                 </Link>
              </div>
               <div className="col-md-4 d-none d-md-block">
                 <h4>Skill Set</h4>
                 <ul className="list-group">
                    {profile.skills.slice(0, 4).map((skill, index) => (
                      <li key={index} className="list-group-item">
                       <i className="fa fa-check pr-1" />
                          {skill}
                      </li>
                    ))}
                 </ul>
                  </div>
                      )}
                </div>
            </div>
           );
        }
      }

     ProfileItem.propTypes = {
            profile: PropTypes.object.isRequired
      };

      export default ProfileItem;
Sign up to request clarification or add additional context in comments.

Comments

2

Hi it's late for the replay you can use ternary operator that would be the easiest solution for it. Thanks to @Dmytro Huz

{profile?.user?.name}

Comments

0

It looks like you try to read properly before the value is set there. Try to add a checking before calling it. Something like:

if(profile.user !== 'null'){
   ...
}

Comments

0

Try to console.log(this.props) first thing on entering render.

Usually you get such errors when initial render is done and the values in props do not exist yet.

The solution will be to check this.props and this.props.xxx, and if they are null, display a 'loading' message / a spinner.

Comments

0

As the error highlights, the bug is at following line:

<h3>{profile.user.name}</h3>

You are trying to access name of object user but problem is the object is not as you expect. Its value is null hence it does not contain a property name. You need to debug where you are populating service response in user.

Comments

0

for me i have covered in try catch block and it works

let TOKEN =""
try{
   TOKEN = JSON.parse(JSON.parse(localStorage.getItem("persist:root")).user).currentUser.accessToken ;
}
catch(err){
    console.log(err);
}
  

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.