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> ); }