Recent Common Components of React Learning (9)

Keywords: React calculator

Often, we encounter multiple components using the same data, and then we need to eliminate the data in each component and construct a common ancestor component to process.

I'll demonstrate it with a temperature test component.

Boiling Verdict module accepts a degree Celsius, whether the output boils or not

function BoilingVerdict(props) {
  if (props.celsius >= 100) {
    return <p>The water would boil.</p>;
  }
  return <p>The water would not boil.</p>;
}

The Calculator component is used to accept an input and keep the value in this.state.temperature at the same time, it also outputs the view of the Boiling Verdict component.

class Calculator extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.state = {temperature: ''};
  }
  handleChange(e) {
    this.setState({temperature: e.target.value});
  }
  render() {
    const temperature = this.state.temperature;
    return (
      <fieldset>
        <legend>Enter temperature in Celsius:</legend>
        <input
          value={temperature}
          onChange={this.handleChange} />
        <BoilingVerdict
          celsius={parseFloat(temperature)} />
      </fieldset>
    );
  }
}

Add another input, which used to be Celsius, and here is Fahrenheit, and of course they're synchronized.

How to achieve it?

const scaleNames = {
  c: 'Celsius',
  f: 'Fahrenheit'
};
class TemperatureInput extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.state = {temperature: ''};
  }
  handleChange(e) {
    this.setState({temperature: e.target.value});
  }
  render() {
    const temperature = this.state.temperature;
    const scale = this.props.scale;
    return (
      <fieldset>
        <legend>Enter temperature in {scaleNames[scale]}:</legend>
        <input value={temperature}
               onChange={this.handleChange} />
      </fieldset>
    );
  }
}
class Calculator extends React.Component {
  render() {
    return (
      <div>
        <TemperatureInput scale="c" />
        <TemperatureInput scale="f" />
      </div>
    );
  }
}

The above code is obviously not achievable, because each component only controls its own internal elements and is not affected by external factors.

As I said before, the unidirectionality of data can only be controlled by the parent component, and this control is based on the interface of the child component. In addition, all the external components can not be directly connected with the child component and can not deal with each other.

So the only thing that can be used is based on the parent component. Since we can't deal with it directly, we connect them through their common parent component, which is generally the most recent common ancestor component. The so-called common ancestor component's algorithmic understanding is the closest common ancestor between the two nodes of the binary tree. First node.

Then our code can be changed to the following:

//Some of the codes are omitted, and we hope that you can complete the complementary function to realize the response by yourselves.
class TemperatureInput extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
  }
  handleChange(e) {
    this.props.onTemperatureChange(e.target.value);//Key to the problem
  }
  render() {
    const temperature = this.props.temperature;
    const scale = this.props.scale;
    return (
      <fieldset>
        <legend>Enter temperature in {scaleNames[scale]}:</legend>
        <input value={temperature}
               onChange={this.handleChange} />
      </fieldset>
    );
  }
}
class Calculator extends React.Component {
  constructor(props) {
    super(props);
    this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
    this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
    this.state = {temperature: '', scale: 'c'};
  }
//Focus section
  handleCelsiusChange(temperature) {
    this.setState({scale: 'c', temperature});
  }
  handleFahrenheitChange(temperature) {
    this.setState({scale: 'f', temperature});
  }
  render() {
    const scale = this.state.scale;
    const temperature = this.state.temperature;
    const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
    const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;

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

This. props. onTemperature Change comes from outside, obviously we knew that props can acquire tag-added attributes before. We can let the parent component transfer function to the child component through the following code.

<TemperatureInput
          scale="c"
          temperature={celsius}
          onTemperatureChange={this.handleCelsiusChange} />

Let's look at the content of this.handleCelsiusChange function again. Because we bind this function to the parent component, which is not affected by the context of the child component, when we pass parameters to the function, we change the data of the state state of the parent component, which causes the parent component to re-render, thus changing the properties of the child component.

Here we need to emphasize that the state of each component is not affected by the outside world. It can only control itself. The outside world can not control it. It is just like a private property. Only functions within the class can change. The outside world can not change directly.

React is render ed only when the state of its component changes, and vice versa.

Here's a brief overview of the React processing mechanism for synchronizing code described above

  1. React detects the onchange event of the DOM element and responds by finding the handleChange function of TemperatureInput

  2. The handleChange function calls this.props.onTemperatureChange, and because we bind, React finds the parent component Calculator.

  3. When the. props. onTemperatureChange function is executed, the state state of the parent component is changed, that is, this.setState() is called.

  4. React detects the state change of the parent component Calculator, then calls its render function, which then calls TemperatureInput to update the view.

This top-down design is very helpful for us to debug programs, through React some browser plug-ins

The next article will talk about combinations and inheritance in React

Posted by mwmobley on Wed, 17 Jul 2019 17:27:35 -0700