Capítulo 26 de 54
FlexRender (component, capital F) is the correct default for rendering a header/cell/footer; the lower-level flexRender() function exists for when you already have a resolved renderer value and its context and don't need FlexRender's table-specific decisions (aggregated-cell fallback, placeholder suppression).
FlexRender takes exactly one table object — cell, header, or footer — and resolves the right column-def property and context itself: <table.FlexRender header={header} />, <table.FlexRender cell={cell} />. It's attached to the table instance, or importable directly as <FlexRender footer={header} /> for footer groups (footer groups are Header objects too, passed via the footer prop).FlexRender also decides which renderer to use: aggregatedCell when the cell is aggregated, falling back to cell if no aggregatedCell is defined, and rendering nothing for grouping placeholder cells. flexRender() alone does not make this decision — it just renders whatever definition/context pair you hand it.flexRender(defOrNode, context) is the lower-level primitive: it distinguishes actual React components (including class components, memo, forwardRef) from already-created nodes and renders accordingly. Reach for it when you already have the specific definition and context resolved and don't need FlexRender's cell-vs-aggregatedCell or placeholder logic.header: ({ column }) => ..., cell: ({ getValue }) => ...) — don't call them as plain functions yourself.cell.getValue()/cell.renderValue() are for when you only need the raw accessor value; use FlexRender (not those) whenever the column def might contain a static node or a component renderer, since FlexRender handles both and passes full context.header.isPlaceholder is not automatically suppressed by FlexRender for headers — check it yourself in your render loop unless the placeholder intentionally carries content (e.g. a row-spanning header, see the Headers Guide's Header Row Spanning pattern).// standard header/cell render loop — always through FlexRender
{table.getHeaderGroups().map((hg) => (
<tr key={hg.id}>
{hg.headers.map((header) => (
<th key={header.id}>{header.isPlaceholder ? null : <table.FlexRender header={header} />}</th>
))}
</tr>
))}
{table.getRowModel().rows.map((row) => (
<tr key={row.id}>
{row.getVisibleCells().map((cell) => <td key={cell.id}><table.FlexRender cell={cell} /></td>)}
</tr>
))}
// low-level flexRender, when you already have the def+context resolved
flexRender(cell.column.columnDef.cell, cell.getContext())
<thead>/<tbody> render loop, and the lower-level call FlexRender wraps internally.table.FlexRender/<FlexRender ... />, not flexRender() directly, unless you specifically need the lower-level primitive.FlexRender already handles aggregated-vs-regular and grouping-placeholder logic — don't re-implement that branching yourself.header.isPlaceholder still needs an explicit check in your render loop; FlexRender doesn't suppress placeholders for you.FlexRender renders.FlexRender.