{"id":"l-rf-2-2","courseId":"react-fundamentals","lang":"en","kind":"lesson","summary":"Pass data into components with props, destructure them with defaults, choose between passing objects and single values, and treat props as read-only snapshots.","html":"<p>Your <code dir=\"ltr\">MovieCard</code> from Section 1 always says “Arrival”. A component that can only show one movie isn’t reusable, it’s a template with one use. Props fix that: they are how a parent hands data to a child, in the same way arguments are how you hand data to a function.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">Passing and reading props</h2>\n<p>Pass props as attributes on the component’s tag:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"jsx\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">src/App.jsx</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">export</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> default</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> App</span><span style=\"color:#953800;--shiki-dark:#FFA657\">() </span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">{</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">main</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">      &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">MovieCard</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> title</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Arrival\"</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> year</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">2016</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> watched</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> /></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">      &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">MovieCard</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> title</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Past Lives\"</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> year</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">2023</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> watched</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">false</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> /></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    &#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">main</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  );</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>React collects them into one object, <code dir=\"ltr\">{ title: 'Arrival', year: 2016, watched: true }</code>, and passes it as the component’s first argument. You almost always destructure it right in the parameter list:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"jsx\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">src/components/MovieCard.jsx</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">export</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> default</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> MovieCard</span><span style=\"color:#953800;--shiki-dark:#FFA657\">({ title, year, watched }) </span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">{</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">article</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">      &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">h2</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">title</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">h2</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">      &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">p</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">year</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">p</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">      &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">p</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">watched </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">?</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'Watched'</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> :</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'To watch'</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">p</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    &#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">article</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  );</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>Three syntax details trip people up:</p>\n<ul>\n<li><strong>Quotes mean string.</strong> <code dir=\"ltr\">year=&quot;2016&quot;</code> passes the string “2016”. Use braces for anything else: <code dir=\"ltr\">year={2016}</code>, <code dir=\"ltr\">watched={false}</code>, <code dir=\"ltr\">genres={['drama', 'sci-fi']}</code>.</li>\n<li><strong>A bare attribute means <code dir=\"ltr\">true</code>.</strong> <code dir=\"ltr\">&lt;MovieCard watched /&gt;</code> is the same as <code dir=\"ltr\">watched={true}</code>, like <code dir=\"ltr\">disabled</code> in HTML.</li>\n<li><strong>Destructuring is optional.</strong> <code dir=\"ltr\">function MovieCard(props)</code> with <code dir=\"ltr\">props.title</code> works too. Destructuring documents which props the component expects at a glance, which is why most code uses it.</li>\n</ul>\n<h2 id=\"sec-2\" tabindex=\"-1\">Default values</h2>\n<p>Give a prop a default in the destructuring pattern:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"jsx\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">JSX</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">export</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> default</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> MovieCard</span><span style=\"color:#953800;--shiki-dark:#FFA657\">({ title, year, watched </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> false</span><span style=\"color:#953800;--shiki-dark:#FFA657\">, genres </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> [] }) </span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">{</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">article</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">      &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">h2</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">title</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">h2</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">      &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">p</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">year</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> · </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">genres.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">join</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">', '</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">||</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'No genres yet'</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">p</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">      &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">p</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">watched </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">?</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'Watched'</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> :</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'To watch'</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">p</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    &#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">article</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  );</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>Now <code dir=\"ltr\">&lt;MovieCard title=&quot;Dune&quot; year={2021} /&gt;</code> works without crashing on <code dir=\"ltr\">genres.join</code>. Defaults apply when a prop is missing or <code dir=\"ltr\">undefined</code>, but not when it’s <code dir=\"ltr\">null</code>. If your data can contain <code dir=\"ltr\">null</code>, handle it explicitly, for example with <code dir=\"ltr\">genres ?? []</code>.</p>\n<h2 id=\"sec-3\" tabindex=\"-1\">Objects or single values?</h2>\n<p>When a component is about one thing, pass that thing:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"jsx\" data-index=\"3\"><div class=\"code-head\"><span class=\"code-title\">JSX</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">MovieCard</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> movie</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">movie</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> /></span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> MovieCard</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">({ </span><span style=\"color:#953800;--shiki-dark:#FFA657\">movie</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> }) {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">h2</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">movie.title</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">h2</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>This keeps call sites short and the component’s purpose obvious. You’ll also see spreading, <code dir=\"ltr\">&lt;MovieCard {...movie} /&gt;</code>, which passes every field as its own prop. It’s convenient, but it hides what the component really uses and passes along fields it doesn’t need. Use it sparingly, typically in small wrapper components that forward props to an element.</p>\n<p>Passing single values has its own advantage: a component that takes <code dir=\"ltr\">title</code> and <code dir=\"ltr\">year</code> can show a movie, a book or a podcast episode. Choose based on how specific the component is. <code dir=\"ltr\">MovieCard</code> is about movies, so <code dir=\"ltr\">movie={movie}</code> is natural. A generic <code dir=\"ltr\">Card</code> should take plain values.</p>\n<h2 id=\"sec-4\" tabindex=\"-1\">Props are read-only snapshots</h2>\n<p>A component must never change its own props. Props belong to the parent’s render: they’re a snapshot of what the parent decided at that moment. In development React even freezes the props object, so assigning to it throws an error.</p>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">Common mistake</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Editing props to format them</span></p>\n<p><code dir=\"ltr\">props.year = '(' + props.year + ')'</code> looks harmless, but it writes to an object your component doesn’t own. Derive a new value instead: <code dir=\"ltr\">const label = '(' + year + ')'</code>, or a template literal. The rule is the same as for a pure function: read your inputs, return a result, change nothing.</p>\n</aside>\n<p>So how does a card ever change? The parent renders it again with different props. When <code dir=\"ltr\">App</code> later has the movies in state and one gets marked watched, <code dir=\"ltr\">App</code> re-renders and passes <code dir=\"ltr\">watched={true}</code> to that card. The card doesn’t update itself; it’s handed new data. That one-way flow, data down from parent to child, is what makes React apps predictable: to find out why a card shows something, you look up the tree.</p>\n<h2 id=\"sec-5\" tabindex=\"-1\">Passing functions</h2>\n<p>Props can be any value, including functions. That’s how a child tells its parent something happened:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"jsx\" data-index=\"4\"><div class=\"code-head\"><span class=\"code-title\">JSX</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">MovieCard</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> movie</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">movie</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> onToggle</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">() </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=></span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> toggleWatched</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(movie.id)</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> /></span></span></code></pre></div>\n<p>The <code dir=\"ltr\">on</code> prefix is a naming convention for callback props, matching DOM events like <code dir=\"ltr\">onClick</code>. You’ll use this pattern constantly in Section 3, where <code dir=\"ltr\">App</code> owns the state and children ask it to change.</p>\n<h2 id=\"sec-6\" tabindex=\"-1\"><code dir=\"ltr\">ref</code> is just a prop now</h2>\n<p>Sometimes a parent needs the actual DOM node inside a child, for example to focus the title input after adding a movie. In React 19 a function component receives <code dir=\"ltr\">ref</code> like any other prop and passes it to an element:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"jsx\" data-index=\"5\"><div class=\"code-head\"><span class=\"code-title\">JSX</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> TitleInput</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">({ </span><span style=\"color:#953800;--shiki-dark:#FFA657\">ref</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">...</span><span style=\"color:#953800;--shiki-dark:#FFA657\">rest</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> }) {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">input</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> ref</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">ref</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> {...</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">rest</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> />;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>Older code wraps components in <code dir=\"ltr\">forwardRef</code> to do this. You don’t need it in React 19, and it’s expected to be deprecated. One prop is still special: <code dir=\"ltr\">key</code>, which you’ll meet with lists, is read by React and never reaches your component.</p>\n<aside class=\"callout callout-tip\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\"/><path d=\"M9 18h6\"/><path d=\"M10 22h4\"/></svg><span><span class=\"callout-kind\">Tip</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Keep prop lists short</span></p>\n<p>If a component takes ten props, it’s usually doing two jobs. Look for a group of props that always travel together and either pass them as one object or split the component.</p>\n</aside>\n<p>Props let a parent configure a child with data. Next, you’ll see how to pass whole chunks of JSX into a component with <code dir=\"ltr\">children</code>, and how that builds flexible layouts.</p>\n","toc":[{"id":"sec-1","text":"Passing and reading props","level":2},{"id":"sec-2","text":"Default values","level":2},{"id":"sec-3","text":"Objects or single values?","level":2},{"id":"sec-4","text":"Props are read-only snapshots","level":2},{"id":"sec-5","text":"Passing functions","level":2},{"id":"sec-6","text":"ref is just a prop now","level":2}],"takeaways":["Props are the arguments of a component; React passes them as a single object that you usually destructure in the parameter list.","Strings can be passed in quotes; every other value, including numbers and booleans, goes in curly braces.","Default values in destructuring (<code dir=\"ltr\">watched = false</code>) apply only when the prop is missing or <code dir=\"ltr\">undefined</code>.","A component must never change its props; to change what’s shown, the parent passes new props.","In React 19, <code dir=\"ltr\">ref</code> is an ordinary prop on function components, so <code dir=\"ltr\">forwardRef</code> is no longer needed."],"further":[{"title":"Passing Props to a Component","url":"https://react.dev/learn/passing-props-to-a-component"},{"title":"Keeping Components Pure","url":"https://react.dev/learn/keeping-components-pure"},{"title":"Manipulating the DOM with Refs (ref as a prop)","url":"https://react.dev/learn/manipulating-the-dom-with-refs"}],"quiz":[{"q":"<p>What does <code dir=\"ltr\">MovieCard</code> receive for <code dir=\"ltr\">year</code> here? <code dir=\"ltr\">&lt;MovieCard title=&quot;Arrival&quot; year=&quot;2016&quot; /&gt;</code></p>","options":[{"text":"The number 2016.","why":"Quoted values are always strings in JSX. To pass a number, use braces, <code dir=\"ltr\">year={2016}</code>."},{"text":"Nothing, because <code dir=\"ltr\">year</code> must be declared in advance.","why":"Components accept any props you pass; there’s no declaration step in plain JavaScript React."},{"text":"The string “2016”.","why":"Correct. Quotes pass a string literal. It displays the same, but <code dir=\"ltr\">year + 1</code> gives “20161” instead of 2017."},{"text":"An error, because numbers can’t be props.","why":"Any JavaScript value can be a prop, including numbers, objects, arrays and functions."}],"answer":2},{"q":"<p><code dir=\"ltr\">MovieCard</code> is declared as <code dir=\"ltr\">function MovieCard({ title, watched = false })</code>. The parent renders <code dir=\"ltr\">&lt;MovieCard title=&quot;Dune&quot; watched={null} /&gt;</code>. What is <code dir=\"ltr\">watched</code> inside the component?</p>\n","options":[{"text":"<code dir=\"ltr\">null</code>","why":"Correct. Destructuring defaults only replace <code dir=\"ltr\">undefined</code>. An explicit <code dir=\"ltr\">null</code> is passed through unchanged."},{"text":"<code dir=\"ltr\">false</code>","why":"The default would apply if the prop were missing or <code dir=\"ltr\">undefined</code>, but <code dir=\"ltr\">null</code> is a real value."},{"text":"<code dir=\"ltr\">undefined</code>","why":"The parent passed <code dir=\"ltr\">null</code>, and React passes props through as they are."}],"answer":0},{"q":"<p>This component is meant to show the year as “(2016)”. What’s wrong with it?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"jsx\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">JSX</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> MovieCard</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">props</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) {</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  props.year </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> `(${</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">props</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">.</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">year</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">})`</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">p</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">props.title</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> {</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">props.year</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">p</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n","options":[{"text":"Nothing; it’s the normal way to format props.","why":"Writing to props breaks React’s contract. The props object belongs to the parent’s render."},{"text":"Template literals aren’t allowed in components.","why":"Template literals are ordinary JavaScript and fine anywhere. The assignment is the problem."},{"text":"It should use <code dir=\"ltr\">this.props</code> instead.","why":"<code dir=\"ltr\">this.props</code> belongs to class components. Function components get props as their argument."},{"text":"It mutates props. Compute a new value instead, such as <code dir=\"ltr\">const label = '(' + year + ')'</code>.","why":"Correct. Props are read-only snapshots. In development React freezes the props object, so the assignment throws a TypeError, and even where it didn’t, the change would vanish on the next render."}],"answer":3},{"q":"<p>You have a <code dir=\"ltr\">movie</code> object with <code dir=\"ltr\">id</code>, <code dir=\"ltr\">title</code>, <code dir=\"ltr\">year</code> and <code dir=\"ltr\">watched</code>. <code dir=\"ltr\">MovieItem</code> only displays the title and the watched status. Which call is the clearest default?</p>","options":[{"text":"<code dir=\"ltr\">&lt;MovieItem {...movie} /&gt;</code>, because spreading is shorter.","why":"Spreading hides which props the component really uses and passes <code dir=\"ltr\">id</code> and <code dir=\"ltr\">year</code> it doesn’t need. Fine occasionally, unclear as a habit."},{"text":"<code dir=\"ltr\">&lt;MovieItem movie={movie} /&gt;</code>, and the component reads <code dir=\"ltr\">movie.title</code> and <code dir=\"ltr\">movie.watched</code>.","why":"Correct. Passing the whole object keeps calls short and is a common, readable default when the component is about that thing."},{"text":"<code dir=\"ltr\">&lt;MovieItem data={JSON.stringify(movie)} /&gt;</code>","why":"Props can be objects. Serializing to a string adds work and loses the structure."}],"answer":1}],"exercise":{"kind":"web","mode":"react","starter":{"jsx":"function MovieCard() {\n  return (\n    <article>\n      <h2>Arrival</h2>\n      <p>2016</p>\n      <p>To watch</p>\n    </article>\n  );\n}\n\nexport default function App() {\n  return (\n    <main>\n      <MovieCard />\n      <MovieCard />\n      <MovieCard />\n    </main>\n  );\n}\n"},"solution":{"jsx":"function MovieCard({ title, year, watched = false }) {\n  return (\n    <article>\n      <h2>{title}</h2>\n      <p>{year}</p>\n      <p>{watched ? 'Watched' : 'To watch'}</p>\n    </article>\n  );\n}\n\nexport default function App() {\n  return (\n    <main>\n      <MovieCard title=\"Arrival\" year={2016} watched />\n      <MovieCard title=\"Past Lives\" year={2023} />\n      <MovieCard title=\"Paddington 2\" year={2017} watched={false} />\n    </main>\n  );\n}\n"},"checks":[{"id":"titles","test":"const a = $$('article'); return a.length === 3 && a.map((x) => text(x.querySelector('h2'))).join('|') === 'Arrival|Past Lives|Paddington 2';"},{"id":"years","test":"const a = $$('article'); return a.length === 3 && ['2016', '2023', '2017'].every((y, i) => text(a[i]).includes(y));"},{"id":"watched-status","test":"const a = $$('article'); return a.length === 3 && text(a[0]).includes('Watched') && !text(a[0]).includes('To watch');"},{"id":"default-status","test":"const a = $$('article'); return a.length === 3 && [a[1], a[2]].every((x) => text(x).includes('To watch') && !text(x).includes('Watched'));"}],"title":"Make MovieCard reusable","prompt":"<p>Every card says “Arrival”. Give <code dir=\"ltr\">MovieCard</code> three props, <code dir=\"ltr\">title</code>, <code dir=\"ltr\">year</code> and <code dir=\"ltr\">watched</code>, and use them:</p>\n<ul>\n<li><code dir=\"ltr\">&lt;h2&gt;</code> shows the title, a <code dir=\"ltr\">&lt;p&gt;</code> shows the year.</li>\n<li>Another <code dir=\"ltr\">&lt;p&gt;</code> shows <strong>Watched</strong> when <code dir=\"ltr\">watched</code> is true and <strong>To watch</strong> otherwise. Default <code dir=\"ltr\">watched</code> to <code dir=\"ltr\">false</code>.</li>\n</ul>\n<p>Then render these three cards in <code dir=\"ltr\">App</code>, in this order:</p>\n<div class=\"table-wrap\" role=\"region\" aria-label=\"Scrollable table\" tabindex=\"0\"><table><thead>\n<tr>\n<th>title</th>\n<th>year</th>\n<th>watched</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Arrival</td>\n<td>2016</td>\n<td>true</td>\n</tr>\n<tr>\n<td>Past Lives</td>\n<td>2023</td>\n<td><em>(don’t pass it)</em></td>\n</tr>\n<tr>\n<td>Paddington 2</td>\n<td>2017</td>\n<td>false</td>\n</tr>\n</tbody>\n</table></div>","hints":["Destructure the props in the parameter list: <code dir=\"ltr\">function MovieCard({ title, year, watched = false })</code>.","Numbers and booleans go in braces: <code dir=\"ltr\">year={2016}</code>. A bare <code dir=\"ltr\">watched</code> means <code dir=\"ltr\">watched={true}</code>.","Choose the status text with a ternary: <code dir=\"ltr\">{watched ? 'Watched' : 'To watch'}</code>."],"explanation":"<p><code dir=\"ltr\">MovieCard</code> is now a function of its props. The default <code dir=\"ltr\">watched = false</code> covers the Past Lives card, which doesn’t pass the prop at all, so <code dir=\"ltr\">watched</code> arrives as <code dir=\"ltr\">undefined</code> and the default kicks in. Numbers and booleans need braces; a quoted <code dir=\"ltr\">year=&quot;2016&quot;</code> would pass a string, which looks the same here but behaves differently in arithmetic and comparisons.</p>\n","checkLabels":{"titles":"Three cards titled Arrival, Past Lives and Paddington 2, in that order","years":"Each card shows its own year","watched-status":"Arrival shows “Watched”","default-status":"Past Lives and Paddington 2 show “To watch”"}},"words":709,"readMinutes":3}