Skip to content
Advertisement

Conditional rendering in React based on current component state

I am struggling with figuring out how to implement conditional rendering in React. Basically, what I want to do is this: if there is a reviewResponse in the reviewResponses array, I no longer want to render the reviewResponseForm. I only want to render that ReviewResponse. In other words, each review can only have one response in this app. I am not sure what I am doing wrong when trying to implement this logic. I know I need to implement some kind of conditional statement saying if the length of my reviewResponses array is greater than 0, I need to render the form. Otherwise, I need to render that reviwResponse. Every statement I have written has not worked here. Does anybody have a suggestion? Here is my code so far:

My review cardDetails component renders my ReviewResponseBox component and passed the specific reviewId as props:

import React from "react";
import { useLocation } from "react-router-dom";
import StarRatings from "react-star-ratings";
import ReviewResponseBox from "../ReviewResponse/ReviewResponseBox";

const ReviewCardDetails = () => {
  const location = useLocation();
  const { review } = location?.state; // ? - optional chaining

  console.log("history location details: ", location);
  return (
    <div key={review.id} className="card-deck">
      <div className="card">
        <div>
          <h4 className="card-title">{review.place}</h4>
          <StarRatings
            rating={review.rating}
            starRatedColor="gold"
            starDimension="20px"
          />
          <div className="card-body">{review.content}</div>
          <div className="card-footer">
            {review.author} - {review.published_at}
          </div>
        </div>
      </div>
      <br></br>
       {/*add in conditional logic to render form if there is not a response and response if there is one*/} 
    <ReviewResponseBox review_id={review.id}/>

    </div>
  );
};

export default ReviewCardDetails;

Then eventually I want this component, ReviewResponseBox, to determine whether to render the responseform or the reviewresponse itself, if it exists already.

import React from 'react';
import ReviewResponse from './ReviewResponse';
import ReviewResponseForm from './ReviewResponseForm';

class ReviewResponseBox extends React.Component {
  constructor() {
    super()

    this.state = {
      reviewResponses: []
    };
  }
  
  render () {
    const reviewResponses = this.getResponses();
    const reviewResponseNodes = <div className="reviewResponse-list">{reviewResponses}</div>;
   

    return(
      <div className="reviewResponse-box">
        <ReviewResponseForm addResponse={this.addResponse.bind(this)}/>
       
        <h3>Response</h3>
        {reviewResponseNodes}
        
      </div>  
        
    );
  } 
  

  addResponse(review_id, author, body) {
    const reviewResponse = {
      review_id,
      author,
      body
    };
    this.setState({ reviewResponses: this.state.reviewResponses.concat([reviewResponse]) }); // *new array references help React stay fast, so concat works better than push here.
  }
   
  
  
  getResponses() {    
    return this.state.reviewResponses.map((reviewResponse) => { 
      return (
        <ReviewResponse 
          author={reviewResponse.author} 
          body={reviewResponse.body} 
          review_id={this.state.review_id} />
      ); 
    });
  }

  
  
}
export default ReviewResponseBox;

Here are the ReviewResponseForm and ReviewResponse components:

import React from "react";

class ReviewResponseForm extends React.Component {
  render() {
    return (
      <form className="response-form" onSubmit={this.handleSubmit.bind(this)}>
        <div className="response-form-fields">
          <input placeholder="Name" required ref={(input) => this.author = input}></input><br />
          <textarea placeholder="Response" rows="4" required ref={(textarea) => this.body = textarea}></textarea>
        </div>
        <div className="response-form-actions">
          <button type="submit">Post Response</button>
        </div>
      </form>
    );
  }
  
  handleSubmit(event) { 
    event.preventDefault();   // prevents page from reloading on submit
    let review_id = this.review_id
    let author = this.author;
    let body = this.body;
    this.props.addResponse(review_id, author.value, body.value);
  }
} 

export default ReviewResponseForm;
import React from 'react';

class ReviewResponse extends React.Component {
    render () {
      return(
        <div className="response">
          <p className="response-header">{this.props.author}</p>
          <p className="response-body">- {this.props.body}</p>
          <div className="response-footer">
            </div>
        </div>
      );
    }
  
  }
  export default ReviewResponse;
  

Any advice would be helpful, thank you.

Advertisement

Answer

If I understand your question correctly, you want to render ReviewResponseForm if the this.state.reviewResponses state array is empty.

Use the truthy (non-zero)/falsey (zero) array length property to conditionally render either UI element.

render () {
  const reviewResponses = this.getResponses();
  const reviewResponseNodes = <div className="reviewResponse-list">{reviewResponses}</div>;


  return(
    <div className="reviewResponse-box">
      {reviewResponses.length 
        ? (
          <>
            <h3>Response</h3>
            {reviewResponseNodes}
          </>
        )
        : (
          <ReviewResponseForm addResponse={this.addResponse.bind(this)}/>
        )}
    </div>  
    
  );
} 
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement