Object TypeError: Cannot read property 'title' of null

Viewed 427

I am facing a bug that I can not resolve. I am building a blogging website as a side project. Right now I am trying to render a single post, but when I try to access object properties I get an error TypeError: Cannot read property 'title' of null. I don't understand why object properties are null, event though I can print the object itself. Here are the code snippets:

This is a PostView Component that will handle rendering of the post content. I can print in the console the post object that I receive from the api but when I try access or print its properties like title, body and etc... I get an error. At first I thought I had an error in redux reducers and actions but it seems it's works fine. The states are changing and and I receive the json response. I used similar code for my other components and it worked, so I don't understand where I am making the mistake here?

import React, {useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { getPost} from 'actions/post';

//Components
import PostContent from '../Content/PostContent';

//Material Ui 
import { Grid } from '@material-ui/core';
import { useStyles } from '@material-ui/core/styles';




const PostView = ({ getPost, post: {post: { title, body, category }, loading }, match}) => {
    useEffect(() => {
        getPost(match.params.id);
    },[getPost]);
    
    //This code works
    console.log(post);
    //But this one does not
    console.log(post.title);

    return (
            <Grid container>
                <PostContent/>
            </Grid>
    )
}

PostView.propTypes = {
    getPost: PropTypes.func.isRequired,
    post: PropTypes.object.isRequired,
}

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

export default connect(mapStateToProps, { getPost })(PostView)

Here is also my actions function:

//Get Post by Id
export const getPost = (id) => async dispatch => {
    try {
        const res = await axios.get(`/api/posts/${id}`);
        dispatch({
            type: GET_POST,
            payload: res.data
        });
    }catch(err){
        dispatch({
            type: POST_ERROR,
            payload: {msg: err.response.statusText, status: err.response.status}
        });
    }

};

And the post reducer file:

import{
    GET_POSTS,
    POST_ERROR,
    UPDATE_VOTES,
    ADD_POST,
    GET_POST,
    GET_POSTS_IMAGE,
    POSTS_IMAGE_ERROR
} from '../actions/types';


const initialState = {
    posts: [],
    post: null,
    loading: true,
    status: true,
    error: {}
}



export default function(state = initialState, action) {
    const { type, payload } = action;

    switch (type) {
        case GET_POSTS:
            return{
                ...state, 
                posts: payload,
                loading: false
            };
        case POST_ERROR:
            return{
                ...state, 
                error: payload,
                loading: false
            } ;
        case UPDATE_VOTES:
            return{
                ...state,
                posts: state.posts.map(post => post._id === payload.postId ? { ...post, upVotes: payload.upVotes} : post),
                loading: false
            };  
        case ADD_POST:
            return{
                ...state,
                posts: [...state.posts, payload],
                loading: false,
                status: false
            };
        case GET_POST:
            return{
                ...state,
                post: payload,
                loading: false
            }
        default:
            return state;
    }
}

I am only learning react and redux, so any help will be appreciated.strong text

2 Answers

The error TypeError: Cannot read property 'title' of null. indicates that at some point, you are reading a property from a value of null, which will cause an error.

From your code, you are setting the initial state of post to null in the reducer, as a result, there is a moment where the prop post is null, the error originates from this moment.

post only updates to a non null value (assuming the ajax call will response with some data), and can be safely accessed after the getPost is finished.

This probably happens because your Redux initial state of post is null and you are trying to read some property of null.

Try to add some conditionals, like:

if(post && post.title) {
  console.log(post.title)
}

Or change your Redux initial state :


const initialState = {
    posts: [],
    post: {
      title: "",
      body: "",
      ...etc
    },
    loading: true,
    status: true,
    error: {}
}
Related