title: React state with calculated fields
body: <p>I have a react component, which has properties and state. Some fields of state contain input data (uplifted from input control), but there is also fields in the state that must be Calculated based on current State and Props:</p>
  
  <p><a href="https://i.stack.imgur.com/y7nG9.png" rel="noreferrer"><img src="https://i.stack.imgur.com/y7nG9.png" alt="enter image description here"></a></p>
  
  <p><strong>The question:</strong> what is the best way to update calculated fields of the state (based on other fields of state and props)?</p>
  
  <p>Ugly way to do it:</p>
  
  <pre><code>componentDidUpdate(){
      this.setState({calculatedField:calculate(this.props,this.state)})) 
  }
  </code></pre>
  
  <p>In this case I get infinite loop of updates or in the best case (if I use PureComponent) double rendering invocation.</p>
  
  <p><strong>The best solution I found so far (but still ugly)</strong>:
  Is to create a <code>calculated</code> object in state, which contains calculated fields and updated in componentWillUpdate avoiding setState:</p>
  
  <pre><code>componentWillUpdate(nextProps,nextState){
     nextState.calculated.field1=f(nextProps,nextState)
  }
  </code></pre>
  
  <p><div class="snippet" data-lang="js" data-hide="true" data-console="true" data-babel="true">
  <div class="snippet-code snippet-currently-hidden">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>class ParentComponent extends React.Component {
    constructor(props, ctx) {
      super(props,ctx)
      this.state={A:"2"}
    }
  
    render() {
      console.log("rendering ParentComponent")
      return &lt;div&gt;
        &lt;label&gt;A=&lt;input value={this.state.A} onChange={e=&gt;{this.setState({A:e.target.value})}} /&gt;&lt;/label&gt; (stored in state of Parent component)
        &lt;ChildComponent A={this.state.A} /&gt;
      &lt;/div&gt;
    }
  }
  
  class ChildComponent extends React.PureComponent {
    constructor(props,ctx) {
      super(props,ctx);
      this.state={
        B:"3",
        Calculated:{}
      }
    }
  
    render() {
      console.log("rendering ChildComponent")
      return &lt;div&gt;
        &lt;label&gt;B=&lt;input value={this.state.B} onChange={e=&gt;{this.setState({B:e.target.value})}} /&gt;&lt;/label&gt; (stored in state of Child component state)
        &lt;div&gt;
          f(A,B)=&lt;b&gt;{this.state.Calculated.result||""}&lt;/b&gt;(stored in state of Child component)
          &lt;button onClick={e=&gt;{ this.setState({Calculated:{result:new Date().toTimeString()}}) }}&gt;Set manual value&lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    }
  
    componentWillUpdate(nextProps, nextState) {
      this.state.Calculated.result = getCalculatedResult(nextProps.A, nextState.B)
    }
  
    componentWillReceiveProps(nextProps) {
      this.state.Calculated.result = getCalculatedResult(nextProps.A, this.state.B)
    }
  
    componentWillMount() {
      this.state.Calculated.result = getCalculatedResult(this.props.A, this.state.B)
    }
  }
  
  function getCalculatedResult(a,b) {
    const aNum = Number(a)||0
    const bNum = Number(b)||0;
    const result = (aNum*bNum).toString();
    return result;
  }
  
  ReactDOM.render(&lt;ParentComponent/&gt;, document.getElementById('root'));</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.development.js"&gt;&lt;/script&gt;
  &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.development.js"&gt;&lt;/script&gt;
  &lt;div id="root"&gt;&lt;/div&gt;</code></pre>
  </div>
  </div>
  </p>
  
  <p>This is also ugly solution and React does not recommended to mutate state avoiding setState. So what is right solution for that?</p>
  
  <p><strong>NOTE:</strong></p>
  
  <p>In my real application I cannot recalculate f(a,b) every single time during rendering, because it's actually complex object, so I need to cache it somehow and the best way is in the state.</p>