State提升

通常,一些組件需要對同一個數(shù)據(jù)做出反應(yīng),這時我們建議將這些組件中關(guān)于這個數(shù)據(jù)的State提升至和它們距離最近的父級組件中。讓我看看該如何做到這一點:
在這個章節(jié),我們將會創(chuàng)建一個溫度計算器,根據(jù)用戶給定數(shù)值來計算水是否沸騰。
我們首先創(chuàng)建一個BoilingVerdict的組件,他接受celsius作為它的props,然后打印出水是否沸騰:

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

接下來,我們創(chuàng)建Calculator組件,它包含一個input控件,并將用戶輸入input控件的值保存在this.state.value中,它依然包含上述中的BoilingVerdict組件,用來根據(jù)用戶輸入來反映水是否沸騰:

class Calculator extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.state = {value: ''};
  }

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

  render() {
    const value = this.state.value;
    return (
      <fieldset>
        <legend>Enter temperature in Celsius:</legend>
        <input
          value={value}
          onChange={this.handleChange} />
        <BoilingVerdict
          celsius={parseFloat(value)} />
      </fieldset>
    );
  }
}

在添加一個input

我們新的要求是這樣的,現(xiàn)在需要另一個Fahrenheit溫度的輸入框,它和上述Celsius的輸入框內(nèi)的值保持同步。
首先我們可以將TemperatureInput組件從Calculator組件中抽象出來,我們添加一個scale的prop用來區(qū)分輸入框是Celsius還是Fahrenheit:

const scaleNames = {
  c: 'Celsius',
  f: 'Fahrenheit'
};

class TemperatureInput extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.state = {value: ''};
  }

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

  render() {
    const value = this.state.value;
    const scale = this.props.scale;
    return (
      <fieldset>
        <legend>Enter temperature in {scaleNames[scale]}:</legend>
        <input value={value}
               onChange={this.handleChange} />
      </fieldset>
    );
  }
}

現(xiàn)在我們的Calculator輸入框可以渲染兩個不同的輸入框了:

class Calculator extends React.Component {
  render() {
    return (
      <div>
        <TemperatureInput scale="c" />
        <TemperatureInput scale="f" />
      </div>
    );
  }
}

現(xiàn)在我們有兩個輸入框了,但是當我們給其中一個輸入框輸入內(nèi)容時,另一個輸入框的內(nèi)容不會同步改變,這不符合我們我們的需求。由于當前的溫度值被隱藏在TemperatureInput組件的內(nèi)部,所以Calculator組件無法知道當前的溫度值,BoilingVerdict組件也就無法知道知道水是否沸騰。

State提升

首先我們需要兩個函數(shù),它們分別將fahrenheit轉(zhuǎn)為Celsius,將Celsius轉(zhuǎn)為ahrenheit:

function toCelsius(fahrenheit) {
  return (fahrenheit - 32) * 5 / 9;
}

function toFahrenheit(celsius) {
  return (celsius * 9 / 5) + 32;
}

上面的兩個函數(shù)都起到轉(zhuǎn)換數(shù)值的作用。我們在另外寫一個函數(shù),這個函數(shù)接受一個字符串和一個函數(shù)作為參數(shù),返回值為一個字符串。當輸入一個非數(shù)字的值時,它返回一個空字符串:

function tryConvert(value, convert) {
  const input = parseFloat(value);
  if (Number.isNaN(input)) {
    return '';
  }
  const output = convert(input);
  const rounded = Math.round(output * 1000) / 1000;
  return rounded.toString();
}
For example, tryConvert('abc', toCelsius) returns an empty string, and tryConvert('10.22', toFahrenheit) returns '50.396'.

Next, we will remove the state from TemperatureInput.

Instead, it will receive both value and the onChange handler by props:

class TemperatureInput extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(e) {
    this.props.onChange(e.target.value);
  }

  render() {
    const value = this.props.value;
    const scale = this.props.scale;
    return (
      <fieldset>
        <legend>Enter temperature in {scaleNames[scale]}:</legend>
        <input value={value}
               onChange={this.handleChange} />
      </fieldset>
    );
  }
}

如果一些組件需要用相同的state時,只需要把這個state提升至最近的父組件內(nèi)就好。在我們的例子中,這個組件便是Calculator,我們把value和scale儲存到它里面。
我們可以把兩個輸入框的值都儲存起來,但是這種做法沒有必要。我們只要儲存最近一次的數(shù)值和scale就可以了,因為我們可以根據(jù)value 和scale來計算另一個scale的value:

class Calculator extends React.Component {
  constructor(props) {
    super(props);
    this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
    this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
    this.state = {value: '', scale: 'c'};
  }

  handleCelsiusChange(value) {
    this.setState({scale: 'c', value});
  }

  handleFahrenheitChange(value) {
    this.setState({scale: 'f', value});
  }

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

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

現(xiàn)在,無論你在哪一個輸入框輸入數(shù)值,Calculator組件中的this.state.value值和this.state.scale值都會被更新,這樣另一個沒被輸入數(shù)值的輸入框的值也會相應(yīng)的被改變。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • React版本:15.4.2**翻譯:xiyoki ** 通常幾個組件需要響應(yīng)相同的數(shù)據(jù)變化。我們建議將共享狀態(tài)提...
    前端xiyoki閱讀 822評論 0 0
  • 通常,幾個組件需要根據(jù)同一個數(shù)據(jù)變化做出響應(yīng)。我們建議將這個共享的狀態(tài)提升到他們最近的一個共用祖先。讓我們看看實際...
    莫銘閱讀 954評論 0 1
  • 最近看了一本關(guān)于學(xué)習(xí)方法論的書,強調(diào)了記筆記和堅持的重要性。這幾天也剛好在學(xué)習(xí)React,所以我打算每天堅持一篇R...
    gaoer1938閱讀 1,812評論 0 5
  • 一 一直在追的熱劇《人民的名義》,昨晚終于落下帷幕。 這部戲的故事情節(jié)折射出殘酷現(xiàn)實和復(fù)雜人性,具有極強的感染力,...
    柴門內(nèi)外閱讀 3,823評論 8 14
  • 記得去年我去寧波參加一個的婚戀課程,遇到這樣一件非常有趣的事情,我在會場認識了一個叫小孔(化名)的男孩子,這個小孔...
    魏康2019閱讀 473評論 0 0

友情鏈接更多精彩內(nèi)容