InfernoJS/ReactJS - Why is my for loop returning the same index in my render?

139 Views Asked by At

I have a for loop in my render function, its supposed for render 5 stars from the fontawesome library, a rating of 3 should render 3 full stars and 2 empty stars....

the issue i am having is that my iterator "i" is returning as 5 for all of them. atleast in my onClick handler. But what is really weird is that if use the same iterator variable "i" as the id or any other custom prop for the element it displays the correct 1,2,3,4, or 5. Why does this happen?

import Component from "inferno-component";
import styles from "./styles";
export default class StarRating extends Component {
constructor() {
    super();
    this.state = {
        rating: 3
    };
}

rate = rating => {
    console.log(rating);
    this.setState({
        rating: rating
    });
};
render() {
    var stars = [];
    for (var i = 0; i < 5; i++) {
        var klass = "fa fa-star";

        if (this.state.rating <= i && this.state.rating != null) {
            klass += "-o";
        }

        stars.push(
            <i
                style={styles.star}
                className={klass}
                id={i}
                aria-hidden="true"
                onClick={() => this.rate(i)}
            />
        );
    }
    return <span>{stars}</span>;
}
}
2

There are 2 best solutions below

0
On

after pulling my hair for two hours i solved the problem by reassign the value like so.

render() {
    var stars = [];
    for (var i = 0; i < 5; i++) {
        var klass = "fa fa-star";

        if (this.state.rating <= i && this.state.rating != null) {
            klass += "-o";
        }

        let id = i + 1;

        stars.push(
            <i
                style={styles.star}
                className={klass}
                id={i}
                aria-hidden="true"
                onClick={() => this.rate(id)}
            />
        );
    }
    return <span>{stars}</span>;
}

i have no idea how this worked but it did the job.

0
On

Let can be a variable I statement in the block level scope, the equivalent of each cycle I only to the current block level scope is used, I is only, so I = 1, 2, 3, 4, 5. and Var equivalent in the global scope statement I, after the I reference cycle is the same, I is always equal to 5.. You can also use a closure to cache I or use let i instead of var i in loop, like this

for (let i = 0; i < 5; i++) {
    var klass = "fa fa-star";

    if (this.state.rating <= i && this.state.rating != null) {
        klass += "-o";
    }

    stars.push(
        <i
            style={styles.star}
            className={klass}
            id={i}
            aria-hidden="true"
            onClick={() => this.rate(i)}
        />
    );
}


for (var i = 0; i < 5; i++) {
    (function(i){
       var klass = "fa fa-star";


       if (this.state.rating <= i && this.state.rating != null) {
          klass += "-o";
        }

       stars.push(
           <i
            style={styles.star}
            className={klass}
            id={i}
            aria-hidden="true"
            onClick={() => this.rate(i)}
          />
       );
    })(i)
}