3
votes

After get the comments array from post component and pass it to comments component the logs start to show the error in the screenshot below

enter image description here

the components are:

import React, { Component } from "react";
import axios from "axios";

import Comments from "../components/comments";

    class Article extends Component {
        constructor(props) {
            super(props);

            this.state = {
                title: "",
                error: "",
                comment: ""
            };
        }

        componentDidMount() {

            this.getComments();
        }


        getComments = () => {
            const {
                match: { params }
            } = this.props;

            return axios
                .get(`/articles/${params.id}/comments`, {
                    headers: {
                        Accept: "application/json",
                        "Content-Type": "application/json",

                    }
                })
                .then(response => {
                    return response.json();
                })
                .then(response => this.setState({ comments: response.comments }))
                .catch(error =>
                    this.setState({
                        error
                    })
                );
        };



        render() {
            return (
                <div>
                    {this.state.title}
                    <div>
                        <h2>Comments</h2>
                        <Comments
                            getComments={this.getComments}

                        />
                    </div>

                </div>
            );
        }
    }

    export default Article;

and Comments component

import React, { Component } from "react";
import PropTypes from "prop-types";
import Comment from "./comment";
import axios from "axios";

import Article from "../screens/article";

class Comments extends Component {
  constructor(props) {
    super(props);
    this.state = {
      comments: [],

      comment: "",
      error: ""
    };

    this.load = this.load.bind(this);

    this.comment = this.comment.bind(this);
  }

  componentDidMount() {
    this.load();
  }

  load() {
    return this.props.getComments().then(comments => {
      this.setState({ comments });

      return comments;
    });
  }

  comment() {
    return this.props.submitComment().then(comment => {
      this.setState({ comment }).then(this.load);
    });
  }

  render() {

    const { comments } = this.state;

    return (
      <div>
        {comments.map(comment => (
          <Comment key={comment.id} commment={comment} />
        ))}
      </div>
    );
  }
}



export default Comments;

so, I've tried to pass it by props, and set the state on comments component. and instead of use just comments.map I've tried to use this.state but show the same error in the logs. So, someone please would like to clarify this kind of issue? seems pretty usual issue when working with react.

3
Hi @JonasWilms, yes. should be contain the comments array - user9157191

3 Answers

0
votes

If an error occurs you do:

  .catch(error =>  this.setState({ error  }) );

which makes the chained promise resolve to undefined and that is used as comments in the Comments state. So you have to return an array from the catch:

 .catch(error => {
   this.setState({ error });
   return [];
 });

Additionally it woupd make sense to not render the Comments child at all if the parents state contains an error.

0
votes

The other way is checking whether it’s an array and if so check it’s length and then do .map. You have initialized comments to empty array so we don’t need to check whether it’s an array but to be on safer side if api response receives an object then it will set object to comments so in that case comments.length won’t work so it’s good to check whether it’s an array or not.

Below change would work

  <div>
    {Array.isArray(comments) && comments.length>0 && comments.map(comment => (
      <Comment key={comment.id} commment={comment} />
    ))}
  </div>
-1
votes

The first time the comments component renders there was no response yet so comments were undefined.

    import React, { Component } from "react";
import PropTypes from "prop-types";
import Comment from "./comment";
import axios from "axios";

import Article from "../screens/article";

class Comments extends Component {
  constructor(props) {
    super(props);
    this.state = {
      comments: [],

      comment: "",
      error: ""
    };

    this.load = this.load.bind(this);

    this.comment = this.comment.bind(this);
  }

  componentDidMount() {
    this.load();
  }

  load() {
    return this.props.getComments().then(comments => {
      this.setState({ comments });

      return comments;
    });
  }

  comment() {
    return this.props.submitComment().then(comment => {
      this.setState({ comment }).then(this.load);
    });
  }

  render() {

    const { comments } = this.state;

    if (!comments) return <p>No comments Available</p>;

    return (
      <div>
        {comments.map(comment => (
          <Comment key={comment.id} commment={comment} />
        ))}
      </div>
    );
  }
}



export default Comments;