Files
react/docs/lifting-state-up.html
T
Dan Abramov 6bb7a6c60e Rebuild docs
2017-01-06 20:28:00 +00:00

614 lines
40 KiB
HTML

<!DOCTYPE html>
<!--[if IE]><![endif]-->
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Lifting State Up - React</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta property="og:title" content="Lifting State Up - React">
<meta property="og:type" content="website">
<meta property="og:url" content="https://facebook.github.io/react/docs/lifting-state-up.html">
<meta property="og:image" content="https://facebook.github.io/react/img/logo_og.png">
<meta property="og:description" content="A JavaScript library for building user interfaces">
<meta property="fb:app_id" content="623268441017527">
<link rel="shortcut icon" href="/react/favicon.ico">
<link rel="alternate" type="application/rss+xml" title="React" href="https://facebook.github.io/react/feed.xml">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.css" />
<link rel="stylesheet" href="/react/css/syntax.css">
<link rel="stylesheet" href="/react/css/codemirror.css">
<link rel="stylesheet" href="/react/css/react.css">
<script src="//use.typekit.net/vqa1hcx.js"></script>
<script>try{Typekit.load();}catch(e){}</script>
<!--[if lte IE 8]>
<script src="/react/js/html5shiv.min.js"></script>
<script src="/react/js/es5-shim.min.js"></script>
<script src="/react/js/es5-sham.min.js"></script>
<![endif]-->
<script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.js"></script>
<script src="/react/js/codemirror.js"></script>
<script src="/react/js/javascript.js"></script>
<script src="/react/js/xml.js"></script>
<script src="/react/js/jsx.js"></script>
<script src="/react/js/react.js"></script>
<script src="/react/js/react-dom.js"></script>
<script src="/react/js/babel.min.js"></script>
<script src="/react/js/live_editor.js"></script>
</head>
<body>
<div class="container">
<div class="nav-main">
<div class="wrap">
<a class="nav-home" href="/react/">
<img class="nav-logo" src="/react/img/logo.svg" width="36" height="36">
React
</a>
<div class="nav-lists">
<ul class="nav-site nav-site-internal">
<li><a href="/react/docs/hello-world.html" class="active">Docs</a></li>
<li><a href="/react/tutorial/tutorial.html">Tutorial</a></li>
<li><a href="/react/community/support.html">Community</a></li>
<li><a href="/react/blog/">Blog</a></li>
<li class="nav-site-search">
<input id="algolia-doc-search" type="text" placeholder="Search docs..." />
</li>
</ul>
<ul class="nav-site nav-site-external">
<li><a href="https://github.com/facebook/react">GitHub</a></li>
<li><a href="https://github.com/facebook/react/releases">v15.4.2</a></li>
</ul>
</div>
</div>
</div>
<section class="content wrap documentationContent">
<div class="inner-content">
<a class="edit-page-link" href="https://github.com/facebook/react/tree/master/docs/docs/lifting-state-up.md" target="_blank">Edit on GitHub</a>
<h1>
Lifting State Up
</h1>
<div class="subHeader"></div>
<p>Often, several components need to reflect the same changing data. We recommend lifting the shared state up to their closest common ancestor. Let&#39;s see how this works in action.</p>
<p>In this section, we will create a temperature calculator that calculates whether the water would boil at a given temperature.</p>
<p>We will start with a component called <code>BoilingVerdict</code>. It accepts the <code>celsius</code> temperature as a prop, and prints whether it is enough to boil the water:</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="kd">function</span> <span class="nx">BoilingVerdict</span><span class="p">(</span><span class="nx">props</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">props</span><span class="p">.</span><span class="nx">celsius</span> <span class="o">&gt;=</span> <span class="mi">100</span><span class="p">)</span> <span class="p">{</span>
<span class="hll"> <span class="k">return</span> <span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;</span><span class="nx">The</span> <span class="nx">water</span> <span class="nx">would</span> <span class="nx">boil</span><span class="p">.</span><span class="o">&lt;</span><span class="err">/p&gt;;</span>
</span> <span class="p">}</span>
<span class="hll"> <span class="k">return</span> <span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;</span><span class="nx">The</span> <span class="nx">water</span> <span class="nx">would</span> <span class="nx">not</span> <span class="nx">boil</span><span class="p">.</span><span class="o">&lt;</span><span class="err">/p&gt;;</span>
</span><span class="p">}</span>
</code></pre></div>
<p>Next, we will create a component called <code>Calculator</code>. It renders an <code>&lt;input&gt;</code> that lets you enter the temperature, and keeps its value in <code>this.state.value</code>.</p>
<p>Additionally, it renders the <code>BoilingVerdict</code> for the current input value.</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="kr">class</span> <span class="nx">Calculator</span> <span class="kr">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span> <span class="p">{</span>
<span class="nx">constructor</span><span class="p">(</span><span class="nx">props</span><span class="p">)</span> <span class="p">{</span>
<span class="kr">super</span><span class="p">(</span><span class="nx">props</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nx">handleChange</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">handleChange</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="hll"> <span class="k">this</span><span class="p">.</span><span class="nx">state</span> <span class="o">=</span> <span class="p">{</span><span class="nx">value</span><span class="o">:</span> <span class="s1">&#39;&#39;</span><span class="p">};</span>
</span> <span class="p">}</span>
<span class="nx">handleChange</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="hll"> <span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">({</span><span class="nx">value</span><span class="o">:</span> <span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">});</span>
</span> <span class="p">}</span>
<span class="nx">render</span><span class="p">()</span> <span class="p">{</span>
<span class="hll"> <span class="kr">const</span> <span class="nx">value</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
</span> <span class="k">return</span> <span class="p">(</span>
<span class="o">&lt;</span><span class="nx">fieldset</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="nx">legend</span><span class="o">&gt;</span><span class="nx">Enter</span> <span class="nx">temperature</span> <span class="k">in</span> <span class="nx">Celsius</span><span class="o">:&lt;</span><span class="err">/legend&gt;</span>
<span class="hll"> <span class="o">&lt;</span><span class="nx">input</span>
</span><span class="hll"> <span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="nx">value</span><span class="p">}</span>
</span><span class="hll"> <span class="nx">onChange</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">handleChange</span><span class="p">}</span> <span class="o">/&gt;</span>
</span><span class="hll"> <span class="o">&lt;</span><span class="nx">BoilingVerdict</span>
</span><span class="hll"> <span class="nx">celsius</span><span class="o">=</span><span class="p">{</span><span class="nb">parseFloat</span><span class="p">(</span><span class="nx">value</span><span class="p">)}</span> <span class="o">/&gt;</span>
</span> <span class="o">&lt;</span><span class="err">/fieldset&gt;</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p><a href="http://codepen.io/gaearon/pen/Gjxgrj?editors=0010">Try it on CodePen.</a></p>
<h2><a class="anchor" name="adding-a-second-input"></a>Adding a Second Input <a class="hash-link" href="#adding-a-second-input">#</a></h2>
<p>Our new requirement is that, in addition to a Celsius input, we provide a Fahrenheit input, and they are kept in sync.</p>
<p>We can start by extracting a <code>TemperatureInput</code> component from <code>Calculator</code>. We will add a new <code>scale</code> prop to it that can either be <code>&quot;c&quot;</code> or <code>&quot;f&quot;</code>:</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="hll"><span class="kr">const</span> <span class="nx">scaleNames</span> <span class="o">=</span> <span class="p">{</span>
</span><span class="hll"> <span class="nx">c</span><span class="o">:</span> <span class="s1">&#39;Celsius&#39;</span><span class="p">,</span>
</span><span class="hll"> <span class="nx">f</span><span class="o">:</span> <span class="s1">&#39;Fahrenheit&#39;</span>
</span><span class="hll"><span class="p">};</span>
</span>
<span class="kr">class</span> <span class="nx">TemperatureInput</span> <span class="kr">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span> <span class="p">{</span>
<span class="nx">constructor</span><span class="p">(</span><span class="nx">props</span><span class="p">)</span> <span class="p">{</span>
<span class="kr">super</span><span class="p">(</span><span class="nx">props</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nx">handleChange</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">handleChange</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nx">state</span> <span class="o">=</span> <span class="p">{</span><span class="nx">value</span><span class="o">:</span> <span class="s1">&#39;&#39;</span><span class="p">};</span>
<span class="p">}</span>
<span class="nx">handleChange</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">({</span><span class="nx">value</span><span class="o">:</span> <span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">});</span>
<span class="p">}</span>
<span class="nx">render</span><span class="p">()</span> <span class="p">{</span>
<span class="kr">const</span> <span class="nx">value</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
<span class="hll"> <span class="kr">const</span> <span class="nx">scale</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">scale</span><span class="p">;</span>
</span> <span class="k">return</span> <span class="p">(</span>
<span class="o">&lt;</span><span class="nx">fieldset</span><span class="o">&gt;</span>
<span class="hll"> <span class="o">&lt;</span><span class="nx">legend</span><span class="o">&gt;</span><span class="nx">Enter</span> <span class="nx">temperature</span> <span class="k">in</span> <span class="p">{</span><span class="nx">scaleNames</span><span class="p">[</span><span class="nx">scale</span><span class="p">]}</span><span class="o">:&lt;</span><span class="err">/legend&gt;</span>
</span> <span class="o">&lt;</span><span class="nx">input</span> <span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="nx">value</span><span class="p">}</span>
<span class="nx">onChange</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">handleChange</span><span class="p">}</span> <span class="o">/&gt;</span>
<span class="o">&lt;</span><span class="err">/fieldset&gt;</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>We can now change the <code>Calculator</code> to render two separate temperature inputs:</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="kr">class</span> <span class="nx">Calculator</span> <span class="kr">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span> <span class="p">{</span>
<span class="nx">render</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o">&lt;</span><span class="nx">div</span><span class="o">&gt;</span>
<span class="hll"> <span class="o">&lt;</span><span class="nx">TemperatureInput</span> <span class="nx">scale</span><span class="o">=</span><span class="s2">&quot;c&quot;</span> <span class="o">/&gt;</span>
</span><span class="hll"> <span class="o">&lt;</span><span class="nx">TemperatureInput</span> <span class="nx">scale</span><span class="o">=</span><span class="s2">&quot;f&quot;</span> <span class="o">/&gt;</span>
</span> <span class="o">&lt;</span><span class="err">/div&gt;</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p><a href="http://codepen.io/gaearon/pen/NRrzOL?editors=0010">Try it on CodePen.</a></p>
<p>We have two inputs now, but when you enter the temperature in one of them, the other doesn&#39;t update. This contradicts our requirement: we want to keep them in sync.</p>
<p>We also can&#39;t display the <code>BoilingVerdict</code> from <code>Calculator</code>. The <code>Calculator</code> doesn&#39;t know the current temperature because it is hidden inside the <code>TemperatureInput</code>.</p>
<h2><a class="anchor" name="lifting-state-up"></a>Lifting State Up <a class="hash-link" href="#lifting-state-up">#</a></h2>
<p>First, we will write two functions to convert from Celsius to Fahrenheit and back:</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="kd">function</span> <span class="nx">toCelsius</span><span class="p">(</span><span class="nx">fahrenheit</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span><span class="nx">fahrenheit</span> <span class="o">-</span> <span class="mi">32</span><span class="p">)</span> <span class="o">*</span> <span class="mi">5</span> <span class="o">/</span> <span class="mi">9</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">toFahrenheit</span><span class="p">(</span><span class="nx">celsius</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span><span class="nx">celsius</span> <span class="o">*</span> <span class="mi">9</span> <span class="o">/</span> <span class="mi">5</span><span class="p">)</span> <span class="o">+</span> <span class="mi">32</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>These two functions convert numbers. We will write another function that takes a string <code>value</code> and a converter function as arguments and returns a string. We will use it to calculate the value of one input based on the other input.</p>
<p>It returns an empty string on an invalid <code>value</code>, and it keeps the output rounded to the third decimal place:</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="kd">function</span> <span class="nx">tryConvert</span><span class="p">(</span><span class="nx">value</span><span class="p">,</span> <span class="nx">convert</span><span class="p">)</span> <span class="p">{</span>
<span class="kr">const</span> <span class="nx">input</span> <span class="o">=</span> <span class="nb">parseFloat</span><span class="p">(</span><span class="nx">value</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">Number</span><span class="p">.</span><span class="nb">isNaN</span><span class="p">(</span><span class="nx">input</span><span class="p">))</span> <span class="p">{</span>
<span class="k">return</span> <span class="s1">&#39;&#39;</span><span class="p">;</span>
<span class="p">}</span>
<span class="kr">const</span> <span class="nx">output</span> <span class="o">=</span> <span class="nx">convert</span><span class="p">(</span><span class="nx">input</span><span class="p">);</span>
<span class="kr">const</span> <span class="nx">rounded</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">round</span><span class="p">(</span><span class="nx">output</span> <span class="o">*</span> <span class="mi">1000</span><span class="p">)</span> <span class="o">/</span> <span class="mi">1000</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">rounded</span><span class="p">.</span><span class="nx">toString</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div>
<p>For example, <code>tryConvert(&#39;abc&#39;, toCelsius)</code> returns an empty string, and <code>tryConvert(&#39;10.22&#39;, toFahrenheit)</code> returns <code>&#39;50.396&#39;</code>.</p>
<p>Next, we will remove the state from <code>TemperatureInput</code>.</p>
<p>Instead, it will receive both <code>value</code> and the <code>onChange</code> handler by props:</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="kr">class</span> <span class="nx">TemperatureInput</span> <span class="kr">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span> <span class="p">{</span>
<span class="nx">constructor</span><span class="p">(</span><span class="nx">props</span><span class="p">)</span> <span class="p">{</span>
<span class="kr">super</span><span class="p">(</span><span class="nx">props</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nx">handleChange</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">handleChange</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">handleChange</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="hll"> <span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">onChange</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
</span> <span class="p">}</span>
<span class="nx">render</span><span class="p">()</span> <span class="p">{</span>
<span class="hll"> <span class="kr">const</span> <span class="nx">value</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
</span> <span class="kr">const</span> <span class="nx">scale</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">scale</span><span class="p">;</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o">&lt;</span><span class="nx">fieldset</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="nx">legend</span><span class="o">&gt;</span><span class="nx">Enter</span> <span class="nx">temperature</span> <span class="k">in</span> <span class="p">{</span><span class="nx">scaleNames</span><span class="p">[</span><span class="nx">scale</span><span class="p">]}</span><span class="o">:&lt;</span><span class="err">/legend&gt;</span>
<span class="o">&lt;</span><span class="nx">input</span> <span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="nx">value</span><span class="p">}</span>
<span class="nx">onChange</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">handleChange</span><span class="p">}</span> <span class="o">/&gt;</span>
<span class="o">&lt;</span><span class="err">/fieldset&gt;</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>If several components need access to the same state, it is a sign that the state should be lifted up to their closest common ancestor instead. In our case, this is the <code>Calculator</code>. We will store the current <code>value</code> and <code>scale</code> in its state.</p>
<p>We could have stored the value of both inputs but it turns out to be unnecessary. It is enough to store the value of the most recently changed input, and the scale that it represents. We can then infer the value of the other input based on the current <code>value</code> and <code>scale</code> alone.</p>
<p>The inputs stay in sync because their values are computed from the same state:</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span class="kr">class</span> <span class="nx">Calculator</span> <span class="kr">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span> <span class="p">{</span>
<span class="nx">constructor</span><span class="p">(</span><span class="nx">props</span><span class="p">)</span> <span class="p">{</span>
<span class="kr">super</span><span class="p">(</span><span class="nx">props</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nx">handleCelsiusChange</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">handleCelsiusChange</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nx">handleFahrenheitChange</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">handleFahrenheitChange</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="hll"> <span class="k">this</span><span class="p">.</span><span class="nx">state</span> <span class="o">=</span> <span class="p">{</span><span class="nx">value</span><span class="o">:</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="nx">scale</span><span class="o">:</span> <span class="s1">&#39;c&#39;</span><span class="p">};</span>
</span> <span class="p">}</span>
<span class="nx">handleCelsiusChange</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
<span class="hll"> <span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">({</span><span class="nx">scale</span><span class="o">:</span> <span class="s1">&#39;c&#39;</span><span class="p">,</span> <span class="nx">value</span><span class="p">});</span>
</span> <span class="p">}</span>
<span class="nx">handleFahrenheitChange</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
<span class="hll"> <span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">({</span><span class="nx">scale</span><span class="o">:</span> <span class="s1">&#39;f&#39;</span><span class="p">,</span> <span class="nx">value</span><span class="p">});</span>
</span> <span class="p">}</span>
<span class="nx">render</span><span class="p">()</span> <span class="p">{</span>
<span class="hll"> <span class="kr">const</span> <span class="nx">scale</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">scale</span><span class="p">;</span>
</span><span class="hll"> <span class="kr">const</span> <span class="nx">value</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
</span><span class="hll"> <span class="kr">const</span> <span class="nx">celsius</span> <span class="o">=</span> <span class="nx">scale</span> <span class="o">===</span> <span class="s1">&#39;f&#39;</span> <span class="o">?</span> <span class="nx">tryConvert</span><span class="p">(</span><span class="nx">value</span><span class="p">,</span> <span class="nx">toCelsius</span><span class="p">)</span> <span class="o">:</span> <span class="nx">value</span><span class="p">;</span>
</span><span class="hll"> <span class="kr">const</span> <span class="nx">fahrenheit</span> <span class="o">=</span> <span class="nx">scale</span> <span class="o">===</span> <span class="s1">&#39;c&#39;</span> <span class="o">?</span> <span class="nx">tryConvert</span><span class="p">(</span><span class="nx">value</span><span class="p">,</span> <span class="nx">toFahrenheit</span><span class="p">)</span> <span class="o">:</span> <span class="nx">value</span><span class="p">;</span>
</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o">&lt;</span><span class="nx">div</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="nx">TemperatureInput</span>
<span class="nx">scale</span><span class="o">=</span><span class="s2">&quot;c&quot;</span>
<span class="hll"> <span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="nx">celsius</span><span class="p">}</span>
</span><span class="hll"> <span class="nx">onChange</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">handleCelsiusChange</span><span class="p">}</span> <span class="o">/&gt;</span>
</span> <span class="o">&lt;</span><span class="nx">TemperatureInput</span>
<span class="nx">scale</span><span class="o">=</span><span class="s2">&quot;f&quot;</span>
<span class="hll"> <span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="nx">fahrenheit</span><span class="p">}</span>
</span><span class="hll"> <span class="nx">onChange</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">handleFahrenheitChange</span><span class="p">}</span> <span class="o">/&gt;</span>
</span> <span class="o">&lt;</span><span class="nx">BoilingVerdict</span>
<span class="hll"> <span class="nx">celsius</span><span class="o">=</span><span class="p">{</span><span class="nb">parseFloat</span><span class="p">(</span><span class="nx">celsius</span><span class="p">)}</span> <span class="o">/&gt;</span>
</span> <span class="o">&lt;</span><span class="err">/div&gt;</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p><a href="http://codepen.io/gaearon/pen/ozdyNg?editors=0010">Try it on CodePen.</a></p>
<p>Now, no matter which input you edit, <code>this.state.value</code> and <code>this.state.scale</code> in the <code>Calculator</code> get updated. One of the inputs gets the value as is, so any user input is preserved, and the other input value is always recalculated based on it.</p>
<h2><a class="anchor" name="lessons-learned"></a>Lessons Learned <a class="hash-link" href="#lessons-learned">#</a></h2>
<p>There should be a single &quot;source of truth&quot; for any data that changes in a React application. Usually, the state is first added to the component that needs it for rendering. Then, if other components also need it, you can lift it up to their closest common ancestor. Instead of trying to sync the state between different components, you should rely on the <a href="/react/docs/state-and-lifecycle.html#the-data-flows-down">top-down data flow</a>.</p>
<p>Lifting state involves writing more &quot;boilerplate&quot; code than two-way binding approaches, but as a benefit, it takes less work to find and isolate bugs. Since any state &quot;lives&quot; in some component and that component alone can change it, the surface area for bugs is greatly reduced. Additionally, you can implement any custom logic to reject or transform user input.</p>
<p>If something can be derived from either props or state, it probably shouldn&#39;t be in the state. For example, instead of storing both <code>celsiusValue</code> and <code>fahrenheitValue</code>, we store just the last edited <code>value</code> and its <code>scale</code>. The value of the other input can always be calculated from them in the <code>render()</code> method. This lets us clear or apply rounding to the other field without losing any precision in the user input.</p>
<p>When you see something wrong in the UI, you can use <a href="https://github.com/facebook/react-devtools">React Developer Tools</a> to inspect the props and move up the tree until you find the component responsible for updating the state. This lets you trace the bugs to their source:</p>
<p><img src="/react/img/docs/react-devtools-state.gif" alt="Monitoring State in React DevTools" width="100%"></p>
<div class="docs-prevnext">
<a class="docs-prev" href="/react/docs/state-and-lifecycle.html">&larr; Prev</a>
<a class="docs-next" href="/react/docs/composition-vs-inheritance.html">Next &rarr;</a>
</div>
</div>
<div class="nav-docs">
<!-- Docs Nav -->
<div class="nav-docs-section">
<h3>Quick Start</h3>
<ul>
<li>
<a href="/react/docs/installation.html">Installation</a>
</li>
<li>
<a href="/react/docs/hello-world.html">Hello World</a>
</li>
<li>
<a href="/react/docs/introducing-jsx.html">Introducing JSX</a>
</li>
<li>
<a href="/react/docs/rendering-elements.html">Rendering Elements</a>
</li>
<li>
<a href="/react/docs/components-and-props.html">Components and Props</a>
</li>
<li>
<a href="/react/docs/state-and-lifecycle.html">State and Lifecycle</a>
</li>
<li>
<a href="/react/docs/handling-events.html">Handling Events</a>
</li>
<li>
<a href="/react/docs/conditional-rendering.html">Conditional Rendering</a>
</li>
<li>
<a href="/react/docs/lists-and-keys.html">Lists and Keys</a>
</li>
<li>
<a href="/react/docs/forms.html">Forms</a>
</li>
<li>
<a href="/react/docs/lifting-state-up.html" class="active">Lifting State Up</a>
</li>
<li>
<a href="/react/docs/composition-vs-inheritance.html">Composition vs Inheritance</a>
</li>
<li>
<a href="/react/docs/thinking-in-react.html">Thinking In React</a>
</li>
</ul>
</div>
<div class="nav-docs-section">
<h3>Advanced Guides</h3>
<ul>
<li>
<a href="/react/docs/jsx-in-depth.html">JSX In Depth</a>
</li>
<li>
<a href="/react/docs/typechecking-with-proptypes.html">Typechecking With PropTypes</a>
</li>
<li>
<a href="/react/docs/refs-and-the-dom.html">Refs and the DOM</a>
</li>
<li>
<a href="/react/docs/uncontrolled-components.html">Uncontrolled Components</a>
</li>
<li>
<a href="/react/docs/optimizing-performance.html">Optimizing Performance</a>
</li>
<li>
<a href="/react/docs/react-without-es6.html">React Without ES6</a>
</li>
<li>
<a href="/react/docs/react-without-jsx.html">React Without JSX</a>
</li>
<li>
<a href="/react/docs/reconciliation.html">Reconciliation</a>
</li>
<li>
<a href="/react/docs/context.html">Context</a>
</li>
<li>
<a href="/react/docs/web-components.html">Web Components</a>
</li>
<li>
<a href="/react/docs/higher-order-components.html">Higher-Order Components</a>
</li>
</ul>
</div>
<div class="nav-docs-section">
<h3>Reference</h3>
<ul>
<li>
<a href="/react/docs/react-api.html">React</a>
<ul>
<li>
<a href="/react/docs/react-component.html">React.Component</a>
</li>
</ul>
</li>
<li>
<a href="/react/docs/react-dom.html">ReactDOM</a>
</li>
<li>
<a href="/react/docs/react-dom-server.html">ReactDOMServer</a>
</li>
<li>
<a href="/react/docs/dom-elements.html">DOM Elements</a>
</li>
<li>
<a href="/react/docs/events.html">SyntheticEvent</a>
</li>
<li>
<a href="/react/docs/addons.html">Add-Ons</a>
<ul>
<li>
<a href="/react/docs/perf.html">Performance Tools</a>
</li>
<li>
<a href="/react/docs/test-utils.html">Test Utilities</a>
</li>
<li>
<a href="/react/docs/animation.html">Animation</a>
</li>
<li>
<a href="/react/docs/create-fragment.html">Keyed Fragments</a>
</li>
<li>
<a href="/react/docs/update.html">Immutability Helpers</a>
</li>
<li>
<a href="/react/docs/pure-render-mixin.html">PureRenderMixin</a>
</li>
<li>
<a href="/react/docs/shallow-compare.html">Shallow Compare</a>
</li>
<li>
<a href="/react/docs/two-way-binding-helpers.html">Two-way Binding Helpers</a>
</li>
</ul>
</li>
</ul>
</div>
<!-- Contributing Nav -->
<div class="nav-docs-section">
<h3>Contributing</h3>
<ul>
<li>
<a href="/react/contributing/how-to-contribute.html">How to Contribute</a>
</li>
<li>
<a href="/react/contributing/codebase-overview.html">Codebase Overview</a>
</li>
<li>
<a href="/react/contributing/implementation-notes.html">Implementation Notes</a>
</li>
<li>
<a href="/react/contributing/design-principles.html">Design Principles</a>
</li>
</ul>
</div>
</div>
</section>
<footer class="nav-footer">
<section class="sitemap">
<a href="/react/" class="nav-home">
</a>
<div>
<h5><a href="/react/docs/">Docs</a></h5>
<a href="/react/docs/hello-world.html">Quick Start</a>
<a href="/react/docs/thinking-in-react.html">Thinking in React</a>
<a href="/react/tutorial/tutorial.html">Tutorial</a>
<a href="/react/docs/jsx-in-depth.html">Advanced Guides</a>
</div>
<div>
<h5><a href="/react/community/support.html">Community</a></h5>
<a href="http://stackoverflow.com/questions/tagged/reactjs" target="_blank">Stack Overflow</a>
<a href="https://discuss.reactjs.org/" target="_blank">Discussion Forum</a>
<a href="https://discord.gg/0ZcbPKXt5bZjGY5n" target="_blank">Reactiflux Chat</a>
<a href="https://www.facebook.com/react" target="_blank">Facebook</a>
<a href="https://twitter.com/reactjs" target="_blank">Twitter</a>
</div>
<div>
<h5><a href="/react/community/support.html">Resources</a></h5>
<a href="/react/community/conferences.html">Conferences</a>
<a href="/react/community/videos.html">Videos</a>
<a href="https://github.com/facebook/react/wiki/Examples" target="_blank">Examples</a>
<a href="https://github.com/facebook/react/wiki/Complementary-Tools" target="_blank">Complementary Tools</a>
</div>
<div>
<h5>More</h5>
<a href="/react/blog/">Blog</a>
<a href="https://github.com/facebook/react" target="_blank">GitHub</a>
<a href="http://facebook.github.io/react-native/" target="_blank">React Native</a>
<a href="/react/acknowledgements.html">Acknowledgements</a>
</div>
</section>
<a href="https://code.facebook.com/projects/" target="_blank" class="fbOpenSource">
<img src="/react/img/oss_logo.png" alt="Facebook Open Source" width="170" height="45"/>
</a>
<section class="copyright">
Copyright © 2017 Facebook Inc.
</section>
</footer>
</div>
<div id="fb-root"></div>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-41298772-1', 'facebook.github.io');
ga('send', 'pageview');
!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="https://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.6&appId=623268441017527";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
docsearch({
apiKey: '36221914cce388c46d0420343e0bb32e',
indexName: 'react',
inputSelector: '#algolia-doc-search'
});
</script>
</body>
</html>