2

I have tried other answers to questions listed on here and they do not work. What am i doing different?

I have an app where I want to list a topic that has a list/array of comments associated with it. When a user clicks on the "add topic" link, the user will then see a random topic generated with past comments associated with it and also an opportunity to add a new comment. I can print out the topic but I can not print out the comments. I can even print out the comments in the console but not on the page.

The error says the comments are undefined. What am I doing wrong?

Here is the code:

topic.js

import React, { Component } from "react";
import axios from "axios";
import { withRouter } from "react-router-dom";
import { createComment, listTopicWithComments } from "../util/APIUtils";
import "./Topic.css";
import TopicComp from "../components/TopicComp";
import { Form, Input, Button, Icon, Select, Col, notification } from "antd";
const URL = "http://localhost:8080/api/auth/randomtopic";
const URL2 = "http://localhost:8080/api/auth/topic/";
const Option = Select.Option;
const FormItem = Form.Item;
const { TextArea } = Input;

class Topic extends Component {
  constructor(props) {
    super(props);
    this.state = {
      topic: {},
      comment: {
        text: ""
      }
    };

    this.handleSubmit = this.handleSubmit.bind(this);
    this.isFormInvalid = this.isFormInvalid.bind(this);
    this.handleCommentChange = this.handleCommentChange.bind(this);
    //this.listTopicWithComments=this.listTopicWithComments.bind(this);
  }
  handleSubmit(event) {
    event.preventDefault();
    const commentData = this.state.comment.text;
    const commentTopicid = this.state.topic.id;
    console.log("commentdata:", commentData);
    console.log("topicid: ", commentTopicid);

    createComment(commentData, commentTopicid)
      .then(response => {
        console.log("response comment: ", response.data);
        this.props.history.push("/");
      })
      .catch(error => {
        if (error.status === 401) {
          this.props.handleLogout(
            "/login",
            "error",
            "You have been logged out. Please login and choose randome topic."
          );
        } else {
          notification.error({
            message: "Social-J App",
            description: error.message || "Sorry, something went wrong."
          });
        }
      });
    listTopicWithComments(commentTopicid).then(response => {
      console.log("topic comment", response.data);
      this.props.history.push("/");
    });
  }

  validateComment = commentText => {
    if (commentText.length === 0) {
      return {
        validateStatus: "error",
        errorMsg: "Please enter your comment!"
      };
    } else if (commentText.length > 150) {
      return {
        validateStatus: "error",
        errorMsg: `Comment is too long (Maximum 150 characters 
        allowed)`
      };
    } else {
      return {
        validateStatus: "success",
        errorMsg: null
      };
    }
  };

  handleCommentChange(event) {
    const value = event.target.value;
    this.setState({
      comment: {
        text: value,
        ...this.validateComment(value)
      }
    });
  }

  componentDidMount() {
    if (this.props.isAuthenticated) {
      axios
        .get(URL)
        .then(response => {
          console.log("response", response.data);
          this.setState({ topic: response.data });
        })
        .catch(err => {
          console.log(err);
        });
    }
  }

  isFormInvalid() {
    if (this.state.comment.validateStatus !== "success") {
      return true;
    }
  }

  render() {
    //console.log("URL used: ",URL);
    //console.log("new topic",this.state.topic.id);
    //console.log("new topic",this.state.topic.topic);

    const topicId = this.state.topic.id;
    const uDate = this.state.topic.expirationDateTime;
    const oldComments = this.state.topic.comments;
    console.log("topicid: ", topicId);
    console.log("date: ", uDate);
    console.log("oldcomments: ", oldComments);

    //return nComment;
    return (
      <div className="new-comment-container">
        <h1 className="page-title">{this.state.topic.topic}</h1>
        <div>
          {this.state.topic.comments.map(comment => {
            return <div key={comment.id}>{comment.comment}</div>;
          })}
        </div>
        <div className="new-comment-content">
          <Form
            onSubmit={this.handleSubmit}
            className="create- 
                  comment-form"
          >
            <FormItem
              validateStatus={this.state.comment.validateStatus}
              help={this.state.comment.errorMsg}
              className="comment-form-row"
            >
              <TextArea
                placeholder="Enter comment"
                style={{
                  fontSize: "16px"
                }}
                autosize={{ minRows: 3, maxRows: 6 }}
                name="comment"
                value={this.state.comment.text}
                onChange={this.handleCommentChange}
              />
            </FormItem>
            <FormItem className="comment-form-row">
              <Button
                type="primary"
                htmlType="submit"
                size="large"
                disabled={this.isFormInvalid()}
                className="create-comment-form-button"
              >
                Add Comment
              </Button>
            </FormItem>
          </Form>
        </div>
        <div>hi</div>
      </div>
    );
  }
}
export default withRouter(Topic);

This is the Error. TypeError:

this.state.topic.comments is undefined render client/src/components/Topic.js:134

         131 |  <div className="new-comment-container">
         132 |  <h1 className="page-title">{this.state.topic.topic}</h1>
         133 |  <div>
       > 134 |     {this.state.topic.comments.map(comment =>{
         135 |         return <div key={comment.id}>
         136 |         {comment.comment}
         137 | </div>

1 Answer 1

2

You are trying to use this.state.topic.comments before topic has been loaded.

You could e.g. set topic to null initially and return null from render until it has been set.

Example

class Topic extends Component {
  constructor(props) {
    super(props);
    this.state = {
      topic: null,
      comment: {
        text: ""
      }
    };

    this.handleSubmit = this.handleSubmit.bind(this);
    this.isFormInvalid = this.isFormInvalid.bind(this);
    this.handleCommentChange = this.handleCommentChange.bind(this);
  }

  render() {
    const { topic } = this.state;

    if (topic === null) {
      return null;
    }

    // ...
  }
}
Sign up to request clarification or add additional context in comments.

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.