Zhady
Zhady

Reputation: 33

Update/set state dynamically in reactjs

I am new to reactjs and used to load/update data through javascript/jquery.

In my example I've got 3 buttons. Whenever I click one one button, I would like to update the text above. Right now, I am using same state for the counter. Can't you somehow get the current divs ID - and update the state inside it?

I could just change the state to 3 different states. But the reason why I am not doing this is if I ever want to load something dynamically they probably have the same state?

jsfiddle: https://jsfiddle.net/t9am76fs/1/

constructor(props) {
    super(props);

    this.state = {
        count: 0,
    };
}
incrementCounter = (value) => {
    this.setState({ count: this.state.count + value })
};

render() {
    return (
        <div>
            <div id='div1'>
                  <p>You clicked {this.state.count} times</p>
                  <button onClick={() => this.incrementCounter(1)}>+1</button>
            </div>

            <div id='div2'>
                  <p>You clicked {this.state.count} times</p>
                  <button onClick={() => this.incrementCounter(1)}>+1</button>
            </div>

            <div id='div3'>
                  <p>You clicked {this.state.count} times</p>
                  <button onClick={() => this.incrementCounter(1)}>+1</button>
            </div>
        </div>
    );
}

Thanks

Upvotes: 3

Views: 680

Answers (3)

Domino987
Domino987

Reputation: 8774

You can also do it by giving the input names and accessing these via the event.target.name and use that to update state depending on the given name.

class Counter extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            count: [0,0,0]
        };
    }
    incrementCounter = (event) => {
        const updatedCount = [...this.state.count] // Create a shallwo copy
        updatedCount[Number(event.target.name)]++
        this.setState({ count: updatedCount })
    };

    render() {
    const [count1, count2, count3] = this.state.count;
        return (
            <div>
                <div id='div1'>
                      <p>You clicked {count1} times</p>
                      <button name='0' onClick={this.incrementCounter}>+1</button>
                </div>

                <div id='div2'>
                      <p>You clicked {count2} times</p>
                      <button name='1' onClick={this.incrementCounter}>+1</button>
                </div>
                
                <div id='div3'>
                      <p>You clicked {count3} times</p>
                      <button name='2' onClick={this.incrementCounter}>+1</button>
                </div>
            </div>
        );
    }
}

ReactDOM.render(<Counter />, document.querySelector("#app"));	
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>

Upvotes: 2

perellorodrigo
perellorodrigo

Reputation: 536

It looks like you want to render dynamic elements, like you would do if you gather data from an API from example.

What I would do is to group the data you need dynamically into an array of objects, and you can keep the counter for each of those objects inside the object itself.

In the example below. You map the array and each onClick will update its own object counter. This way you don't need to explicitly write the state for every single element.

This is just a sample and you can improve it later:

const dynamicDivsInfo = [
  { name: "Example", id: "div1", count: 0 },
  { name: "Example 2", id: "div2", count: 0 }
];

class Example extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      divs: [...dynamicDivsInfo]
    };
  }
  incrementCounter = (value, index) => {
    const divs = [...this.state.divs];
    divs[index].count += value;
    this.setState({ divs });
  };

  render() {
    return (
      <div>
        {this.state.divs.map((element, index) => {
          return (
            <div id={element.id}>
              <p>
                You clicked {element.name}: {element.count} times
              </p>
              <button onClick={() => this.incrementCounter(1, index)}>
                +1
              </button>
            </div>
          );
        })}
      </div>
    );
  }
}

Here is a code sandbox example: https://codesandbox.io/s/goofy-night-1hfoc?file=/src/App.js:244-1086

Upvotes: 1

Michael
Michael

Reputation: 1872

Try it:

class Counter extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            count1: 0,
            count2: 0,
            count3: 0,
        };
    }
    incrementCounter = (type) => {
        this.setState({ [type]: this.state[type] + 1 })
    };

    render() {
        return (
            <div>
                <div id='div1'>
                      <p>You clicked {this.state.count1} times</p>
                      <button onClick={() => this.incrementCounter('count1')}>+1</button>
                </div>

                <div id='div2'>
                      <p>You clicked {this.state.count2} times</p>
                      <button onClick={() => this.incrementCounter('count2')}>+1</button>
                </div>
                
                <div id='div3'>
                      <p>You clicked {this.state.count3} times</p>
                      <button onClick={() => this.incrementCounter('count3')}>+1</button>
                </div>
            </div>
        );
    }
}

ReactDOM.render(<Counter />, document.querySelector("#app"));	

Upvotes: 1

Related Questions