From Props to Powerhouses: Using Context and Composition in React

AristilAristil
5 min read

Ever found yourself wondering how to manage data in a React app without passing it through multiple layers of components? Or maybe you're thinking about creating flexible and reusable components that can be easily combined? That's where two key React patterns come in: Context and Composition. These tools help simplify data flow and make your code easier to maintain and scale.

In this guide, I'll explain Context and Composition, why they were developed, and how they help solve common issues like prop drilling. By the end, you’ll have a clear idea of when and how to use each concept in your own projects.

Why Were Context and Composition Created?

As React applications grew larger and more complex, developers faced two main issues: passing data deeply through components (causing prop drilling) and making UI components flexible and reusable.

Prop drilling happens when you need to pass data through several layers just to reach the component that actually needs it. This makes your code harder to follow and maintain. On the other hand, Composition was introduced to address the need for reusable components that could work together without rigid, predefined structures. It allows developers to create more modular, adaptable user interfaces.

Context and Composition were developed to solve these problems, helping you manage shared data more effectively while keeping your UI flexible.

What is Context?

Picture this: you're hosting a movie night and want all your guests, who are spread across different rooms, to follow the same theme (dim lighting, for instance). Instead of telling each person individually, you simply post a note with the instructions where everyone can see it.

In React, Context works the same way. It lets you share data, like a theme, across multiple components without having to pass it manually down through each level. This way, you avoid prop drilling—your components can just look up the shared data whenever they need it.

Example of Context

import React, { createContext, useContext } from 'react';

// Create a Context with default value "light"
const ThemeContext = createContext('light');

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return <button style={{ background: theme === 'dark' ? '#333' : '#fff' }}>Click me</button>;
}

Here, the theme is provided at a higher level with ThemeContext.Provider, and the ThemedButton can access it using the useContext hook, skipping the need to pass it manually through every component. This clears up prop drilling.

When to Use Context

Use Context when your data—like themes, user preferences, or authentication status—needs to be available across multiple components. It’s ideal for managing global data without cluttering your component tree with props. But remember, for localized data, props or Composition might be a better choice.

What is Composition?

Think of Composition like making a sandwich. You have ingredients (bread, lettuce, tomatoes), each one a separate component, and together they form the sandwich. You can swap out different ingredients (like switching turkey for ham) while still keeping the same basic structure.

In React, Composition works the same way. Instead of building large, hard-to-maintain components, you create smaller ones that can be combined flexibly, allowing for more modular and reusable UIs.

Example of Composition

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

function App() {
  return (
    <Card>
      <h1>Title</h1>
      <p>This is card content</p>
    </Card>
  );
}

In this example, the Card component acts like the bread—it can hold any content inside it, but the structure remains reusable. The flexibility here demonstrates the power of Composition in React.

When to Use Composition

Use Composition when you want to create reusable, flexible components that can be combined to build larger UIs. This makes your components more modular and adaptable, helping you avoid rewriting code. Composition is especially useful for building layouts and reusable UI elements like cards and lists.

When to Use Context vs. Composition

These two patterns serve different purposes but can often work together in React applications.

  • Use Context when you need to share global data (such as themes, settings, or authentication) across many components. This helps you avoid prop drilling, keeping your code cleaner and more maintainable.

  • Use Composition when you want to build reusable, flexible components that can be combined like building blocks. This lets you keep your code modular and adaptable to different contexts.

Combining Context and Composition

Let’s say you're building reusable card components for your app. You can use Composition to structure the card’s content. If all the cards need to follow a common theme (like dark mode), you’d use Context to provide that shared theme without having to pass it down manually through each card.

Putting It All Together

Here’s an example where we use both Context and Composition:

const ThemeContext = createContext('light');

function ThemedInput({ placeholder }) {
  const theme = useContext(ThemeContext);
  return <input style={{ background: theme === 'dark' ? '#333' : '#fff' }} placeholder={placeholder} />;
}
function Form() {
  return (
    <form>
      <ThemedInput placeholder="Enter your name" />
      <ThemedInput placeholder="Enter your email" />
    </form>
  );
}
function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Form />
    </ThemeContext.Provider>
  );
}

In this example, Context manages the theme globally, while Composition allows us to reuse the ThemedInput component multiple times. This setup avoids prop drilling and keeps the code clean and reusable.

To Sum Up:

  • Context is for sharing global data (like themes or user settings) across multiple components without prop drilling.

  • Composition is for building reusable, flexible components that can be combined like building blocks.

Together, these patterns make your React code scalable, maintainable, and easier to work with.

References

0
Subscribe to my newsletter

Read articles from Aristil directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Aristil
Aristil