React Components 🧩

1. Introduction 👋

Components are the fundamental building blocks of every React application. They let you split complex user interfaces into small, independent, and reusable pieces. This tutorial explores what components are, how to create and organize them, and the design principles that separate maintainable React code from tangled, hard-to-follow code.

Information

This tutorial builds on concepts from the JSX tutorial. If you haven't reviewed JSX syntax yet, it's recommended to do so first.

2. What are Components? 🤔

A component is a self-contained, reusable piece of UI. Technically, it's just a JavaScript function that accepts inputs (called props) and returns JSX describing what should appear on screen.

Code Snippet

function Welcome() {
  return <h1>Hello, welcome to React! 👋</h1>;
}
>>"Components let you split the UI into independent, reusable pieces, and think about each piece in isolation." — React Documentation

3. Why Components? 💡

  • Reusability: Write a piece of UI once and reuse it across your application.
  • Maintainability: Isolated components are easier to debug, test, and update.
  • Composability: Small components combine to build complex interfaces.
  • Separation of Concerns: Each component can encapsulate its own logic, markup, and (optionally) styles.
  • Collaboration: Teams can work on different components independently without conflicts.

4. Types of Components đŸ—‚ī¸

Modern React development revolves almost entirely around function components. Legacy class components still exist in older codebases but are no longer recommended for new code.

TypeStatusDescription
Function ComponentsRecommendedPlain JavaScript functions returning JSX, using Hooks for state and lifecycle.
Class ComponentsLegacyES6 classes extending React.Component, using lifecycle methods.

Best Practice

Always use function components with Hooks for new code. Class components are only relevant when maintaining older codebases.

5. Function Components âš™ī¸

A function component is simply a JavaScript function that returns JSX. Its name must start with a capital letter so React can distinguish it from a regular HTML tag.

Code Snippet

function ProfileCard({ name, role }) {
  return (
    <div className="profile-card">
      <h2>{name}</h2>
      <p>{role}</p>
    </div>
  );
}
  • Accepts a single props object as its argument.
  • Must return JSX, null, or an array of elements.
  • Can use Hooks like useState and useEffect internally.

6. Creating Your First Component đŸŽŦ

Greeting.jsx

function Greeting({ name }) {
  return <h1>Hello, {name}! 👋</h1>;
}

export default Greeting;

App.jsx

import Greeting from './Greeting';

function App() {
  return (
    <div>
      <Greeting name="Alice" />
    </div>
  );
}

export default App;

Tip

Start with the smallest possible component and grow complexity gradually — it's much easier to combine small components than to break apart a large one later.

7. Rendering Components đŸ–ŧī¸

To render a component, use it like a custom JSX tag. React calls the function, evaluates the returned JSX, and inserts the result into the DOM.

Code Snippet

function App() {
  return (
    <div>
      <Greeting name="Bob" />
      <Greeting name="Carol" />
      <Greeting name="Dave" />
    </div>
  );
}

Note

Each <Greeting /> instance is completely independent — they don't share state or interfere with one another.

8. Naming Components đŸˇī¸

  • Component names must start with an uppercase letter (e.g., UserCard, not userCard).
  • React treats lowercase tags as built-in HTML elements (e.g., div, span).
  • Use PascalCase consistently for component names and their file names.
  • Choose descriptive, specific names (e.g., UserAvatar over Avatar1).

Important

A component named button (lowercase) will be interpreted by React as an HTML button element, not your custom component — this is a common source of bugs.

9. Importing Components đŸ“Ĩ

Code Snippet

// Named export
import { Header } from './Header';

// Default export
import Footer from './Footer';

// Importing multiple components
import { Button, Input, Card } from './ui-components';

Tip

Group related components into a shared folder or barrel file (e.g., ui-components/index.js) to simplify imports across a large codebase.

10. Exporting Components 📤

Code Snippet

function Header() {
  return <header>My App</header>;
}

export default Header;

Use default exports when a file exports a single, primary component.

Code Snippet

export function Button({ label }) {
  return <button>{label}</button>;
}

export function IconButton({ icon }) {
  return <button>{icon}</button>;
}

Use named exports when a file exports multiple related components.

11. Nested Components đŸĒ†

Components can render other components inside their JSX, forming a tree of nested UI pieces.

Code Snippet

function Avatar({ src }) {
  return <img className="avatar" src={src} alt="User avatar" />;
}

function UserCard({ user }) {
  return (
    <div className="user-card">
      <Avatar src={user.avatarUrl} />
      <h3>{user.name}</h3>
    </div>
  );
}

Caution

Never define a component inside another component's function body — it gets recreated on every render, causing unnecessary re-mounts and lost state.

12. Reusable Components â™ģī¸

Well-designed components accept props to customize their behavior and appearance, allowing the same component to be reused in many different contexts.

Code Snippet

function Button({ label, variant = "primary", onClick }) {
  return (
    <button className={`btn btn-${variant}`} onClick={onClick}>
      {label}
    </button>
  );
}

// Reused with different props
<Button label="Save" variant="primary" onClick={handleSave} />
<Button label="Cancel" variant="secondary" onClick={handleCancel} />
<Button label="Delete" variant="danger" onClick={handleDelete} />

13. Component Composition đŸ—ī¸

Composition is the practice of building complex UIs by combining smaller components, often passing components as children rather than hardcoding structure.

Code Snippet

function Card({ children }) {
  return <div className="card">{children}</div>;
}

function App() {
  return (
    <Card>
      <h2>Card Title</h2>
      <p>Card content goes here.</p>
    </Card>
  );
}

Best Practice

React favors composition over inheritance — instead of extending a base component's behavior, wrap and combine components using props and children.

14. Splitting UI into Components đŸ”Ē

Breaking a large interface into components involves identifying logical, reusable boundaries in the UI.

App
Header
MainContent
Footer
Logo
NavMenu
Sidebar
ArticleList
ArticleCard
ArticleCard

Tip

A helpful rule of thumb: if a piece of UI is reused, has its own distinct logic, or is complex enough to reason about separately, it deserves its own component.

15. Root Component đŸŒŗ

The root component (commonly App) sits at the top of the component tree and is the entry point rendered into the DOM.

main.jsx

import { createRoot } from 'react-dom/client';
import App from './App';

createRoot(document.getElementById('root')).render(<App />);

16. Parent Components đŸ‘Ē

A parent component renders other components inside it and typically manages shared state or data passed down to its children via props.

Code Snippet

function TodoApp() {
  const todos = ["Learn React", "Build a project"];

  return (
    <div>
      <h1>My Todos</h1>
      <TodoList todos={todos} />
    </div>
  );
}

17. Child Components đŸ‘ļ

A child component receives data from its parent through props and typically has no knowledge of where that data originates.

Code Snippet

function TodoList({ todos }) {
  return (
    <ul>
      {todos.map((todo) => (
        <li key={todo}>{todo}</li>
      ))}
    </ul>
  );
}

Note

Data flows in one direction — from parent to child — which makes React applications predictable and easier to debug.

18. Component Hierarchy 🌲

React applications form a tree structure, where each component may have zero or more child components, all rooted at the top-level App component.

App
Navbar
Dashboard
Logo
SearchBar
StatsPanel
Chart

Information

Understanding the component hierarchy is essential for reasoning about state placement and data flow in larger applications.

19. Organizing Components đŸ—„ī¸

As applications grow, a clear folder structure keeps components discoverable and maintainable.

src/
components/
features/
Button/
Card/
Dashboard/
Profile/
Button.jsx
Button.module.css
Card.jsx

Tip

For larger apps, organizing by feature (e.g., features/Dashboard) often scales better than organizing purely by component type.

20. Single Responsibility Principle đŸŽ¯

Each component should ideally do one thing well. A component handling data fetching, complex business logic, and detailed presentation all at once quickly becomes difficult to test and reuse.

Before: One Component Doing Too Much

function UserDashboard() {
  // fetching logic, formatting logic, and rendering
  // all mixed together in one large component
  // ...
}

After: Split by Responsibility

function UserDashboard() {
  const { user, loading } = useUser();
  if (loading) return <Spinner />;
  return <UserProfile user={user} />;
}

21. Presentational Components 🎨

Presentational components focus purely on how things look. They receive data via props and render UI, without containing business logic or data-fetching code.

Code Snippet

function PriceTag({ amount, currency }) {
  return (
    <span className="price-tag">
      {currency}{amount.toFixed(2)}
    </span>
  );
}

22. Container Components đŸ“Ļ

Container components handle how things work — managing state, fetching data, and passing it down to presentational components.

Code Snippet

function ProductPriceContainer({ productId }) {
  const [price, setPrice] = useState(null);

  useEffect(() => {
    fetchPrice(productId).then(setPrice);
  }, [productId]);

  if (price === null) return <Spinner />;
  return <PriceTag amount={price} currency="$" />;
}

Note

The container/presentational pattern has become less rigid with Hooks, but the underlying principle — separating logic from display — remains valuable.

23. Generic Components đŸ§Ŧ

Generic components are highly reusable, unopinionated building blocks (like buttons, modals, or inputs) that adapt to many contexts through flexible props.

Code Snippet

function Modal({ isOpen, onClose, children }) {
  if (!isOpen) return null;

  return (
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal-content" onClick={(e) => e.stopPropagation()}>
        {children}
      </div>
    </div>
  );
}

Best Practice

Design generic components with children and flexible props so they remain reusable across many unrelated features.

24. Component Communication Overview 📡

Components communicate with each other in a few well-defined ways within React's unidirectional data flow model.

PatternDirectionMechanism
Parent → ChildDownwardProps
Child → ParentUpwardCallback functions passed as props
Sibling ↔ SiblingIndirectLifted state in a common parent
Deeply NestedAny levelContext API

Reference

This is a high-level overview — component communication patterns like props, Context, and lifting state are covered in depth in a dedicated tutorial.

25. Component Lifecycle Overview âŗ

Every component goes through a lifecycle: it mounts (is created and inserted), updates (re-renders in response to state or prop changes), and eventually unmounts (is removed).

Information

In function components, lifecycle behavior is managed through the useEffect Hook rather than explicit lifecycle methods — this is covered in detail in the Hooks tutorial.

26. Component Best Practices 🌟

  1. Keep components small and focused on a single responsibility.
  2. Name components with PascalCase and descriptive, specific names.
  3. Never define a component inside another component's function body.
  4. Favor composition using children over rigid, hardcoded structures.
  5. Extract reusable UI patterns into generic, prop-driven components.
  6. Colocate a component's styles and tests with its file when practical.

27. Common Component Mistakes đŸšĢ

  • Defining components with a lowercase name, causing React to treat them as HTML tags.
  • Nesting component definitions inside other components, causing state loss on every render.
  • Creating overly large "god" components that handle too many responsibilities at once.
  • Duplicating logic across components instead of extracting a shared, reusable component.
  • Forgetting to pass a key when rendering a list of components.

Danger

Defining a component inside another component's body causes React to treat it as a brand-new component type on every render, destroying and recreating its internal state repeatedly.

28. Frequently Asked Questions ❓

Question

Should I always use function components?

Answer

Yes, for all new code. Function components with Hooks are the modern standard; class components are only relevant for legacy codebases.

Question

How small should a component be?

Answer

There's no strict rule, but a good guideline is: if a component is doing more than one clear job, or a piece of its JSX is reused elsewhere, it's likely time to split it.

Question

Can a component return multiple elements?

Answer

A component must return a single root node — but that node can be a Fragment wrapping multiple sibling elements.

29. Summary 📝

Components are the core unit of reuse and organization in React. By breaking interfaces into small, focused pieces — following principles like single responsibility and composition — you create applications that are easier to build, test, and maintain over time.

Summary

With a solid understanding of components, the natural next steps are exploring Props and State, which give components the data and interactivity that make React applications come alive.