Web Development / React

React Components - Building Reusable UI

Master React components - the building blocks of React applications. Learn functional components, props, component composition, and build a user profile card example.

Intermediate
⏱️ 16 minutes📚 Prerequisites: javascript-functions, html-introduction

Introduction

What You'll Learn

  • What React components are and why they matter
  • Functional components vs class components
  • Understanding and using props
  • Component composition patterns
  • JSX syntax and best practices
  • Building reusable components
  • Creating a complete user profile card component

Why This Topic is Important

Components are the heart of React. They allow you to break your UI into reusable, independent pieces. Understanding components is essential for building modern React applications. Components make code more maintainable, testable, and reusable.

Real-World Applications

  • Building user interfaces
  • Creating reusable UI libraries
  • Developing single-page applications
  • Building component-based design systems
  • Creating interactive web applications
  • Developing mobile apps with React Native
  • Building dashboards and admin panels

Learning Objectives

  • Understand React component concepts
  • Create functional components
  • Use props to pass data
  • Compose components together
  • Write clean JSX code
  • Build reusable component patterns
  • Create a complete component example

What are React Components?

A React component is a reusable piece of code that returns JSX (JavaScript XML) to describe what should appear on the screen. Components are like JavaScript functions, but they return UI elements instead of values.

Think of components as building blocks. Just like you can build a house from bricks, you can build a user interface from components. Each component is independent and can be reused throughout your application.

📝 Note

React components must start with a capital letter. This is how React distinguishes components from regular HTML elements.

Functional Components

Functional components are the modern way to write React components. They're simply JavaScript functions that return JSX.

JAVASCRIPT
// Simple functional component
function Welcome() {
  return <h1>Hello, World!</h1>;
}

// Arrow function component
const Welcome = () => {
  return <h1>Hello, World!</h1>;
};

// Using the component
function App() {
  return (
    <div>
      <Welcome />
      <Welcome />
      <Welcome />
    </div>
  );
}

Components are defined as functions that return JSX. You can use them like HTML tags. This example shows the Welcome component used three times.

JSX Syntax

JSX looks like HTML but it's actually JavaScript. It allows you to write HTML-like code in your JavaScript files.

JAVASCRIPT
// JSX with JavaScript expressions
function Greeting() {
  const name = "Alice";
  const age = 25;
  
  return (
    <div>
      <h1>Hello, {name}!</h1>
      <p>You are {age} years old.</p>
      <p>Next year you'll be {age + 1}.</p>
    </div>
  );
}

// JSX with conditional rendering
function Message({ isLoggedIn }) {
  return (
    <div>
      {isLoggedIn ? (
        <p>Welcome back!</p>
      ) : (
        <p>Please log in.</p>
      )}
    </div>
  );
}

// JSX with lists
function TodoList() {
  const todos = ['Learn React', 'Build app', 'Deploy'];
  
  return (
    <ul>
      {todos.map((todo, index) => (
        <li key={index}>{todo}</li>
      ))}
    </ul>
  );
}

JSX allows you to embed JavaScript expressions in curly braces `{}`. You can use variables, expressions, conditionals, and loops.

💡 Tip

In JSX, you must use `className` instead of `class`, and `htmlFor` instead of `for`, because `class` and `for` are reserved words in JavaScript.

Props: Passing Data to Components

Props (short for properties) allow you to pass data from a parent component to a child component. Props are read-only and cannot be modified by the child component.

JAVASCRIPT
// Component that accepts props
function Greeting({ name, age }) {
  return (
    <div>
      <h1>Hello, {name}!</h1>
      <p>You are {age} years old.</p>
    </div>
  );
}

// Using the component with props
function App() {
  return (
    <div>
      <Greeting name="Alice" age={25} />
      <Greeting name="Bob" age={30} />
      <Greeting name="Charlie" age={28} />
    </div>
  );
}

// Props with default values
function Button({ text = "Click me", color = "blue" }) {
  return (
    <button style={{ backgroundColor: color }}>
      {text}
    </button>
  );
}

Props are passed as attributes to components. You can destructure props in the function parameters. Props can have default values.

📊 Diagram:

React Props Flow: Parent component "App" at top with data (name="Alice", age=25). Arrow pointing down to child component "Greeting" showing props being passed. Greeting component displays the data. Multiple Greeting components shown side by side with different props.

Alt text: React props data flow diagram

Component Composition

Component composition means building complex UIs by combining smaller components. This is one of React's greatest strengths.

JAVASCRIPT
// Small, reusable components
function Card({ title, children }) {
  return (
    <div className="card">
      <h2>{title}</h2>
      {children}
    </div>
  );
}

function Button({ text, onClick }) {
  return (
    <button onClick={onClick} className="btn">
      {text}
    </button>
  );
}

// Composing components together
function App() {
  return (
    <div>
      <Card title="Welcome">
        <p>This is the welcome card.</p>
        <Button text="Get Started" onClick={() => alert('Clicked!')} />
      </Card>
      
      <Card title="About">
        <p>This is the about card.</p>
        <Button text="Learn More" onClick={() => alert('Learn more!')} />
      </Card>
    </div>
  );
}

By breaking UI into small, reusable components, you can compose them together to build complex interfaces. The `children` prop allows components to contain other components.

Complete Example: User Profile Card

Let's build a complete, reusable user profile card component:

JAVASCRIPT
// User Profile Card Component
function UserProfileCard({ user }) {
  const { name, email, avatar, bio, followers, following } = user;
  
  return (
    <div className="profile-card">
      <div className="profile-header">
        <img src={avatar} alt={name} className="avatar" />
        <h2>{name}</h2>
        <p className="email">{email}</p>
      </div>
      
      <div className="profile-body">
        <p className="bio">{bio}</p>
      </div>
      
      <div className="profile-stats">
        <div className="stat">
          <span className="stat-value">{followers}</span>
          <span className="stat-label">Followers</span>
        </div>
        <div className="stat">
          <span className="stat-value">{following}</span>
          <span className="stat-label">Following</span>
        </div>
      </div>
      
      <button className="follow-button">Follow</button>
    </div>
  );
}

// Using the component
function App() {
  const user1 = {
    name: "Alice Johnson",
    email: "alice@example.com",
    avatar: "https://example.com/avatar1.jpg",
    bio: "Software developer passionate about React and web development.",
    followers: 1250,
    following: 320
  };
  
  const user2 = {
    name: "Bob Smith",
    email: "bob@example.com",
    avatar: "https://example.com/avatar2.jpg",
    bio: "Designer and creative thinker.",
    followers: 890,
    following: 150
  };
  
  return (
    <div className="app">
      <UserProfileCard user={user1} />
      <UserProfileCard user={user2} />
    </div>
  );
}

This complete example shows a reusable profile card component that accepts a user object as a prop and displays all the user information in a structured way.

CSS
/* Profile Card Styles */
.profile-card {
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: 20px;
  max-width: 300px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.profile-header {
  text-align: center;
  margin-bottom: 20px;
}

.avatar {
  width: 80px;
  height: 80px;
  border-radius: 50%;
  margin-bottom: 10px;
}

.profile-body {
  margin-bottom: 20px;
}

.bio {
  color: #666;
  font-size: 14px;
}

.profile-stats {
  display: flex;
  justify-content: space-around;
  margin-bottom: 20px;
  padding-top: 20px;
  border-top: 1px solid #eee;
}

.stat {
  text-align: center;
}

.stat-value {
  display: block;
  font-size: 20px;
  font-weight: bold;
}

.stat-label {
  display: block;
  font-size: 12px;
  color: #666;
}

.follow-button {
  width: 100%;
  padding: 10px;
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

CSS styles for the profile card component. These styles make the component look professional and polished.

Best practice

Keep components small and focused on a single responsibility. If a component is doing too much, break it into smaller components.

Component Best Practices

  • Keep components small and focused
  • Use descriptive component names (PascalCase)
  • Extract reusable logic into separate components
  • Use props for configuration, not for everything
  • Keep components pure when possible (same props = same output)
  • Use meaningful prop names
  • Provide default values for optional props
  • Document components with comments

📊 Comparison:

Good vs Bad Component Design: Left side "Good" shows small, focused components like Button, Card, Header. Right side "Bad" shows one large component doing everything. Green checkmarks on good design, red X on bad design.

Alt text: Component design best practices comparison

Practical Examples

Example 1: Simple Button Component

function Button({ text, onClick }) {
  return (
    <button onClick={onClick} className="btn">
      {text}
    </button>
  );
}

function App() {
  return (
    <div>
      <Button text="Click Me" onClick={() => alert('Clicked!')} />
      <Button text="Submit" onClick={() => console.log('Submitted')} />
    </div>
  );
}

A simple, reusable button component that accepts text and onClick handler as props.

Example 2: Card Component with Children

function Card({ title, children }) {
  return (
    <div className="card">
      <h2>{title}</h2>
      <div className="card-content">
        {children}
      </div>
    </div>
  );
}

function App() {
  return (
    <Card title="Welcome">
      <p>This is card content.</p>
      <button>Action</button>
    </Card>
  );
}

Card component that accepts children, allowing flexible content composition.

Example 3: List Component

function List({ items }) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{item}</li>
      ))}
    </ul>
  );
}

function App() {
  const fruits = ['Apple', 'Banana', 'Orange'];
  return <List items={fruits} />;
}

List component that renders an array of items. Always use a unique key prop when rendering lists.

Example 4: Conditional Rendering Component

function UserGreeting({ isLoggedIn, username }) {
  if (isLoggedIn) {
    return <h1>Welcome back, {username}!</h1>;
  }
  return <h1>Please log in.</h1>;
}

function App() {
  return (
    <div>
      <UserGreeting isLoggedIn={true} username="Alice" />
      <UserGreeting isLoggedIn={false} />
    </div>
  );
}

Component that conditionally renders different content based on props.

Example 5: Composed Dashboard Component

function Header({ title }) {
  return <header><h1>{title}</h1></header>;
}

function Sidebar({ items }) {
  return (
    <aside>
      <ul>
        {items.map(item => <li key={item}>{item}</li>)}
      </ul>
    </aside>
  );
}

function Main({ content }) {
  return <main>{content}</main>;
}

function Dashboard() {
  return (
    <div>
      <Header title="My Dashboard" />
      <Sidebar items={['Home', 'About', 'Contact']} />
      <Main content={<p>Dashboard content here</p>} />
    </div>
  );
}

Complex component composed of smaller components, demonstrating component composition.

Quiz: Test Your Knowledge

1. What is JSX?

2. How do you pass data to a React component?

3. What must React component names start with?

4. What is component composition?

5. In JSX, what should you use instead of the HTML `class` attribute?

Practice Exercises

Exercise 1: Create a Product Card Component

Build a reusable product card component that displays product name, price, and image. Accept these as props.

Show Hints
  • Create a functional component
  • Accept name, price, and imageUrl as props
  • Use JSX to structure the card
  • Add some basic styling
Show Solution
function ProductCard({ name, price, imageUrl }) {
  return (
    <div className="product-card">
      <img src={imageUrl} alt={name} />
      <h3>{name}</h3>
      <p className="price">${price}</p>
    </div>
  );
}

Exercise 2: Build a Navigation Component

Create a navigation component that accepts an array of links and renders them as a navigation menu.

Show Hints
  • Accept links array as prop
  • Map over the links array
  • Render each link as an anchor tag
  • Use key prop for list items

Exercise 3: Create a Modal Component

Build a modal component that accepts title, content, and a close function. Use conditional rendering to show/hide it.

Show Hints
  • Accept isOpen, title, children, and onClose props
  • Conditionally render based on isOpen
  • Add a close button that calls onClose
  • Style it as an overlay

Exercise 4: Build a Form Input Component

Create a reusable input component that accepts label, type, value, and onChange handler.

Show Hints
  • Accept label, type, value, onChange as props
  • Use label element for accessibility
  • Connect input value and onChange
  • Add proper HTML attributes

Exercise 5: Create a Todo Item Component

Build a todo item component that displays todo text, completion status, and has toggle/delete buttons.

Show Hints
  • Accept todo object with text and completed
  • Accept onToggle and onDelete functions
  • Conditionally style based on completed status
  • Add buttons for actions