0

In Review.js, I'm trying to create a for loop so the <starIcon/> shows up multiple times based on the ratings it has. so if it has a rating of 4 stars, I would render 4 star icons in that review area. I'm trying to use for loops inside the JSX (I tried using this source: Loop-inside-react-jsx but I'm not sure how I can use the database data to change the limit of the for loop. Like the for loop condition should basically be but I'm not sure how to implement that in this project.

(for i=0; i < ({rating}-1); i++){

App.js

   export default class App extends Component {
    constructor() {
        super();
    this.state = {
        language: "english"
    };
}

render() {
    return <Fragment>
        <Overview />
        <Reviews />
    </Fragment>;
}
}

Reviews.js

function Reviews({ reviews, getReviewsQuery }) {
const length = reviews.length;
return <div className="reviews">
    <div className="reviews__header">
        <h2>Reviews</h2>
        <div className="reviews__header__stars">
            <StarIcon />
            {`(${length} reviews)`}
        </div>
    </div>
    {length ? <hr /> : ""}
    <table>
        <tbody>
            {reviews.map(r => (
                <Review key={r.id} review={r} getReviewsQuery={getReviewsQuery} />
            ))}
        </tbody>
    </table>
    <hr />
    <CreateReview getReviewsQuery={getReviewsQuery} />
</div>;
}
const getReviews = gql`
query getReviews {
    reviews {
        id
        rating
        author
        comment
        created_at
    }
}
`;

export default function ReviewsHOC(props) {
    return <Query query={getReviews}>
    {({ data }) => (
                <Reviews
            {...props}
            getReviewsQuery={getReviews}
            reviews={data && data.reviews || []} // eslint-disable-line no- 
   mixed-operators
            />
        )}
    </Query>;
    }

Review.js

export default function Review({
onDeleteReview,
review: {
    id,
    rating,
    author,
    comment,
    created_at
} = {}
}) {
return <tr className="review">
    <td className="review__info">
        <div className="review__info__author">
            {author}
        </div>
        <div className="review__info__date">
            {created_at}
        </div>
    </td>
    <td className="review__details">
        <div className="review__details__rating">
            {rating} <StarIcon />
        </div>
        <div className="review__details__comment">
            {comment}
        </div>
    </td>
    <td className="review__delete">
        <TrashIcon />
    </td>
</tr>;
}

Star.js

export default function StarIcon(props) {
    return <svg className="star-icon" viewBox="0 0 20 20" {...props}>
        <path d="M10 0L6.91 6.585 0 7.64l5 5.125L3.82 20 10 16.583 16.18 20 15 12.765l5-5.125-6.91-1.056z" fillRule="evenodd" opacity=".5" />
    </svg>;
}
Saeed Zhiany
  • 2,051
  • 9
  • 30
  • 41

1 Answers1

0

JavaScript lacks a "range" method that some other languages have which prevents that declarative programming JSX loves. I'd say the two most common options are:

a. Use the [...Array(count)] trick inside your render's return.

    <div className="review__details__rating">
        {[...Array(rating)].map(() => <StarIcon />)}
    </div>

b. Do a loop outside the render's return, pushing each star into an array (like your linked post shows)

// before you `return`
let stars = [];
for (let i = 0; i < rating; i++) {
  stars.push(<StarIcon />);
}

// ...somewhere inside render's return
    <div className="review__details__rating">
        <div>{stars}</div>
    </div>
SamVK
  • 3,077
  • 1
  • 14
  • 19
  • Small note: if `rating` is a _string_ of a number, the `for` loop will convert it, while the `...Array` trick won't (if you're only getting _one_ loop regardless of the count, that's probably why - the count need be be converted to a number first.) – SamVK Aug 19 '18 at 06:22
  • Can you explain the [...Array(count)] trick. I've never seen that before. – this_egirl Aug 20 '18 at 05:08