Components and Props

Reviewed & published by Brayan K

By the end of this lesson you'll be able to build reusable function components, pass data into them with props, nest them to compose a screen, render lists with .map(), and show or hide content conditionally — the core skills behind every React UI.

Part of the free React course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

What You'll Learn

1️⃣ Function Components

A React component is simply a JavaScript function that returns JSX (the HTML-like markup describing what to show). “Rendering” a component just means React calls that function and uses what it returns. Define it once, reuse it anywhere. One non-negotiable rule: a component name must start with a capital letter (PascalCase) — React reads lowercase tags as plain HTML, so <greeting /> would silently do nothing.

Here's a complete component. Read it first — every part has a job:

// A function component — note the Capital G.
function Greeting() {
  return <h1>Hello, World!</h1>;   // returns JSX (its UI)
}

// You "use" it like an HTML tag, and you can reuse it freely:
function App() {
  return (
    <div>
      <Greeting />
      <Greeting />    
    </div>
  );
}

The demo below runs the same idea as plain JavaScript so you can watch a function return its output and be reused — exactly what React does when it renders a component.

// A React component is just a function that RETURNS its UI.
// Here we run the same idea as plain JavaScript so you can see the output.

function greeting() {
  return "Hello, World!";   // In React this 'return' produces <h1>Hello, World!</h1>
}

// "Rendering" a component = calling its function and using what comes back.
console.log(greeting());   // Hello, World!
console.log(greeting());   // Hello, World!  (reuse it as many times as you like)
console.log(greeting());   // Hello, World!

// One definition, three results — that is the whole point of a component.

Now your turn. A component returns its output, so build a function that returns a string (don't console.log inside it). Fill in the blank:

// 🎯 YOUR TURN — fill in each ___ then press "Try it Yourself".
// A component is a function that returns its output. Build that function.

// 1) Make a function called "welcome" that takes a name
function welcome(name) {
  // 2) Return a greeting string that includes the name.
  //    Use a template literal with backticks: `...${name}...`
  return ___;        // 👉 e.g. `Welcome, ${name}!`
}

console.log(welcome("Ada"));
console.log(welcome("Linus"));

// ✅ Expected output:
//    Welcome, Ada!
//    Welcome, Linus!

2️⃣ Props — Passing Data Down

Props (short for “properties”) are how a parent component hands data to a child. They behave just like function arguments, and they all arrive bundled into a single object called props. Two habits make them pleasant to work with: destructuring (pull the fields you need straight out in the parameter list) and default values (a fallback used when a prop isn't passed).

Critically, props are read-only. A component must never change its own props — that's data flowing down from the parent, and rewriting it breaks React's mental model. (When data needs to change, you'll use state — the next lesson.)

// Destructure name, age, role from props. role defaults to "Member".
function UserCard({ name, age, role = "Member" }) {
  return (
    <div className="card">
      <h2>{name}</h2>
      <p>Age: {age}</p>
      <p>Role: {role}</p>
    </div>
  );
}

// The parent passes data as attributes. Strings use "quotes";
// any other value (numbers, booleans) goes inside { curly braces }.
<UserCard name="Alice" age={28} role="Developer" />
<UserCard name="Cleo"  age={22} />

The demo passes those same prop objects into a plain function so you can see destructuring and a default prop actually run:

// PROPS = the data a parent passes into a child. They arrive as one object.
// In React you'd write <UserCard name="Alice" age={28} />.
// That object is exactly what we pass to the function below.

// Destructuring pulls fields straight out of the props object.
// 'role = "Member"' is a DEFAULT — used only when role isn't passed.
function userCard({ name, age, role = "Member" }) {
  return `[${name} | age ${age} | ${role}]`;
}

console.log(userCard({ name: "Alice", age: 28, role: "Developer" }));
// [Alice | age 28 | Developer]

console.log(userCard({ name: "Bob", age: 34, role: "Designer" }));
// [Bob | age 34 | Designer]

console.log(userCard({ name: "Cleo", age: 22 }));   // role left out
// [Cleo | age 22 | Member]   ← the default kicked in

// Props are READ-ONLY: a component must never reassign its own props.

3️⃣ Children & Composition

Everything you put between a component's opening and closing tags arrives as a special prop called children. That lets you build generic wrappers — a Card, a Modal — that don't care what they contain. This is composition: building complex UIs by nesting small, focused components, which React prefers over inheritance.

function Card({ children }) {
  return <div className="card">{children}</div>;   // render whatever was passed in
}

// Compose a whole page by nesting components inside each other:
function App() {
  return (
    <Page>
      <Header>
        <Logo />
        <NavMenu />
      </Header>
      <Card>
        <h2>Welcome back!</h2>      
        <p>Glad to see you.</p>
      </Card>
    </Page>
  );
}

Composition keeps each component small and reusable: Card handles the border and padding once, and every screen reuses it with different children.

4️⃣ Rendering Lists with .map()

UIs are full of repeated rows — a to-do list, search results, a menu. You don't write each one by hand; you take an array and transform it into UI with .map(), which returns a new array containing one element per item. Each element needs a key: a stable, unique id React uses to track rows when the list changes. Use a real id from your data — never the array index if items can be reordered, added, or removed.

function FruitList() {
  const fruits = ["Apple", "Banana", "Cherry"];
  return (
    <ul>
      {fruits.map(fruit => (
        <li key={fruit}>{fruit}</li>   // key = unique id for this row
      ))}
    </ul>
  );
}

The demo runs the .map() behind that JSX so you can see exactly what it builds — one line per item:

// RENDERING A LIST = take an array, turn each item into a piece of UI.
// The tool is Array.map(): it returns a NEW array, one result per item.

const fruits = ["Apple", "Banana", "Cherry"];

// In React:  {fruits.map(f => <li key={f}>{f}</li>)}
// Here we build the matching <li> strings so you can see what map produces:
const items = fruits.map(fruit => `<li key="${fruit}">${fruit}</li>`);

items.forEach(line => console.log(line));
// <li key="Apple">Apple</li>
// <li key="Banana">Banana</li>
// <li key="Cherry">Cherry</li>

// The 'key' is a unique id React uses to track each row efficiently.
// Without it React warns and list updates can glitch.
// 🎯 YOUR TURN — fill in each ___ then run it.
// Turn this array of users into one <li> string per user.

const users = [
  { id: 1, name: "Sam" },
  { id: 2, name: "Mia" },
  { id: 3, name: "Tom" },
];

// 1) Use .map() to build a string for each user.
// 2) Each string should use user.id as the key and show user.name.
const rows = users.map(user => `<li key="${___}">${___}</li>`);
//                                              👆 user.id   👆 user.name

rows.forEach(line => console.log(line));

// ✅ Expected output:
//    <li key="1">Sam</li>
//    <li key="2">Mia</li>
//    <li key="3">Tom</li>
function Profile({ isLoggedIn, unread }) {
  return (
    <div>
       
      {isLoggedIn ? <Dashboard /> : <LoginButton />}

       
      {unread > 0 && <Badge count={unread} />}
    </div>
  );
}
// CONDITIONAL RENDERING = decide what UI to show based on a condition.

// 1) Ternary  (condition ? whenTrue : whenFalse)  — pick ONE of two things.
function statusLabel(isOnline) {
  return isOnline ? "🟢 Online" : "⚫ Offline";   // In JSX: {isOnline ? ... : ...}
}
console.log(statusLabel(true));    // 🟢 Online
console.log(statusLabel(false));   // ⚫ Offline

// 2) && (logical AND) — show something ONLY when the condition is true.
//    In JSX:  {count > 0 && <Badge />}
//    If the left side is false, React renders nothing (no badge).
function maybeBadge(count) {
  return count > 0 && `🔔 ${count} new`;   // false  OR  the string
}
console.log(maybeBadge(3));   // 🔔 3 new
console.log(maybeBadge(0));   // false  → in React this renders NOTHING

// ⚠️ Gotcha: {count && <X/>} renders the number 0 when count is 0.
//    Use a real boolean test instead:  {count > 0 && <X/>}.
// ❌ Error: two root elements, nothing wrapping them
function Bad() {
  return (
    <h1>Title</h1>
    <p>Subtitle</p>
  );
}

// ✅ Fragment groups them — no extra <div> in the output
function Good() {
  return (
    <>
      <h1>Title</h1>
      <p>Subtitle</p>
    </>
  );
}
// === A small "team list" — composition + list + conditionals together ===

const team = [
  { id: 1, name: "Alice", isAdmin: true,  posts: 42 },
  { id: 2, name: "Bob",   isAdmin: false, posts: 0  },
  { id: 3, name: "Cleo",  isAdmin: false, posts: 15 },
];

// One small "component" (function) renders ONE member.
function memberLine({ name, isAdmin, posts }) {
  const role = isAdmin ? "👑 Admin" : "👤 User";          // ternary
  const activity = posts > 0 ? `${posts} posts` : "No posts yet"; // ternary
  return `${role} ${name} — ${activity}`;
}

// The "parent" maps the array, calling the child for each member.
team.map(member => memberLine(member)).forEach(line => console.log(line));
// 👑 Admin Alice — 42 posts
// 👤 User Bob — No posts yet
// 👤 User Cleo — 15 posts

Pro Tips

📋 Quick Reference

PatternSyntax
Componentfunction Name() { return <div />; }
Use it<Name />
Props + destructurefunction Card({ title, children }) {}
Default prop{ color = "blue" }
Pass a number/bool<Card count={3} open={true} />
List{items.map(i => <li key={i.id}>{i.name}</li>)}
Ternary{ok ? <Yes /> : <No />}
Show if true{count > 0 && <Badge />}
Fragment<><h1/><p/></>

Frequently Asked Questions

Q: Why must component names start with a capital letter?

React decides what a tag means by its case. Lowercase tags like <div> are treated as built-in HTML; capitalised tags like <Greeting> are treated as your components. Lowercase your component and React looks for an HTML element of that name and renders nothing useful.

Q: What exactly is the key for, and can I use the array index?

The key gives React a stable identity for each list item so it can update the minimum needed when the list changes. A real, unique id (e.g. item.id) is best. The array index works only if the list never reorders, inserts, or deletes — otherwise it causes subtle bugs.

Q: Props vs state — what's the difference?

Props are passed in from a parent and are read-only to the child. State is data a component owns and can change over time. This lesson is all props; state is next.

Q: When should I reach for a Fragment instead of a <div>?

Use a Fragment <>...</> whenever you only need to group elements to satisfy the “one root” rule and an extra <div> would mess up your layout or semantics (e.g. inside a table row or a flex container).

Mini-Challenge: Product List

No blanks this time — just a brief and a starter array. Map the products into display lines and add a sale tag conditionally. Run it and check your output against the example in the comments. This is the exact pattern real product pages are built from.

// 🎯 MINI-CHALLENGE: Product list
// You have an array of products. Build one display line per product.
//
// 1. Map over 'products' to create one string per item.
// 2. Each line should show the name and price, e.g. "Mug — £8".
// 3. If a product is on sale (onSale === true), add " (SALE!)" to the line.
//    Hint: use && or a ternary for the sale tag.
// 4. console.log every line.
//
// ✅ Expected output:
//    Mug — £8
//    Hoodie — £35 (SALE!)
//    Sticker — £2

const products = [
  { id: 1, name: "Mug",     price: 8,  onSale: false },
  { id: 2, name: "Hoodie",  price: 35, onSale: true  },
  { id: 3, name: "Sticker", price: 2,  onSale: false },
];

// your code here

🎉 Lesson Complete

Practice quiz

What must a React function component return to describe its UI?

  • A string of HTML
  • A DOM node created with document.createElement
  • JSX (or null)
  • An object with a render method

Answer: JSX (or null). A function component returns JSX (or null/strings/arrays). React turns that JSX into the actual DOM.

Why must a component's name start with a capital letter?

  • React treats lowercase tags as built-in HTML elements
  • It is only a style convention with no effect
  • Lowercase names cause a syntax error
  • It changes how props are passed

Answer: React treats lowercase tags as built-in HTML elements. React reads <greeting /> as the HTML tag 'greeting'. Capitalized names like <Greeting /> are treated as your components.

How does a parent pass data to a child component?

  • Through global variables
  • By mutating the child's state
  • Through the children array only
  • Through props (attributes on the JSX tag)

Answer: Through props (attributes on the JSX tag). Props are passed as attributes and arrive bundled as a single props object in the child.

What is true about props in React?

  • A component may reassign its own props freely
  • They are read-only inside the component that receives them
  • They are always strings
  • They can only be passed to class components

Answer: They are read-only inside the component that receives them. Props are read-only. A component must never reassign the props it receives; data flows down from the parent.

How do you pass a non-string value like a number as a prop?

  • count={3}
  • count="3"
  • count=(3)
  • count: 3

Answer: count={3}. Strings use quotes; any other JS value (numbers, booleans, objects) goes inside curly braces: count={3}.

Whatever you nest between a component's opening and closing tags arrives as which prop?

  • content
  • slot
  • children
  • inner

Answer: children. Nested content is passed as the special children prop, which the component renders with {children}.

When rendering a list with .map(), what does the key prop do?

  • It sets the CSS class of each item
  • It gives React a stable identity to track each item across renders
  • It sorts the list
  • It is required only for class components

Answer: It gives React a stable identity to track each item across renders. key is a stable unique id React uses to track each row efficiently when the list changes.

Which is the recommended value for a list item's key?

  • The array index always
  • Math.random()
  • The item's text content
  • A stable unique id from the data (e.g. item.id)

Answer: A stable unique id from the data (e.g. item.id). Use a stable, unique id. The array index is risky if items can reorder, insert, or delete.

What does {count && <Badge />} render when count is 0?

  • Nothing
  • A literal 0 on screen
  • The Badge component
  • An error

Answer: A literal 0 on screen. 0 is falsy, so && returns 0 and React renders the literal 0. Use {count > 0 && <Badge />} instead.

What lets a component return multiple sibling elements without adding an extra DOM node?

  • A <div> wrapper
  • An array literal
  • A Fragment, written <>...</>
  • The children prop

Answer: A Fragment, written <>...</>. A Fragment (<>...</> or <React.Fragment>) groups elements to satisfy the one-root rule without an extra node.

Continue this course

Related lessons