Bryan
Bryan

Reputation: 119

How do export a React component with related "child" components

I've seen some libraries supporting the ability to do things like

<Table>
    <Table.Row>This would replace importing a component called TableRow separately.</Table.Row>
</Table>

Not sure if it's bad practice or not but was wondering how you do it.

Upvotes: 5

Views: 3470

Answers (2)

Drew Reese
Drew Reese

Reputation: 202608

This is a design pattern known as Compound Components. You can make the sub-components static members of the outer class.

import React, { Component } from "react";
import PropTypes from "prop-types";

const Row = ({ children }) => <div>{children}</div>;

class Table extends Component {
  static Row = Row;

  render() {
    const { children, ...props } = this.props;
    return <div {...props}>{children}</div>;
  }
}

Table.propTypes = {
  children: PropTypes.arrayOf(
    PropTypes.shape({
      type: PropTypes.oneOf([Row])
    })
  )
};

export default Table;

Usage

import Table from "./Table";

...

<Table>
  <Table.Row>I'm a compound Row component!!</Table.Row>
  <Table.Row>I'm another compound Row component!!</Table.Row>
  <div>I'll throw a react proptype warning</div>
</Table>

Edit Compound component

How can we achieve this with function components?

It is nearly the same, but just add the compounded component as a property to the root component. If Table is a function component then to add the Row component to it, Table.Row = Row;. With class components falling out of favor in React this is the preferred pattern.

const Row = ({ children }) => <div>{children}</div>;

const Table = ({ children, ...props }) => (
  <div {...props}>{children}</div>
);

Table.Row = Row;

export default Table;

Upvotes: 1

saulmaldonado
saulmaldonado

Reputation: 756

You can do this by adding the child component to the parent component object and export the parent. Not exactly bad practice but it can help a lot with keeping components organized.

import React from 'react';

const Row = ({children}) => <span>{children}</span>;

const Table = ({children}) => <>{children}</>;

Table.Row = Row;

export default Table;

Upvotes: 5

Related Questions