Giala Jefferson
Giala Jefferson

Reputation: 1929

setState did not accept dynamic value in react?

I have few states like

this.state = {
   abc1,
   abc2,
   abc3
}

Why I can't setState dynamically? like

handleDiscount = (count) => {
        this.setState({
            `abc${count}`: `!this.state.abc${count}`
        });
    }

Where count is 1 / 2 / 3.

Upvotes: 1

Views: 760

Answers (3)

Przemysław Zalewski
Przemysław Zalewski

Reputation: 3996

In order to get property of the target object please use target["string property name"] bracket syntax.

As for adding dynamic property to object you should use { ["string property name"]: value } computed property name syntax.

Your fixed code should look like this:

handleDiscount = (count) => {
  this.setState({
    [`abc${count}`]: !this.state[`abc${count}`]
  });
}

Please see working example here.

As a side note, you should really check Linus' answer regarding React's setState behavior.

Upvotes: 0

Linus Thiel
Linus Thiel

Reputation: 39261

The problem is that you are using a template string for an object property declaration; it's a syntax error. Even so, you couldn't set the template string to a variable and use that, either:

let count = 2;
let bar = `baz${count}`;
// This will set foo.bar, not foo.baz2
let foo = {
  bar: count
};

What you can do is use ES6 computed property names:

let count = 2;
let bar = `baz${count}`;
// This will set foo[<value of bar>], i.e. foo.baz2
let foo = {
  [bar]: count
};

And this also works with template strings:

let count = 2;
// This will set foo[<template string evaluated>], i.e. foo.baz2
let foo = {
  [`baz${count}`]: count
};

Also, the template string in your value is wrong. That will not evaluate the property in this.state, instead, it will be the string e.g. "!this.state.abc2". !this.state is code, not a string. You need this:

!this.state[`abc${count}`]

That being said, whenever setting React state based on the previous state, you should invoke setState with a function instead, from React docs on setState:

[...] If the next state depends on the previous state, we recommend using the updater function form, instead:

this.setState((prevState) => {
  return {counter: prevState.quantity + 1};
});

So, to summarize, this should do the trick:

handleDiscount = (count) => {
  this.setState((prevState) => {
    return { [`abc${count}`]: !prevState[`abc${count}`] }
  });
};

Upvotes: 2

Martin Dawson
Martin Dawson

Reputation: 7657

That's not how you dynamically set object properties. That's template literals.

handleDiscount = (count) => {
    this.setState({
        abc[count]: !this.state.abc[count]
    });
}

But you can't do that with array indexes anyway

Upvotes: -1

Related Questions