Files
react/docs/multiple-components.html
T
Vjeux ee5805da65 Christopher Chedeau vjeux Document isMounted … 30e16e4
Nick Thompson	nick-thompson	Clarify componentWillMount behavior	542f20b
Cheng Lou	chenglou	docs fix back link in Examples	6b15ad5
Cheng Lou	chenglou	docs add jsx->js tab to live editors	7ac5f3c
Paul O’Shannessy	zpao	Normalize line endings	6b1c6be
Ben Alpert	spicyj	Update homepage for new JSX/JS editor	761e1c8
Ben Alpert	spicyj	Properly clear live editor on JSX compile failure	d3fc5ad
Ben Alpert	spicyj	Simplify live editor execution logic	c7f0663
Cheng Lou	chenglou	[docs] Tweak frontpage first example and jsx-compiler example	8c8841c
Christoph Pojer	cpojer	Update propTypes documentation.	b66fbde
Jean Lauliac	jeanlauliac	Update broken link in 'why react' article	341d292
Jean Lauliac	jeanlauliac	Normalize internal links in 'why react' article	0681d13
aymanosman	aymanosman	Fix typo	09650e1
Bob Eagan	bobeagan	fix incorrect link	2edb76f
Bob Eagan	bobeagan	add hash link for lifecycle section of working with the browser page	3db3460
Pete Hunt	petehunt	remove references to react-page	3120192
Ben Alpert	spicyj	Fix docs typo	6e4ddfd
Paul O’Shannessy	zpao	Fix animation example code …	dd66223
Eric Schoffstall	Contra	fix grammar mistake	64ac427
Kunal Mehta	kmeht	Add documentation about React.renderComponent …	f970453
Christopher Chedeau	vjeux	s/Mock DOM/Virtual DOM/ …	22772c9
Ben Alpert	spicyj	Disable CodeMirror smart indentation …	571d173
Ben Alpert	spicyj	[docs] Fix comma splice	3810c83
2014-02-02 03:58:18 +01:00

501 lines
25 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>React | Multiple Components</title>
<meta name="viewport" content="width=device-width">
<meta property="og:title" content="React | Multiple Components" />
<meta property="og:type" content="website" />
<meta property="og:url" content="http://facebook.github.io/react/docs/multiple-components.html" />
<meta property="og:image" content="http://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="http://facebook.github.io/react/feed.xml">
<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 type="text/javascript" src="//use.typekit.net/vqa1hcx.js"></script>
<script type="text/javascript">try{Typekit.load();}catch(e){}</script>
<!--[if lte IE 8]>
<script type="text/javascript" src="/react/js/html5shiv.min.js"></script>
<script type="text/javascript" src="/react/js/es5-shim.min.js"></script>
<script type="text/javascript" src="/react/js/es5-sham.min.js"></script>
<![endif]-->
<script type="text/javascript" src="/react/js/codemirror.js"></script>
<script type="text/javascript" src="/react/js/javascript.js"></script>
<script type="text/javascript" src="/react/js/react.min.js"></script>
<script type="text/javascript" src="/react/js/JSXTransformer.js"></script>
<script type="text/javascript" src="/react/js/live_editor.js"></script>
<script type="text/javascript" src="/react/js/showdown.js"></script>
</head>
<body>
<div class="container">
<div class="nav-main">
<div class="wrap">
<a class="nav-home" href="/react/index.html">
<img class="nav-logo" alt="" src="/react/img/logo_small.png" width="38" height="38">
React
</a>
<ul class="nav-site">
<li><a href="/react/docs/getting-started.html" class="active">docs</a></li>
<li><a href="/react/support.html">support</a></li>
<li><a href="/react/downloads.html">download</a></li>
<li><a href="/react/blog/">blog</a></li>
<li><a href="http://github.com/facebook/react">github</a>
</ul>
</div>
</div>
<section class="content wrap documentationContent">
<div class="nav-docs">
<!-- Docs Nav -->
<div class="nav-docs-section">
<h3>Quick Start</h3>
<ul>
<li>
<a href="/react/docs/getting-started.html">
Getting Started
</a>
</li>
<li>
<a href="/react/docs/tutorial.html">
Tutorial
</a>
</li>
<li>
<a href="/react/docs/videos.html">
Videos
</a>
</li>
</ul>
</div>
<div class="nav-docs-section">
<h3>Guides</h3>
<ul>
<li>
<a href="/react/docs/why-react.html">
Why React?
</a>
</li>
<li>
<a href="/react/docs/displaying-data.html">
Displaying Data
</a>
<ul>
<li>
<a href="/react/docs/jsx-in-depth.html">
JSX in Depth
</a>
</li>
<li>
<a href="/react/docs/jsx-gotchas.html">
JSX Gotchas
</a>
</li>
</ul>
</li>
<li>
<a href="/react/docs/interactivity-and-dynamic-uis.html">
Interactivity and Dynamic UIs
</a>
</li>
<li>
<a href="/react/docs/multiple-components.html" class="active">
Multiple Components
</a>
</li>
<li>
<a href="/react/docs/reusable-components.html">
Reusable Components
</a>
</li>
<li>
<a href="/react/docs/forms.html">
Forms
</a>
</li>
<li>
<a href="/react/docs/working-with-the-browser.html">
Working With the Browser
</a>
<ul>
<li>
<a href="/react/docs/more-about-refs.html">
More About Refs
</a>
</li>
</ul>
</li>
<li>
<a href="/react/docs/tooling-integration.html">
Tooling Integration
</a>
</li>
<li>
<a href="/react/docs/addons.html">
Add-Ons
</a>
<ul>
<li>
<a href="/react/docs/animation.html">
Animation
</a>
</li>
<li>
<a href="/react/docs/two-way-binding-helpers.html">
Two-Way Binding Helpers
</a>
</li>
<li>
<a href="/react/docs/class-name-manipulation.html">
Class Name Manipulation
</a>
</li>
</ul>
</li>
<li>
<a href="/react/docs/examples.html">
Examples
</a>
</li>
</ul>
</div>
<div class="nav-docs-section">
<h3>Reference</h3>
<ul>
<li>
<a href="/react/docs/top-level-api.html">
Top-Level API
</a>
</li>
<li>
<a href="/react/docs/component-api.html">
Component API
</a>
</li>
<li>
<a href="/react/docs/component-specs.html">
Component Specs and Lifecycle
</a>
</li>
<li>
<a href="/react/docs/tags-and-attributes.html">
Supported Tags and Attributes
</a>
</li>
<li>
<a href="/react/docs/events.html">
Event System
</a>
</li>
<li>
<a href="/react/docs/dom-differences.html">
DOM Differences
</a>
</li>
<li>
<a href="/react/docs/special-non-dom-attributes.html">
Special Non-DOM attributes
</a>
</li>
<li>
<a href="/react/docs/reconciliation.html">
Reconciliation
</a>
</li>
</ul>
</div>
<!-- Tips Nav -->
<div class="nav-docs-section">
<h3>Tips</h3>
<ul>
<li>
<a href="/react/tips/introduction.html">Introduction</a>
</li>
<li>
<a href="/react/tips/inline-styles.html">Inline Styles</a>
</li>
<li>
<a href="/react/tips/if-else-in-JSX.html">If-Else in JSX</a>
</li>
<li>
<a href="/react/tips/self-closing-tag.html">Self-Closing Tag</a>
</li>
<li>
<a href="/react/tips/maximum-number-of-jsx-root-nodes.html">Maximum Number of JSX Root Nodes</a>
</li>
<li>
<a href="/react/tips/style-props-value-px.html">Shorthand for Specifying Pixel Values in style props</a>
</li>
<li>
<a href="/react/tips/children-props-type.html">Type of the Children props</a>
</li>
<li>
<a href="/react/tips/controlled-input-null-value.html">Value of null for Controlled Input</a>
</li>
<li>
<a href="/react/tips/componentWillReceiveProps-not-triggered-after-mounting.html">componentWillReceiveProps Not Triggered After Mounting</a>
</li>
<li>
<a href="/react/tips/props-in-getInitialState-as-anti-pattern.html">Props in getInitialState Is an Anti-Pattern</a>
</li>
<li>
<a href="/react/tips/dom-event-listeners.html">DOM Event Listeners in a Component</a>
</li>
<li>
<a href="/react/tips/initial-ajax.html">Load Initial Data via AJAX</a>
</li>
<li>
<a href="/react/tips/false-in-jsx.html">False in JSX</a>
</li>
<li>
<a href="/react/tips/communicate-between-components.html">Communicate Between Components</a>
</li>
<li>
<a href="/react/tips/expose-component-functions.html">Expose Component Functions</a>
</li>
</ul>
</div>
</div>
<div class="inner-content">
<h1>Multiple Components</h1>
<div class="subHeader"></div>
<p>So far, we&#39;ve looked at how to write a single component to display data and handle user input. Next let&#39;s examine one of React&#39;s finest features: composability.</p>
<h2><a class="anchor" name="motivation-separation-of-concerns"></a>Motivation: Separation of Concerns <a class="hash-link" href="#motivation-separation-of-concerns">#</a></h2>
<p>By building modular components that reuse other components with well-defined interfaces, you get much of the same benefits that you get by using functions or classes. Specifically you can <em>separate the different concerns</em> of your app however you please simply by building new components. By building a custom component library for your application, you are expressing your UI in a way that best fits your domain.</p>
<h2><a class="anchor" name="composition-example"></a>Composition Example <a class="hash-link" href="#composition-example">#</a></h2>
<p>Let&#39;s create a simple Avatar component which shows a profile picture and username using the Facebook Graph API.</p>
<div class="highlight"><pre><code class="javascript language-javascript" data-lang="javascript"><span class="cm">/** @jsx React.DOM */</span>
<span class="kd">var</span> <span class="nx">Avatar</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="nx">createClass</span><span class="p">({</span>
<span class="nx">render</span><span class="o">:</span> <span class="kd">function</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="o">&lt;</span><span class="nx">ProfilePic</span> <span class="nx">username</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">username</span><span class="p">}</span> <span class="o">/&gt;</span>
<span class="o">&lt;</span><span class="nx">ProfileLink</span> <span class="nx">username</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">username</span><span class="p">}</span> <span class="o">/&gt;</span>
<span class="o">&lt;</span><span class="err">/div&gt;</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="kd">var</span> <span class="nx">ProfilePic</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="nx">createClass</span><span class="p">({</span>
<span class="nx">render</span><span class="o">:</span> <span class="kd">function</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">img</span> <span class="nx">src</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;http://graph.facebook.com/&#39;</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">username</span> <span class="o">+</span> <span class="s1">&#39;/picture&#39;</span><span class="p">}</span> <span class="o">/&gt;</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="kd">var</span> <span class="nx">ProfileLink</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="nx">createClass</span><span class="p">({</span>
<span class="nx">render</span><span class="o">:</span> <span class="kd">function</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">a</span> <span class="nx">href</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;http://www.facebook.com/&#39;</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">username</span><span class="p">}</span><span class="o">&gt;</span>
<span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">username</span><span class="p">}</span>
<span class="o">&lt;</span><span class="err">/a&gt;</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="nx">React</span><span class="p">.</span><span class="nx">renderComponent</span><span class="p">(</span>
<span class="o">&lt;</span><span class="nx">Avatar</span> <span class="nx">username</span><span class="o">=</span><span class="s2">&quot;pwh&quot;</span> <span class="o">/&gt;</span><span class="p">,</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">&#39;example&#39;</span><span class="p">)</span>
<span class="p">);</span>
</code></pre></div><h2><a class="anchor" name="ownership"></a>Ownership <a class="hash-link" href="#ownership">#</a></h2>
<p>In the above example, instances of <code>Avatar</code> <em>own</em> instances of <code>ProfilePic</code> and <code>ProfileLink</code>. In React, <strong>an owner is the component that sets the <code>props</code> of other components</strong>. More formally, if a component <code>X</code> is created in component <code>Y</code>&#39;s <code>render()</code> method, it is said that <code>X</code> is <em>owned by</em> <code>Y</code>. As discussed earlier, a component cannot mutate its <code>props</code> — they are always consistent with what its owner sets them to. This key property leads to UIs that are guaranteed to be consistent.</p>
<p>It&#39;s important to draw a distinction between the owner-ownee relationship and the parent-child relationship. The owner-ownee relationship is specific to React, while the parent-child relationship is simply the one you know and love from the DOM. In the example above, <code>Avatar</code> owns the <code>div</code>, <code>ProfilePic</code> and <code>ProfileLink</code> instances, and <code>div</code> is the <strong>parent</strong> (but not owner) of the <code>ProfilePic</code> and <code>ProfileLink</code> instances.</p>
<h2><a class="anchor" name="children"></a>Children <a class="hash-link" href="#children">#</a></h2>
<p>When you create a React component instance, you can include additional React components or JavaScript expressions between the opening and closing tags like this:</p>
<div class="highlight"><pre><code class="javascript language-javascript" data-lang="javascript"><span class="o">&lt;</span><span class="nx">Parent</span><span class="o">&gt;&lt;</span><span class="nx">Child</span> <span class="o">/&gt;&lt;</span><span class="err">/Parent&gt;</span>
</code></pre></div>
<p><code>Parent</code> can read its children by accessing the special <code>this.props.children</code> prop.</p>
<h3><a class="anchor" name="child-reconciliation"></a>Child Reconciliation <a class="hash-link" href="#child-reconciliation">#</a></h3>
<p><strong>Reconciliation is the process by which React updates the DOM with each new render pass.</strong> In general, children are reconciled according to the order in which they are rendered. For example, suppose two render passes generate the following respective markup:</p>
<div class="highlight"><pre><code class="html language-html" data-lang="html">// Render Pass 1
<span class="nt">&lt;Card&gt;</span>
<span class="nt">&lt;p&gt;</span>Paragraph 1<span class="nt">&lt;/p&gt;</span>
<span class="nt">&lt;p&gt;</span>Paragraph 2<span class="nt">&lt;/p&gt;</span>
<span class="nt">&lt;/Card&gt;</span>
// Render Pass 2
<span class="nt">&lt;Card&gt;</span>
<span class="nt">&lt;p&gt;</span>Paragraph 2<span class="nt">&lt;/p&gt;</span>
<span class="nt">&lt;/Card&gt;</span>
</code></pre></div>
<p>Intuitively, <code>&lt;p&gt;Paragraph 1&lt;/p&gt;</code> was removed. Instead, React will reconcile the DOM by changing the text content of the first child and destroying the last child. React reconciles according to the <em>order</em> of the children.</p>
<h3><a class="anchor" name="stateful-children"></a>Stateful Children <a class="hash-link" href="#stateful-children">#</a></h3>
<p>For most components, this is not a big deal. However, for stateful components that maintain data in <code>this.state</code> across render passes, this can be very problematic.</p>
<p>In most cases, this can be sidestepped by hiding elements instead of destroying them:</p>
<div class="highlight"><pre><code class="html language-html" data-lang="html">// Render Pass 1
<span class="nt">&lt;Card&gt;</span>
<span class="nt">&lt;p&gt;</span>Paragraph 1<span class="nt">&lt;/p&gt;</span>
<span class="nt">&lt;p&gt;</span>Paragraph 2<span class="nt">&lt;/p&gt;</span>
<span class="nt">&lt;/Card&gt;</span>
// Render Pass 2
<span class="nt">&lt;Card&gt;</span>
<span class="nt">&lt;p</span> <span class="na">style=</span><span class="s">{{display:</span> <span class="err">&#39;</span><span class="na">none</span><span class="err">&#39;}}</span><span class="nt">&gt;</span>Paragraph 1<span class="nt">&lt;/p&gt;</span>
<span class="nt">&lt;p&gt;</span>Paragraph 2<span class="nt">&lt;/p&gt;</span>
<span class="nt">&lt;/Card&gt;</span>
</code></pre></div><h3><a class="anchor" name="dynamic-children"></a>Dynamic Children <a class="hash-link" href="#dynamic-children">#</a></h3>
<p>The situation gets more complicated when the children are shuffled around (as in search results) or if new components are added onto the front of the list (as in streams). In these cases where the identity and state of each child must be maintained across render passes, you can uniquely identify each child by assigning it a <code>key</code>:</p>
<div class="highlight"><pre><code class="javascript language-javascript" data-lang="javascript"> <span class="nx">render</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">results</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">results</span><span class="p">;</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o">&lt;</span><span class="nx">ol</span><span class="o">&gt;</span>
<span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">results</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">result</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="o">&lt;</span><span class="nx">li</span> <span class="nx">key</span><span class="o">=</span><span class="p">{</span><span class="nx">result</span><span class="p">.</span><span class="nx">id</span><span class="p">}</span><span class="o">&gt;</span><span class="p">{</span><span class="nx">result</span><span class="p">.</span><span class="nx">text</span><span class="p">}</span><span class="o">&lt;</span><span class="err">/li&gt;;</span>
<span class="p">})}</span>
<span class="o">&lt;</span><span class="err">/ol&gt;</span>
<span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p>When React reconciles the keyed children, it will ensure that any child with <code>key</code> will be reordered (instead of clobbered) or destroyed (instead of reused).</p>
<h2><a class="anchor" name="data-flow"></a>Data Flow <a class="hash-link" href="#data-flow">#</a></h2>
<p>In React, data flows from owner to owned component through <code>props</code> as discussed above. This is effectively one-way data binding: owners bind their owned component&#39;s props to some value the owner has computed based on its <code>props</code> or <code>state</code>. Since this process happens recursively, data changes are automatically reflected everywhere they are used.</p>
<h2><a class="anchor" name="a-note-on-performance"></a>A Note on Performance <a class="hash-link" href="#a-note-on-performance">#</a></h2>
<p>You may be thinking that it&#39;s expensive to react to changing data if there are a large number of nodes under an owner. The good news is that JavaScript is fast and <code>render()</code> methods tend to be quite simple, so in most applications this is extremely fast. Additionally, the bottleneck is almost always the DOM mutation and not JS execution and React will optimize this for you using batching and change detection.</p>
<p>However, sometimes you really want to have fine-grained control over your performance. In that case, simply override <code>shouldComponentUpdate()</code> to return false when you want React to skip processing of a subtree. See <a href="/react/docs/component-specs.html">the React reference docs</a> for more information.</p>
<blockquote>
<p>Note:</p>
<p>If <code>shouldComponentUpdate()</code> returns false when data has actually changed, React can&#39;t keep your UI in sync. Be sure you know what you&#39;re doing while using it, and only use this function when you have a noticeable performance problem. Don&#39;t underestimate how fast JavaScript is relative to the DOM.</p>
</blockquote>
<div class="docs-prevnext">
<a class="docs-prev" href="/react/docs/interactivity-and-dynamic-uis.html">&larr; Prev</a>
<a class="docs-next" href="/react/docs/reusable-components.html">Next &rarr;</a>
</div>
<div class="fb-comments" data-width="650" data-num-posts="10" data-href="http://facebook.github.io/react/docs/multiple-components.html"></div>
</div>
</section>
<footer class="wrap">
<div class="left">A Facebook &amp; Instagram collaboration.</div>
<div class="right">&copy; 2014 Facebook Inc.</div>
</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/all.js#xfbml=1&appId=623268441017527";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
</script>
</body>
</html>