انتقال state به بالا
اغلب، تغییر یک داده، منجر به واکنش چندین کامپوننت میشود. پیشنهاد ما انتقال state مشترک میان آنها به نزدیکترین کامپوننت بالادستی است که آنهار در بر دارد. بیایید با هم ببینیم در عمل چگونه کار میکند. در این بخش، ما یک دماسنج میسازیم که محاسبه میکند در دمای داده شده به آن آب جوش آمده است یا خیر.
ما با کامپوننتی شروع خواهیم کرد که به آن BoilingVerdict میگویند.
این کامپوننت celsius را به عنوان prop دریافت میکند و درصورت کافی بودن آن برای به جوش آوردن آب آن را چاپ میکند.
function BoilingVerdict(props) {
  if (props.celsius >= 100) {
    return <p>The water would boil.</p>;  }
  return <p>The water would not boil.</p>;}سپس کامپوننتی به عنوان Calculator ایجاد میکنیم.
که آن یک <input> را رندر میکند که به شما اجازه میدهد دما را وارد کنید و مقدار آن را در this.state.temperature نگهداری کنید.
به علاوه  BoilingVerdict را برای مقدار اولیه input رندر میکند.
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>
    );
  }
}افزودن input دوم
نیاز جدید ما این است که برای ورودی سلیسوس یک مقدار فارنهایت فراهم کنیم. که با هم همگام باشند.
ما میتوانیم با استخراج کردن کامپوننت TemperatureInput از Calculator شروع کنیم.
یک prop جدید به نام scale به آن اضافه میکنیم که میتواند "c" یا "f" باشد.
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>
    );
  }
}ما حالا میتوانیم Calculator را در دو دمای مجزا رندر کنیم.
class Calculator extends React.Component {
  render() {
    return (
      <div>
        <TemperatureInput scale="c" />        <TemperatureInput scale="f" />      </div>
    );
  }
}ما در حال حاضر دو input داریم که اگر شما در یکی از آنها دما وارد کنید، دیگری آپدیت نمیشود. که با نیاز ما در تناقض است: ما میخواهیم با هم همگام باشند.
همچنین نمیتوانیم BoilingVerdict از Calculator را نمایش دهیم.
Calculator دمای کنونی را نمیداند زیرا در TemperatureInput مخفی است.
نوشتن تابع تبدیل
در ابتدا ما دو تابع مینویسیم که دما را از سیلسیوس به فارنهایت و برعکس تبدیل کند:
function toCelsius(fahrenheit) {
  return (fahrenheit - 32) * 5 / 9;
}
function toFahrenheit(celsius) {
  return (celsius * 9 / 5) + 32;
}این دو تابع اعداد را تبدیل میکنند. ما دو تابع خواهیم نوشت که temperature از جنس string و تابع تبدیل را به عنوان آرگومان دریافت میکند و یک string برمیگرداند. ما از آن برای محاسبه مقدار یک input باتوجه به مقدار input دیگر استفاده میکنیم.
که این روی مقدار نامعتبر temperature، string خالی برمیگرداند و خروجی را تا سه رقم اعشار رند میکند:
function tryConvert(temperature, convert) {
  const input = parseFloat(temperature);
  if (Number.isNaN(input)) {
    return '';
  }
  const output = convert(input);
  const rounded = Math.round(output * 1000) / 1000;
  return rounded.toString();
}برای مثال، tryConvert('abc', toCelsius)، string خالی برمیگرداند و tryConvert('10.22', toFahrenheit)، string '50.396' را برمیگرداند.
انتقال state به بالا
در حال حاضر، هر دو کامپوننت TemperatureInput به صورت جداگانه مقادیر خود را در state محلی خود نگهداری میکنند.
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;    // ...  گرچه، میخواهیم که این دو input با هم همگام باشند. هنگامی که مقدار input سلیسیوس را بهروز میکنیم، مقدار تبدیل شده فارنهایت نیز باید منعکس شود، و برعکس.
در React ، به اشتراک گذاری state به صورت حرکت دادن آن به نزدیکترین جد کامپوننتی که به آن نیاز دارد است. به این “انتقال state به بالا” گفته میشود. ما state محلی TemperatureInputرا پاک میکنیم و به جای آن در Calculator میبریم.
اگر Calculator state به اشتراک گذاشته شده را ازآن خود کند، به “منبع حقیقت” برای هر دو input تبدیل میشود. و اینها را برای داشتن مقادیر نامتناقض آگاه میکند. از آنجایی که propهای هر دو کامپوننت TemperatureInput از کامپوننت پدری یکسان به اسم Calculator میآیند، هر دو input همیشه با هم همگام هستند.
بیایید قدم به قدم ببینیم که چگونه کار میکند.
اول، this.state.temperature را با مقدار this.props.temperature در کامپوننت TemperatureInput جایگزین میکنیم. فعلا فرض میکنیم که this.props.temperature قبلا وجود داشته است، گرچه در آینده باید آن را به Calculator انتقال بدهیم:
  render() {
    // قبلا : const temperature = this.state.temperature;
    const temperature = this.props.temperature;    // ...ما میدانیم که propsها فقط خواندنی هستند. هنگامی که temperature در state محلی بود، TemperatureInput فقط میتوانست this.setState() را برای تغییرش صدا کند. گرچه حالا temperature از پدر به عنوان props میآید TemperatureInput هیچ کنترلی روی آن ندارد.
در React این مسله معمولا با تبدیل کامپوننت به “کنترل شده” حل میشود. درست مثل DOM که <input> prop، value و onChange را قبول میکند، پس TemperatureInput شخصی ما نیز میتواند propهای temperature و onTemperatureChange را از پدر خودش Calculator قبول کند. 
حالا، وقتی که TemperatureInput بخواهد دمای خودش را بهروز رسانی کند، میتواند this.props.onTemperatureChange را صدا کند.
  handleChange(e) {
    // قبلا : this.setState({temperature: e.target.value});
    this.props.onTemperatureChange(e.target.value);    // ...توجه:
propهای
temperatureیاonTemperatureChangeهیچ مفهوم خاصی در کامپوننت شخصی ندارند. ما هر چه بخواهیم میتوانیم نامگذاری کنیم, مانندvalueوonChangeکه قراردادی، مرسوم هستند.
propهای onTemperatureChange و temperature توسط پدرشان فراهم خواهند شد. که تغییرات را در state محلی خودش رسیدگی میکند، سبب رندر مجدد جفت inputها میشود. خیلی زود به پیادهسازی Calculator نگاه میاندازیم.
قبل از اینکه به تغییرات داخل Calculator بپردازیم، بیایید تغییراتی که روی TemperatureInputدادهایم را جمع بندی کنیم. ما state محلی را از آن پاک کردیم، و به جای خواندن از this.state.temperature، اکنون از this.props.temperature میخوانیم .وقتی میخواهیم تغییری بدهیم به جای صدا کردن this.setState() اکنون this.props.onTemperatureChange() را صدا میکنیم، که توسط Calculator فراهم شده است.
class TemperatureInput extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
  }
  handleChange(e) {
    this.props.onTemperatureChange(e.target.value);  }
  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>
    );
  }
}حالا بیایید به کامپوننت Calculator برگردیم.
ما مقادیر temperature و scale inputها را در state داخلیاش ذخیره میکنیم. این همان stateای هست که از inputها “به بالا” انتقال دادیم که برای هر دوی آنها به عنوان “منبع حقیقت” عمل میکند. این کمترین تمثالی از تمام دادهای است که برای رندر input به آن نیاز  داریم .
برای مثال، اگر ما ۳۷ را در input سلیسیوس وارد کنیم، state کامپوننت Calculator میشود:
{
  temperature: '37',
  scale: 'c'
}اگر بعدا فارنهایت را به ۲۱۲ تغییر دهیم، state Calculator خواهد بود:
{
  temperature: '212',
  scale: 'f'
}ما میتوانیم که مقدار هر دو input را ذخیره کنیم ولی به نظر میرسد که ضروری نباشد.
همین کافیست که مقدار input که آخرین بار تغییر کرده به همراه scale که نماینده آن است ذخیره شود. سپس میتوانیم مقدار input را به تنهایی با temperature و scale استنتاج کنیم.
inputها با هم همگام هستند زیرا مقادیرشان از state یکسانی محاسبه میشود.
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'};  }
  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>
    );
  }
}حالا اهمیتی ندارد که کدام یک از inputها را ویرایش کنید، this.state.temperature و this.state.scale در Calculator بهروز رسانی میشوند. یکی از inputها که مقدار بگیرد هر ورودی کاربر محفوظ میشود و input دیگر با توجه به آن مقدارش محاسبه میشود.
بیایید آنچه در ویرایش input اتفاق میافتد را با هم جمعبندی کنیم.
- React تابعی که به عنوان onChangeروی DOM<input>مشخص شده است را صدا میکند. در این مورد متدhandleChangeدر کامپوننتTemperatureInputمیباشد.
- متد handleChangeدر کامپوننتTemperatureInput،this.props.onTemperatureChange()را با مقدار جدیدش صدا میزند. که propاش, شاملonTemperatureChangeمیباشد، که توسط کامپوننت پدر که همانCalculatorاست فراهم شده است.
- قبلا که رندر شد Calculatorمشخص کرد کهonTemperatureChangeای که برایTemperatureInputسلیسوس بود متدی بهنامhandleCelsiusChangeدرCalculatorاست وonTemperatureChangeای که برای فارنهایت بود متدی بهنامhandleFahrenheitChangeدرCalculatorاست. پس این دو متد از Calculator بسته به اینکه کدام input ویرایش شده است فراخوانی میشود.
- درون این متدها, کامپوننت Calculatorبا درخواستthis.setState()از React میخواهد با مقدار جدید input و scale کنونی input که تازه ویرایش شده خودش را دوباره رندر کند.
- React متد renderکامپوننتCalculatorرا فراخوانی میکند تا بفهمد که UI به چه شکل باید باشد. مقدار هر دو input با توجه به دمای کنونی و scale فعال دوباره محاسبه میشود. تبدیل دما در اینجا انجام میشود.
- React متد renderهر یک از کامپوننتهایTemperatureInputبا propهای جدیدی کهCalculatorمشخص کرده است صدا میزند. و. و میفهمد که UI هر یک به چه شکل باید باشد.
- React متد renderاز کامپوننتBoilingVerdictرا صدا میزند, و دمای سلیسوس را به عنوان prop ارسال میکند.
- React DOM ، DOM را با حکم جوش بهروز رسانی میکند تا مقادیر ورودی مورد نظر را تطبیق دهد. inputای که درحال حاضر ویرایش کردیم مقدار خودش را میگیرد و input دیگر دمای خودش را بعد از تبدیل بهروز رسانی میکند.
هر به روز رسانی این مراحل را طی میکند تا در نهایت این دو input با هم همگام باشند.
درسهایی که آموختیم
باید برای هر دادهای که در React تغییر میکند یک “منبع حقیقت” وجود داشته باشد. معمولا state در ابتدا به کامپوننت برای رندر مجدد اضافه میشود. و اگر کامپوننت دیگری بهآن نیاز داشت، شما میتوانید آن را به بالا و نزدیکترین جد مشترک انتقال دهید. به جای اینکه سعی کنید state را بین کامپوننت های مختلف همگام کنید، باید به حالت جریان داده از بالا-به-پایین تکیه کنید.
بالا بردن state شامل نوشتن بیشتر “boilerplate” نسبت به روش binding دو-طرفه است، ولی به عنوان مزیت، هزینه کمتری برای پیدا کردن و کپسوله کردن باگها دارد. از آنجایی که هر state در برخی کامپوننتها “زندگی” میکند و آن کامپوننت به تنهایی میتواند آن را تغییر دهد، سطح وسیعی از باگها به طور چشمگیری کاهش پیدا میکند. علاوه بر این ، شما میتوانید منطق سفارشی برای رد یا انتقال ورودی کاربر پیاده سازی کنید.
اگر چیزی میتوانست از props یا state ناشی شود ، احتمالا نباید در state باشد. برای مثال ، به جای ذخیره کردن celsiusValue و fahrenheitValue، ما فقط آخرین temperature و scale تغییر کرده را ذخیزه میکنیم. مقدار سایز inputها میتواند در متد render() محاسبه شود. این به ما امکان می دهد بدون از دست دادن دقت در ورودی کاربر ، سایر فیلدها را پاک یا رند کنیم.
وقتی میبینید چیزی در UI اشتباه است, میتواند از  ابزار توسعه React برای بازرسی propها استفاده کنید و در درخت اینقدر بالا بروید تا کامپوننتی که مسول بهروز رسانی state هست را پیدا کنید. این به شما امکان میدهد  تا باگها را تا منبع دنبال کنید.
