Charas
Charas

Reputation: 1827

ReactJS for loop create buttons and set variable according to the integer in the loop

I am new to ReactJS, I am trying to create 10 buttons with for loops, and set a variable with the integer from the for loop, however the function setMqty(i) always returns 11 for all the buttons. What is the correct way for doing this?

  var qtyButtons = [];
  for(var i = 1; i < 11; i++) {
    qtyButtons.push(<div
        onClick={(btn) => {qtyBtnToggle(btn);setMqty(i); }}
    >
      {i}
    </div>)
  }

Thank you in advance.

Upvotes: 1

Views: 71

Answers (3)

3limin4t0r
3limin4t0r

Reputation: 21130

The main issue here has to do with scoping. Let me reduce your example to a more minimal example:

var qtyCallbacks = [];
for (var i = 1; i < 11; i++) {
  qtyCallbacks.push(() => console.log(i));
}

for (const callback of qtyCallbacks) {
  callback();
}

What's going wrong here? Why is it only logging 11 and not 1-10?

The issue is that a variable defined with var are scoped to the nearest function or globally if not in a function. So what does this mean?

It means that each iteration in your for loop refers to the same i. This isn't an issue if you directly use i.

for (var i = 1; i < 11; i++) {
  console.log(i); // logs 1-10
}

However it does become an issue if you refer to i in code that is executed at a later point. The reason the initial snippet only logs 11 is because all the callbacks are created, each one referring to the same i. So when you evoke each callback after the for-loop is complete, they will all refer to the current value (which is 11).

for (var i = 1; i < 11; i++) {
}

console.log(i); // logs 11
// so if we invoke the callbacks here they all log 11

So how do you solve this issue? The simplest solution is probably to replace var with let. let will create a new variable for each for-iteration. Meaning that each created callback will refer to their own i and not a shared i. This also means that you cannot access i outside of the for-loop.

var qtyCallbacks = [];
for (let i = 1; i < 11; i++) {
  qtyCallbacks.push(() => console.log(i));
}

for (const callback of qtyCallbacks) {
  callback();
}

console.log(i); // expected error, `i` is only available within the for-block

Upvotes: 1

Ritchi
Ritchi

Reputation: 311

I think using a map function is the correct way for doing it.

Therefore, you must generate a range of numbers our any element to be able to perform a map function.

So if i was in your place i would have do it like:

const [mqty, setMqty] = useState(0);

// ...

const qtyButtons = Array(10).fill().map((_, i) => {
  const value = parseInt(i);

  return (
    <button onClick={handleClick(value)}>
      {value}
    </button>
  );
});

// ...
// The trick here is that function returning another function, beware of that
const handleClick = (i) => () => {
  setMqty(i);
};

Upvotes: 1

pranit
pranit

Reputation: 168

I am guessing setMqty is a state.Can you try

setMqty(currentValue=> currentValue+1)

Upvotes: 0

Related Questions