Stop Coding before thinking Feat- Render Props and Compound Patterns Frontend System Design, Pt — 1

Stop Coding before thinking Feat- Render Props and Compound Patterns Frontend System Design, Pt — 1

Write better code with these patterns

React Design patterns are a great way to way structure and share functionality in your applications.

Render Props patterns

The render props pattern is a technique that allows components to share functionality through props that are functions. By passing a function as a prop to a component, you enable that component to render content provided by the function. This pattern unlocks a world of possibilities for creating reusable and dynamic components.

Here’s an Example

// Counter component using Render Props
const Counter = ({ render }) => {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  const decrement = () => {
    setCount(count - 1);
  };

  // Render the counter and control functions
  return render(count, increment, decrement);
};

// Parent component using the Counter component
const App = () => {
  return (
    <div>
      <h1>Render Props Counter</h1>
      <Counter
        render={(count, increment, decrement) => (
          <div>
            <p>Count: {count}</p>
            <button onClick={increment}>Increment</button>
            <button onClick={decrement}>Decrement</button>
          </div>
        )}
      />
    </div>
  );
};
  1. The Counter component manages the count state using the useState hook which defines increment and decrement functions to update the count.

  2. The Counter component accepts a render prop, which is a function that takes count, increment, and decrement as arguments. We then invoke the render function and pass in the count, increment, and decrement values.

  3. The parent App component renders the Counter component and provides a rendering function as the render prop.

  4. The rendering function within the parent component uses the provided count and functions to display the current count and buttons for incrementing and decrementing.

This simple example demonstrates how the Render Props pattern allows you to encapsulate functionality within a component and delegate the rendering and behavior control to the parent component.

But Manish how it is useful??

Let’s consider a scenario where you need to create two separate components that display a count with increment and decrement buttons. Instead of duplicating the count logic and rendering code in both components, you can use the Render Props pattern to encapsulate the count logic in a single Counter component and share it between the two components.

const Counter = ({ render }) => {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  const decrement = () => {
    setCount(count - 1);
  };

  // Render the counter and control functions
  return render(count, increment, decrement);
};

// Component 1
const CounterDisplay1 = () => {
  return (
    <Counter
      render={(count, increment, decrement) => (
        <div>
          <h2>Counter 1</h2>
          <p>Count: {count}</p>
          <button onClick={increment}>Increment</button>
          <button onClick={decrement}>Decrement</button>
        </div>
      )}
    />
  );
};

// Component 2
const CounterDisplay2 = () => {
  return (
    <Counter
      render={(count, increment, decrement) => (
        <div>
          <h2>Counter 2</h2>
          <p>Count: {count}</p>
          <button onClick={increment}>Increment</button>
          <button onClick={decrement}>Decrement</button>
        </div>
      )}
    />
  );
};

// Parent component
const App = () => {
  return (
    <div>
      <h1>Code Reusability with Render Props</h1>
      <CounterDisplay1 />
      <CounterDisplay2 />
    </div>
  );
};

Here you can see that both components can have an entirely different UI and other things but since the counter component is handling the logic part we can make use of the render prop pattern to share logic and reusability among different components.


React compound patterns

The React Compound Pattern is a design approach that involves composing components together to create a unified interface with shared behavior and state while allowing each individual component to remain relatively simple and focused on a specific aspect of the UI.

When to use Compound patterns ??

  1. Complex UI Elements — Compound components are particularly valuable for creating complex UI elements that require coordination between multiple components. Examples include tabs, accordions, modals, sliders, and more.

  2. Shared State and Behavior — When you need to share state or behavior across a set of components, the Compound Pattern provides a structured way to manage this shared functionality.

Simple examples are the select and options HTML elements. Both select and options HTML elements work in groups to provide the given functionality

// SelectMenu component
const SelectMenu = ({ options, onSelect }) => {
  const [selectedOption, setSelectedOption] = useState(options[0]);

  const handleSelectChange = (event) => {
    const selectedValue = event.target.value;
    setSelectedOption(selectedValue);
    onSelect(selectedValue);
  };

  return (
    <select className="select-menu" value={selectedOption} onChange={handleSelectChange}>
      {options.map((option, index) => (
        <option key={index} value={option}>
          {option}
        </option>
      ))}
    </select>
  );
};

// App component
const App = () => {
  const themeOptions = ['Default', 'Dark', 'Light'];

  const handleThemeChange = (selectedTheme) => {
    // Logic to apply the selected theme
    console.log(`Selected theme: ${selectedTheme}`);
  };

  return (
    <div>
      <h1>Select Option Menu Example</h1>
      <SelectMenu options={themeOptions} onSelect={handleThemeChange} />
      {/* Rest of the app content */}
    </div>
  );
};

This is an example of a theme switcher that is based on a compound pattern

  1. The select menu component encapsulates the logic for rendering the select menu and handling selection changes.

  2. The App component renders the Select Menu component and provides the available options as well as a callback function ( handle change ) to handle the selected option.

Conclusion

It’s not a hard and fast rule to always use these patterns feel free to write code as you like but using these will surely give you an edge on code quality, reusability, customization, and many more things.

Up Next

HOC pattern, Hooks pattern, and many more

Did you find this article valuable?

Support Manish Bisht by becoming a sponsor. Any amount is appreciated!