Chapter 5 of 20 · React for Beginners — Complete Free Tutorial
Props: Passing Data Between Components
Components in the React for Beginners series are useful because they are configurable: the same function can render a thousand different cards, avatars or rows. The mechanism for passing configuration from parent to child is called props — short for properties. This chapter covers passing data, reading it with destructuring, applying defaults, and the one rule you must never break.
Props are function arguments
Underneath the JSX, a component is an ordinary function, and props are simply its first parameter. Writing <UserCard name="Ada" role="admin" /> is equivalent to calling UserCard({ name: 'Ada', role: 'admin' }). JSX attribute syntax is just a friendly way to supply that object:
function UserCard({ name, role }) {
return (
<article className="card">
<h3>{name}</h3>
<p>Role: {role}</p>
</article>
);
}
export default function App() {
return <UserCard name="Ada" role="admin" />;
}
Expected output:
Ada
Role: admin
Destructuring in the parameter list ({ name, role }) unpacks the props object — the same destructuring you may know from objects and JSON.
Passing different kinds of data
Because JSX attributes are JavaScript, you can pass anything by placing it in braces. Strings can be written bare (role="admin"); every other type needs braces.
| Type | How to pass | Typical use |
|---|---|---|
| String | title="Hello" or title={"Hello"} | Labels, headings, ids |
| Number | count={3} | Scores, totals, indexes |
| Boolean | disabled or disabled={true} | Toggles, feature flags |
| Array / object | items={list} | Lists, configuration |
| Function | onSelect={handleSelect} | Callbacks — events flow back up (chapter 7) |
| Element | icon={<Star />} | Slots — composition (chapter 14) |
Omitting a value for a boolean prop passes true, which is why <Button disabled /> works.
Defaults and optional props
Real components accept optional inputs. Default parameter values in the destructuring give you safe fallbacks, and the logical OR operator handles empty cases:
function Badge({ label, tone = 'info', count = 0 }) {
const text = count > 0 ? `${label} (${count})` : label;
return <span className={`badge badge--${tone}`}>{text}</span>;
}
// Used three different ways:
// <Badge label="Inbox" /> → Inbox
// <Badge label="Inbox" count={12} /> → Inbox (12)
// <Badge label="Errors" tone="danger" count={2} />
Expected output:
Inbox
Inbox (12)
Errors (2)
Props drive the UI
The same component renders differently per parent — that is the entire point. A status widget can receive a variant prop and branch on it, keeping presentation decisions next to the markup they affect:
function Status({ state, message }) {
if (state === 'loading') return <p role="status">Loading…</p>;
if (state === 'error') return <p className="error">{message}</p>;
return <p className="ok">{message}</p>;
}
Expected output: whichever branch matches the prop — Loading…, the message in red, or the message in green. Parents own the data; children own the markup.
The read-only rule
Props are read-only. A component never writes to the object it received; to change something, the owner of the data updates its own state and passes new props down (chapter 6 and chapter 11 explain the mechanics). React enforces the spirit of this rule — reassigning name = 'Ravi' inside UserCard throws in StrictMode's development checks. Unidirectional data flow is what makes an application debuggable: to find where a value came from, you walk up the tree, never sideways.
Children: props you write as markup
Anything nested between a component's tags arrives as props.children — a single prop holding elements. It is why wrappers like <Card><h2>…</h2></Card> work. Chapter 14 is devoted to this pattern; here it is enough to know that children are ordinary props.
Common mistakes
- Typo in a prop name —
nmae="Ada"silently yieldsundefined; React will not warn about an unknown prop. - Passing a string where a number is expected —
count="12"plus arithmetic gives string concatenation; usecount={12}. - Mutating props inside the child — props belong to the parent; derive new values instead of editing the received object.
- Calling a callback prop during render —
onSave={save()}runs immediately; passonSave={save}and let the child decide when. - Boolean shorthand confusion — remember
disabledmeanstrue;disabled="false"is actually truthy.
Practice checklist
- Build a
Badgewithlabel,toneandcountdefaults; render it three ways with different data. - Pass an array of strings and render one list item per element with
map. - Pass a callback prop and log it from the child using
console.log(without calling it). - Intentionally misspell a prop, observe the
undefinedoutput, then fix it. - Draw a parent-child data flow diagram: which arrows carry props, which carry callbacks?
Props flow down, but something must change for the UI to respond — meet state in State with useState.
Frequently Asked Questions
React is a JavaScript library for building user interfaces from reusable components. It manages how your UI updates when data changes, so you describe what the screen should look like and React performs the efficient DOM updates. It is one of the most in-demand frontend skills and powers products from Netflix to Instagram, which makes it an excellent next step after core JavaScript.
You should be comfortable with functions, arrays and objects (map, filter, spread), destructuring, modules and basic async/await. React itself is written in plain JavaScript — JSX is a syntax layer on top. If any of those feel shaky, revisit the JavaScript fundamentals first and this series will go much faster.
React is a library focused only on the UI layer — you choose your own router, data layer and tooling. Angular is a full framework that ships routing, forms, HTTP client and testing conventions as one opinionated package. React's flexibility and huge ecosystem make it the common choice for teams that want to compose their own stack.
A component is a reusable function that returns UI. It receives input through props, keeps private data in state, and can render other components. Pages are composed by nesting small components (navbar, card list, footer) instead of one giant file, which keeps code testable and easy to change.
JSX is a syntax extension that looks like HTML but compiles to React's create() calls — it is a description of UI, not markup the browser parses. Small differences matter: class becomes className, style takes an object, and you embed JavaScript expressions inside curly braces. Once compiled, React turns that description into real DOM nodes.
Props are inputs passed from a parent — they are read-only inside the child, like function arguments. State is private, mutable data owned by a component; updating it triggers a re-render. The rule of thumb: values that come from outside the component are props; values that change over the component's lifetime are state.
Rendering means calling your component function to produce a description of the UI for the current state and props. It does not always mean DOM work — React compares the new description with the previous one (reconciliation) and applies only the differences to the real DOM. This is why updating state 100 times does not mean 100 full page rebuilds.
An effect runs after the component has committed to the screen — after render, not during it. You list dependencies in an array, and React re-runs the effect only when one of them changes. If the effect returns a cleanup function, React runs it before the next re-run and on unmount, which is where you cancel timers, abort fetches and remove listeners.
Use Vite. Create React App is effectively in maintenance mode, while Vite starts instantly (native ES modules) and builds fast, and it is the default choice for new React projects. This series uses Vite for every example — you only need Node.js installed to follow along.
React apps compile to static files (HTML, CSS and JavaScript), so any static host works: Netlify, Vercel, GitHub Pages or Cloudflare Pages. Run the production build, upload the dist folder, and configure a single-page-application fallback so unknown paths load index.html — routing chapters explain why that fallback is required.