0

I am trying to develop a discussion forum website using React, Node and MongoDB.In post object, there is nested author object and tags array. Here is sample image of a post object: State

here is the component which I am trying to render:

import React, { Component } from "react";
import http from "../services/httpService";
import { postEndPoint, repliesEndPoint } from "../config.json";

class PostPage extends Component {
  state = {
    post: [],
    replies: [],
  };
  async componentDidMount() {
    const id = this.props.match.params.id;
    const { data: post } = await http.get(postEndPoint + "/" + id);
    const { data: replies } = await http.get(repliesEndPoint + "/" + id);
    console.log(post.tags, typeof post.tags);
    this.setState({ post: post, replies: replies });
  }
  render() {
    const { post, replies } = this.state;
    return (
      <React.Fragment>
        <div className="container col-lg-8 shadow-lg p-3 mt-5 bg-body rounded">
          <h2>{post.title}</h2>
          <p className="mt-4" style={{ color: "#505050" }}>
            {post.description}
          </p>
          <div className="mt-1">
            Related Topics:
            {post.tags.map((tag) => (
              <span className="badge badge-secondary m-1 p-2">
                {(tag).name}
              </span>
            ))}
            <h6 className="mt-2">
              {post.upvotes.length} Likes {post.views} Views
            </h6>
            <div class="d-flex w-100 justify-content-between">
              <small class="mb-1">Posted by {post.author['name']}</small>
            </div>
          </div>
        </div>
      </React.Fragment>
    );
  }
}

export default PostPage;

This throws the following : TypeError: post.tags is undefined. a Similar error is throws while accessing post.upvotes and post.author

3 Answers 3

1

Since you do your http request in 'componentDidMount' a render occured at least once before. So react tried to read post.something and it was still undefined.

And even if you do it before an http request is asynchronous so be careful

You need to check that post.something is defined before you use.

Also your initialisation if confusing you initialize post as an array but you are trying to do post.title.

If post is really an array then post.map() won't crash on an empty array.

If it's an object check that is it defined correctly.

Try this as initial state

state = {
        post: {
         description:"",
         title:"",
         tags: [],
         author:[] ,
         upvotes:[] , 
         views : 0
        },
     }
Sign up to request clarification or add additional context in comments.

3 Comments

It works fine when I am use post.title, but it doesn't with post.tags
state = { post: {description:"", title:"", tags: [], author:[] , upvotes:[] , views : 0}, replies: [], }; Should be your initial state here
Also you can remove the React.fragment
1

initial state for post is {}

state = {
    post: { tags: [] },
    replies: [],
};

Comments

0

You can have a simple if condition added. So it will only loop through that if it is present. Check this.

import React, { Component } from "react";
import http from "../services/httpService";
import { postEndPoint, repliesEndPoint } from "../config.json";

class PostPage extends Component {
  state = {
    post: [],
    replies: [],
  };
  async componentDidMount() {
    const id = this.props.match.params.id;
    const { data: post } = await http.get(postEndPoint + "/" + id);
    const { data: replies } = await http.get(repliesEndPoint + "/" + id);
    console.log(post.tags, typeof post.tags);
    this.setState({ post: post, replies: replies });
  }
  render() {
    const { post, replies } = this.state;
    return (
      <React.Fragment>
        <div className="container col-lg-8 shadow-lg p-3 mt-5 bg-body rounded">
          <h2>{post.title}</h2>
          <p className="mt-4" style={{ color: "#505050" }}>
            {post.description}
          </p>
          <div className="mt-1">
            Related Topics:
            {post.tags && post.tags.map((tag) => ( // <--- map will only execute when it finds tags.
              <span className="badge badge-secondary m-1 p-2">
                {(tag).name}
              </span>
            ))}
            <h6 className="mt-2">
              {(post.upvotes && post.upvotes.length) || 0} Likes {post.views} Views // <---- These default values too will handle the case where the data isnt ready yet
            </h6>
            <div class="d-flex w-100 justify-content-between">
              <small class="mb-1">Posted by {post.author['name']}</small>
            </div>
          </div>
        </div>
      </React.Fragment>
    );
  }
}

export default PostPage;

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.