The Subtle Art of Component Composition in ReactJS Link to heading

Building a React application often feels like assembling a complex puzzle. But what if I told you there’s a way to make this puzzle more intuitive, maintainable, and even enjoyable? Enter component composition. Buckle up, because today we’re diving deep into the subtle art of component composition in ReactJS.

What is Component Composition? Link to heading

Component composition is the practice of combining smaller components to build more complex ones. Think of it as Lego blocks; you start with basic blocks and snap them together to create intricate structures. This approach aligns perfectly with React’s philosophy of building UI components.

Why Should You Care? Link to heading

If you’re wondering why you should bother with component composition, let me hit you with some wisdom:

  1. Reusability: Smaller, well-defined components can be reused across different parts of your application.
  2. Maintainability: Smaller components are easier to understand, test, and debug.
  3. Scalability: As your application grows, well-composed components make it easier to manage complexity.

The Basics Link to heading

Let’s start with a simple example. Suppose we have a Button component:

import React from 'react';

const Button = ({ onClick, children }) => {
  return (
    <button onClick={onClick}>
      {children}
    </button>
  );
};

export default Button;

Now, let’s say we want to create a PrimaryButton and a SecondaryButton. Instead of duplicating code, we can compose these buttons from our Button component:

import React from 'react';
import Button from './Button';

const PrimaryButton = ({ onClick, children }) => {
  return (
    <Button onClick={onClick} style={{ background: 'blue', color: 'white' }}>
      {children}
    </Button>
  );
};

const SecondaryButton = ({ onClick, children }) => {
  return (
    <Button onClick={onClick} style={{ background: 'grey', color: 'black' }}>
      {children}
    </Button>
  );
};

export { PrimaryButton, SecondaryButton };

Advanced Techniques Link to heading

Higher-Order Components (HOCs) Link to heading

HOCs are functions that take a component and return a new component. They are a powerful way to reuse component logic. Here’s a basic example:

import React from 'react';

const withLogging = WrappedComponent => {
  return class extends React.Component {
    componentDidMount() {
      console.log('Component Mounted');
    }

    render() {
      return <WrappedComponent {...this.props} />;
    }
  };
};

export default withLogging;

You can use this HOC to wrap any component you want to log:

import React from 'react';
import withLogging from './withLogging';

class MyComponent extends React.Component {
  render() {
    return <div>My Component</div>;
  }
}

export default withLogging(MyComponent);

Render Props Link to heading

Render props are another pattern for sharing code between components using a prop whose value is a function. Here’s an example:

import React from 'react';

class MouseTracker extends React.Component {
  state = { x: 0, y: 0 };

  handleMouseMove = event => {
    this.setState({
      x: event.clientX,
      y: event.clientY
    });
  };

  render() {
    return (
      <div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}>
        {this.props.render(this.state)}
      </div>
    );
  }
}

const App = () => (
  <MouseTracker render={({ x, y }) => (
    <h1>The mouse position is ({x}, {y})</h1>
  )} />
);

export default App;

Conclusion Link to heading

Component composition is a powerful technique that can make your React applications more modular, maintainable, and scalable. By leveraging basic composition, higher-order components, and render props, you can create a clean and efficient codebase. So next time you find yourself in the labyrinth of React components, remember: the subtle art of component composition is your guiding light.

React Logo