1

I'd like to have two input numeric fields, value1 and value2 and add the values of those two fields. The sum will then be saved in this.state.sum. I also don't want to use a "submit" button. Some code:

import React, { Component } from 'react';
import addNumbers from "./components/addNumbers"

class App extends Component {
  constructor() {
    super()
    this.state = {
      value1: 10,
      value2: 3,
      sum: 13
    }
    this.handleChange = this.handleChange.bind(this)
  }

  handleChange(event) {
    //first setState call works fine
    this.setState({[event.target.name]: event.target.value})
    //call addNumbers function
    const sum = addNumbers(this.state.value1, this.statevalue2)
   //this second setState() call will lag by one step
    this.setState({sum: sum})
    console.log(newBarData)
  }

  render() {
    return (
      <div>
        <form>
        <input name="value1" type="number" placeholder="10" onBlur={this.handleChange} />
        <input name="value2" type="number" placeholder="3" onBlur={this.handleChange} />
        </form>
      </div>
    );
  }
}

export default App;

What happens is: the second setState() call won't be effected until I make a second change on the page. This is quite a common issue, but I'm not sure how to work around it. I'd like for it to be able to proc immediately after the user updates the form. In the actual use-case, there'll be some calculations based on user-input values, then visualized on a graph (plotly.js), and I want to be able to update the graph "live" after each input field change.

AndreyIto
  • 954
  • 1
  • 14
  • 35

1 Answers1

1

You can use currying to create different handler in one piece of code (see: makeHandleChange). Then you can use componentDidUpdate to check if the value of your inputs changed to update your sum state value.

import React, { Component } from 'react';
import addNumbers from "./components/addNumbers"

class App extends Component {
  state = {
    value1: 10,
    value2: 3,
    sum: 13
  }

  componentDidUpdate(lastProps, lastState) {
    const valueChanged = this.state.value1 !== lastState.value1 || this.state.value2 != lastState.value2
    if (valueChanged) {
      const sum = addNumbers(this.state.value1, this.state.value2)
      this.setState({ sum }) 
    }
  }

  makeHandleChange = id => ({ target: { value } }) => {
    this.setState({
      [`value${id}`]: value
    })
  }

  render() {
    return (
      <div>
        <form>
          <input name="value1" type="number" placeholder="10" onBlur={this.makeHandleChange(1)} />
          <input name="value2" type="number" placeholder="3" onBlur={this.makeHandleChange(2)} />
          <div>the sum is: {this.state.sum}</div>
        </form>
      </div>
    );
  }
}

export default App;
Alexandre Nicolas
  • 1,851
  • 17
  • 19
  • This answer somewhat works, but triggers en error: "Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops". I suspect it's due to the `if(true) {...}` statement in `componentDidUpdate()`, but I dunno how this would proc more than twice. – AndreyIto Mar 07 '19 at 05:45
  • I have tested my code, I can't reproduce your issue: https://jsfiddle.net/o7zgd8fs/2/ – Alexandre Nicolas Mar 07 '19 at 08:33
  • it still happens sporadically for me (possibly because the real use case has 4 inputs?). Also, I use ``` handleChange(event) { this.setState({[event.target.name]: parseFloat(event.target.value)}) } ``` Instead of your version of `makeHandleChange`; could that be an issue? – AndreyIto Mar 08 '19 at 02:27