Dev Krishna Sadana
Dev Krishna Sadana

Reputation: 77

How to render Array stored in a Object in React?

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

Upvotes: 0

Views: 68

Answers (3)

Omkar Kulkarni
Omkar Kulkarni

Reputation: 1215

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;

Upvotes: 0

Topsy
Topsy

Reputation: 1162

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
        },
     }

Upvotes: 1

Garud Pragati
Garud Pragati

Reputation: 173

initial state for post is {}

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

Upvotes: 1

Related Questions