Reputation: 151
I am developing a rating system using ReactJS.
my code is as follows -
This is the essential code in my ReviewCard Component.
This basically returns a div where the review, username,and rating would be displayed.
starfunc(){
document.querySelector('.stars-inner').style.width = starPercentageRounded;
}
render(){
<h1 className="rating">Rating : {review.Rating}
<div class="stars-outer">
<div class="stars-inner" ></div>
</div>
</h1>
}
This is my Reviews Component It recieves reviews from DB, and for each review, maps in to ReviewCard Component
const reviewColumns = reviews ? reviews.map(review => (
<ReviewCard review={review} styles={{backgroundColor:"black"},{padding:"5px"}} />
)) : null;
The issue is that in my ReviewCard, the document.querySelector('.stars-inner') always takes the first instance of occurence. This is resulting in the only first review getting changed everytime.
Is there a way to keep the id or classname variable or unique? Or are there any other approaches i should follow?
Here is the full code
ReviewCard
class ReviewCardComponent extends React.Component {
constructor(props) {
super(props);
}
componentDidMount(){
this.starfunc();
}
starfunc() {
var {review} = this.props;
var rating = review.Rating
if(rating>5){
rating = rating/2;
}
al = 5;
const starPercentage = (rating / starTotal) * 100;
const starPercentageRounded = `${(Math.round(starPercentage / 10) * 10)}%`;
document.querySelector(id).style.width = starPercentageRounded;
}
render() {
console.log("reviewcard",this.props);
const {review} = this.props;
// The CardTitle.subtitle won't render if it's null
console.log("qwer",review.review_id);
return (
<div className="main">
<div className="fline">
<h1 className="name">{review.user_name}</h1>
<h1 className="rating">Rating : {review.Rating}
<div class="stars-outer">
<div class="stars-inner" id={review.user_name}></div>
</div>
</h1>
<button className="DeleteOptions">Options</button>
</div>
<h2 className="reviewtext">{review.review}</h2>
<hr/>
</div>
);
}
}
its CSS file
.stars-outer {
display: inline-block;
position: relative;
font-family: FontAwesome;
}
.stars-outer::before {
content: "\f006 \f006 \f006 \f006 \f006";
}
.stars-inner {
position: absolute;
top: 0;
left: 0;
white-space: nowrap;
overflow: hidden;
width: 0;
}
.stars-inner::before {
content: "\f005 \f005 \f005 \f005 \f005";
color: #f8ce0b;
}
Upvotes: 1
Views: 2858
Reputation: 26
Your approach is wrong :) You should not use querySelector as this accesses the real DOM element and not the React virtualDOM element; The approach is to use the React Refs system :
PS: Where is your return for the JSX inside the render() for your ReviewCard Component ?
Upvotes: 1
Reputation: 1179
In your case, I think the <Review />
component would look like this:
starfunc
function to arrow function to utilize this
percentage
state in each <Review />
component, by default it will be 0class ReviewCardComponent extends React.Component {
state = {
percentage: 0,
}
componentDidMount() {
this.starfunc();
}
starfunc = () => {
const { review } = this.props;
const rating = review.Rating;
const starTotal = 5;
if (rating > 5) {
rating = rating / 2;
}
const starPercentage = (rating / starTotal) * 100;
const starPercentageRounded = Math.round(starPercentage / 10) * 10;
this.setState({
percentage: starPercentageRounded || 0
})
}
render() {
const { review } = this.props;
const { percentage } = this.state;
// The CardTitle.subtitle won't render if it's null
console.log("qwer", review.review_id);
return (
<div className="main">
<div className="fline">
<h1 className="name">{review.user_name}</h1>
<h1 className="rating">
Rating : {review.Rating}
<div class="stars-outer">
<div class="stars-inner" id={review.user_name} style={{width: `${percentage}%`}}></div>
</div>
</h1>
<button className="DeleteOptions">Options</button>
</div>
<h2 className="reviewtext">{review.review}</h2>
<hr />
</div>
);
}
}
Upvotes: 2