React state management: Difference between revisions

From wikinotes
No edit summary
Line 15: Line 15:
A <code>text</code> input maintains state in the browser when the user changes text.<br>
A <code>text</code> input maintains state in the browser when the user changes text.<br>
It is encouraged to mirror this within your react component, to ensure your state matches what is rendered to screen.
It is encouraged to mirror this within your react component, to ensure your state matches what is rendered to screen.
This becomes especially useful if one component refers to state from multiple child components.<br>
Using this approach to manage the render ensures that your changes are always synchronized within your parent-component's state.<br>
see https://reactjs.org/docs/lifting-state-up.html


<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
Line 54: Line 50:
</syntaxhighlight>
</syntaxhighlight>
</blockquote><!-- Mirroring Form State -->
</blockquote><!-- Mirroring Form State -->
= Lifting State Up =
<blockquote>
The previous approach becomes especially useful if one component refers to state from multiple child components.<br>
Using this approach to manage the render ensures that your changes are always synchronized within your parent-component's state.<br>
see https://reactjs.org/docs/lifting-state-up.html
Since events travel downwards, your intercepting of the rendering (and passing state as params),<br>
ensures the rendered state always updates all involved components together,<br>
ensuring your state is always consistent.
<syntaxhighlight lang="javascript">
// copied form official tutorial
class Calculator extends React.Component {
  constructor(props) {
    super(props);
    this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
    this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
    this.state = {temperature: '', unit: 'c'};
  }
  // changes to unit change the rendered `BoilingVerdict`
  // we want to make sure both 'unit' and 'temperature' are updated together
  handleCelsiusChange(temperature) {
    this.setState({unit: 'c', temperature});
  }
  handleFahrenheitChange(temperature) {
    this.setState({unit: 'f', temperature});
  }
  render() {
    const unit = this.state.unit;
    const temperature = this.state.temperature;
    const celsius = unit === 'f' ? tryConvert(temperature, toCelsius) : temperature;
    const fahrenheit = unit === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;
    return (
      <div>
        <TemperatureInput
          unit="c"
          temperature={celsius}
          onTemperatureChange={this.handleCelsiusChange} />
        <TemperatureInput
          unit="f"
          temperature={fahrenheit}
          onTemperatureChange={this.handleFahrenheitChange} />
        <BoilingVerdict
          celsius={parseFloat(celsius)} />
      </div>
    );
  }
}
</syntaxhighlight>
</blockquote><!-- Lifting State UP -->

Revision as of 23:54, 10 December 2022

HTML forms in react behave similarly to html,
but react encourages you to mirror form state changes within your react components so they can be the source-of-truth.

Documentation

official tutorial https://reactjs.org/docs/forms.html

Mirroring Form State

A text input maintains state in the browser when the user changes text.
It is encouraged to mirror this within your react component, to ensure your state matches what is rendered to screen.

// copied from official tutorial
class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name: <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>

        <input type="submit" value="Submit" />
      </form>
    );
  }
}

Lifting State Up

The previous approach becomes especially useful if one component refers to state from multiple child components.
Using this approach to manage the render ensures that your changes are always synchronized within your parent-component's state.
see https://reactjs.org/docs/lifting-state-up.html

Since events travel downwards, your intercepting of the rendering (and passing state as params),
ensures the rendered state always updates all involved components together,
ensuring your state is always consistent.

// copied form official tutorial
class Calculator extends React.Component {
  constructor(props) {
    super(props);
    this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
    this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
    this.state = {temperature: '', unit: 'c'};
  }

  // changes to unit change the rendered `BoilingVerdict`
  // we want to make sure both 'unit' and 'temperature' are updated together
  handleCelsiusChange(temperature) {
    this.setState({unit: 'c', temperature});
  }

  handleFahrenheitChange(temperature) {
    this.setState({unit: 'f', temperature});
  }

  render() {
    const unit = this.state.unit;
    const temperature = this.state.temperature;
    const celsius = unit === 'f' ? tryConvert(temperature, toCelsius) : temperature;
    const fahrenheit = unit === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;

    return (
      <div>
        <TemperatureInput
          unit="c"
          temperature={celsius}
          onTemperatureChange={this.handleCelsiusChange} />
        <TemperatureInput
          unit="f"
          temperature={fahrenheit}
          onTemperatureChange={this.handleFahrenheitChange} />
        <BoilingVerdict
          celsius={parseFloat(celsius)} />
      </div>
    );
  }
}