The Ultimate Guide to Modern React Component Patterns in 2024
Introduction
React component patterns are evolving! This guide dives into some modern approaches to writing reusable and maintainable React components in 2024. We'll cover Compound Components, Render Props (briefly), and the increasingly popular Hooks-based patterns.
Compound Components
Compound components let you implicitly share state and logic between parent and child components. They create a more declarative API and reduce prop drilling.
import React, { createContext, useContext, useState } from 'react';
const ToggleContext = createContext();
const Toggle = ({ children }) => {
const [on, setOn] = useState(false);
const toggle = () => setOn(prev => !prev);
return (
<ToggleContext.Provider value={{ on, toggle }}>
{children}
</ToggleContext.Provider>
);
};
const ToggleOn = ({ children }) => {
const { on } = useContext(ToggleContext);
return on ? children : null;
};
const ToggleOff = ({ children }) => {
const { on } = useContext(ToggleContext);
return on ? null : children;
};
const ToggleButton = () => {
const { on, toggle } = useContext(ToggleContext);
return <button onClick={toggle}>{on ? 'On' : 'Off'}</button>;
};
Toggle.On = ToggleOn;
Toggle.Off = ToggleOff;
Toggle.Button = ToggleButton;
export default Toggle;
// Usage:
// <Toggle>
// <Toggle.On>The button is on!</Toggle.On>
// <Toggle.Off>The button is off!</Toggle.Off>
// <Toggle.Button />
// </Toggle>
Render Props (A Quick Look)
Render props, while still valid, are often superseded by Hooks. They involve a component that accepts a function as a prop and calls that function to render content.
import React from 'react';
const Mouse = ({ render }) => {
const [x, y] = React.useState({ x: 0, y: 0 });
const handleMouseMove = (event) => {
// more updates to come!
const { clientX, clientY } = event;
// Update the X and Y
React.useState({ x: clientX, y: clientY })
};
return (
<div style={{ height: '100vh' }} onMouseMove={handleMouseMove}>
{render(x, y)}
</div>
);
};
// Usage:
// <Mouse render={(x, y) => (
// <h1>The mouse position is ({x}, {y})</h1>
// )} />
Hooks-Based Patterns
Hooks provide a more direct and flexible way to share logic. Custom Hooks are key to extracting reusable behavior.
import { useState, useCallback } from 'react';
const useToggle = (initialValue = false) => {
const [on, setOn] = useState(initialValue);
const toggle = useCallback(() => {
setOn(prev => !prev);
}, []);
return { on, toggle };
};
export default useToggle;
// Usage:
// const { on, toggle } = useToggle();
// <button onClick={toggle}>{on ? 'On' : 'Off'}</button>
Conclusion
These modern React component patterns help you build cleaner, more maintainable, and more reusable UI components. Experiment with them to find what works best for your project's specific needs. As React continues to evolve, keeping up with these approaches will be crucial for efficient development.