Files
react/docs/multiple-components.html
T
Paul O’Shannessy e82227b698 Updated to latest changes
7c4c0cd [docs] Remove commented out ghbtns
92102ac Add info about dev vs. prod builds
277cbf0 [docs] Add timezone to _config
b0b7717 Remove stray "117", combine lines in polyfill docs
8d63dad Rewrite Older Browsers polyfill section for clarity.
edd61ed Fix "Uncontrolled Components" documentation
d99cafa Fix typo in docs.
190f373 Update docs to mention that you need both es5-shim.js and
es5-sham.js to use React with IE8.
1873e1d Add dataType to all $.ajax calls for consistency
27ac8a3 Fix #845, Trivial year change
97f2441 Fix #874: Edit thinking-in-react
ce72e84 Document return value of unmountComponentAtNode
52ad24f Remove two more react.min.js references
7efdb43 Don't use the min build in getting started guide
51e7a6b Fix URL in displayName description
f44e8cc Add charCode/keyCode/which to key event docs
2014-01-15 11:42:32 -08: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/react.css">
<link rel="stylesheet" href="/react/css/syntax.css">
<link rel="stylesheet" href="/react/css/codemirror.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>