Search code examples
javascriptreactjstypescriptprimereact

Column headers not rendering as expected after refactoring <Column />


This renders the header properly in that I can see a table with a "Product ID" header for the column:

// DataTable.tsx
// React Imports
import React, { useState } from 'react';

// PrimeReact Imports
import { DataTable as DT } from 'primereact/datatable';
import { Column } from 'primereact/column';

// Custom Imports
import DataTableHeader from './DataTableHeader';

const DataTable = (): JSX.Element => {
  const [rowData, setRowData] = useState([]);
  return (
    <DT
      value={rowData}
      emptyMessage='Run the utility first.'
      size='small'
    >
      <Column field='product_id' header='Product ID' />
    </DT>
  );
};

export default DataTable;

I'm trying to refactor it so I can reuse <DataTable /> and <Column /> given they are almost identical throughout the app:

// DataTable.tsx
// React Imports
import React, { useState } from 'react';

// PrimeReact Imports
import { DataTable as DT } from 'primereact/datatable';

// Custom Imports
import DataTableHeader from './DataTableHeader';
import ColumnProductID from './ColumnProductID';

const DataTable = (): JSX.Element => {
  const [rowData, setRowData] = useState([]);
  return (
    <DT
      value={rowData}
      emptyMessage='Run the utility first.'
      size='small'
    >
      <ColumnProductID />
    </DT>
  );
};

export default DataTable;
// ColumnProductID.tsx

import React from 'react';

// PrimeReact Imports
import { Column } from 'primereact/column';

const ColumnProductID = (): JSX.Element => {
  return <Column field='product_id' header='Product ID' />
};

export default ColumnProductID;

In this case, the <Column /> header is not rendered... inspecting the page elements for an occurrence of "Product ID" does not yield anything so it seems the <ColumnProductID /> is not being rendered.

Suggestions for what I am doing wrong here?


I did manage to get this to work, by doing:

// DataTable.tsx
// React Imports
import React, { useState } from 'react';

// PrimeReact Imports
import { DataTable as DT } from 'primereact/datatable';

// Custom Imports
import DataTableHeader from './DataTableHeader';
import ColumnProductID from './ColumnProductID';

const DataTable = (): JSX.Element => {
  const [rowData, setRowData] = useState([]);
  return (
    <DT
      value={rowData}
      emptyMessage='Run the utility first.'
      size='small'
    >
      <ColumnProductID field='product_id' header='Product ID' />
    </DT>
  );
};

export default DataTable;
// ColumnProductID.tsx

import React from 'react';

// PrimeReact Imports
import { Column } from 'primereact/column';

interface ColumnProductIDProps {
  field: string;
  header: string;
}

const ColumnProductID = (props: ColumnProductIDProps): JSX.Element => {
  return <Column field={field} header={header} />
};

export default ColumnProductID;

But this is undesirable... in fact it is the very thing I'm trying to avoid and it is pointless to refactor <Column /> from primereact into a <ColumnProductID /> component. This effectively makes <ColumnProductID /> === <Column /> with an additional layer and unnecessary complexity.

The redundancy I'm trying to get around is this:

  • A field named status, for example, can relate to all kinds of data: Customers, Companies, Products, Leads, etc. etc. etc.
  • Whatever <DataTable /> this field status appears in, it should have the exact same props.
  • If there are <DataTable /> for Customers, Companies, Products, Leads, and this <Column field='status' /> is in all of them, and you want to change something about it, then you have to go into each <DataTable /> and update it.
  • But if you can make a <ColumnStatus /> component and pass that into the <DataTable /> then you only need to update it one place: in the <ColumnStatus /> component.

Solution

  • This is not currently possible with PrimeReact. Column is not a a "component" that renders itself so it cannot be wrapped or extended. The Datatable looks specifically for <Column> as children and not anything else.

    See: https://github.com/primefaces/primereact/issues/2268

    See: https://github.com/primefaces/primereact/issues/2052#issuecomment-1173678665