2

Consider the following code block :

class FormInputComponent extends React.Component {
  render() {
    return (<input type="text" value={this.props.valueHandler} onChange={this.props.changeHandler} />);
  }
}

class MyApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      rate: 50,
      inputOne: 0,
      inputTwo: 0
    }
  }

  changeHandler(key) {
    switch(key) {
      case "ONE":
        this.setState({
          inputOne: event.target.value
        });
        break;
      case "TWO":
        this.setState({
          inputTwo: event.target.value
        });
        break;
    }
  }

  getValue(key) {
    switch(key) {
      case "ONE":
        return this.state.inputOne;
        break;
      case "TWO":
        return this.state.inputTwo;
        break;
    }
  }
  render() {
    return (
      <div>
       <FormInputComponent valueHandler={this.getValue("ONE")} changeHandler={this.changeHandler.bind(this, "ONE")} />
        <br />
       <FormInputComponent valueHandler={this.getValue("TWO")} changeHandler={this.changeHandler.bind(this, "TWO")}/>
     </div>);
  }
}

ReactDOM.render(<MyApp />, document.body);

At the moment, the two input field components get their value props from whatever the user keys in the respective fields (Controlled). Here's the functionality that I want :

When the user types a value in the first input field (e.g. 30), then the second input field should instantly update with the value 30 * this.state.rate i.e. the second field should show 1500.

Next, if the user types a value in the second input field, or even edits it, the first input field should show a resulting value computed as (val/this.state.rate). So, if someone types 3500 in the second field, the resulting value (3500/50) should be shown in the first input field.

This can be achieved by computing the resulting values and storing them in two state variables. In this case, the two form field components can simply output the values of the state variables.

As per React docs, computed values should not be ideally stored in state and should be rather computed in the render method. However, in this case, how would we achieve the result without storing computed values in the state??

Here's a link to the JSBIN for the above code : https://jsbin.com/poxuqe/edit?js,console,output

3 Answers 3

1

You may try this:

class MyApp extends React.Component {

    changeHandler(key) {
      switch(key) {
         case "ONE":
           this.setState({
             inputOne: event.target.value,
             inputTwo: null
           });
           break;
      case "TWO":
         this.setState({
          inputOne:null,
          inputTwo: event.target.value
        });
          break;
    }
 }

  render() {
       let x = this.state.inputOne , y = this.state.inputTwo;
       if (x != null){
           y = x * this.state.rate;
       }
       if (y != null){
          x = y / this.state.rate;
       }

   return (
  <div>
   <FormInputComponent 
             valueHandler={x} 
             changeHandler={this.changeHandler.bind(this, "ONE")} />
    <br />
   <FormInputComponent 
      valueHandler={y} 
      changeHandler={this.changeHandler.bind(this, "TWO")} />
 </div>);

} }

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a pile. This is exactly what I had in mind as well, but wanted validation on its worth.
0

All you need is to update the state for both inputs for every change. See the updated JSBin.

https://jsbin.com/mobutetazo/1/edit?js,console,output

for sake of brevity (and less of applying mind), I've just cloned the value for second state, you can very well modify it before assigning.

Comments

0

You just need to choose one of the values to store (e.g. inputOne), and then calculate the value of inputTwo in changeHandler (before setState) and getValue (before returning).

See this JSBin: https://jsbin.com/jozokufuca/1/edit?js,console,output


Summary:

changeHandler(key) {
    switch(key) {
      case "ONE":
        this.setState({
          inputOne: event.target.value
        });
        break;
      case "TWO":
        this.setState({
          inputOne: event.target.value / this.state.rate
        });
        break;
    }
}

getValue(key) {
    switch(key) {
      case "ONE":
        return this.state.inputOne;
        break;
      case "TWO":
        return this.state.inputOne * this.state.rate;
        break;
    }
}

2 Comments

The issue with this approach is that we're calculating values while setting state, at least in one of the instances.
@shadowfax that's actually a very good thing to do. The reason react recommends not to store calculated state is so that you keep your state as simple as possible so that it can't become inconsistent with itself - I.e. you don't want to accidentally have a value in both inputs. If you store both values, you're still relying on the logic in setting the state to make sure only one value is ever set. In more complicated scenarios (e.g. with more inputs) this can be easy to get wrong.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.