I have a table built using react-table
with useSortBy
hook. Everything works just fine until I change what Cell
returns from columns
. The thing is, for certain columns I have to modify how data is displayed on the table (without altering the data itself). For example, I have a column on the table that doesnt just display the raw data, it has to combine other values to that data, then display the result. Take a look at the sample code below.
import { useContext, useMemo } from "react";
import "../assets/css/result.css";
import { useTable, useSortBy } from "react-table";
import globalContext from "../globalContext/globalData";
const Result = () => {
const { searchResults } = useContext(globalContext);
const columns = useMemo(() => headers, []); // headers defined below
const data = useMemo(() => searchResults, [searchResults]);
return (
<section id="result">
<div className="title">
<p>Here is my fancy table</p>
</div>
<div className="table">
<Table columns={columns} data={data} />
</div>
</section>
);
};
export default Result;
function Table({ columns, data }) {
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable(
{
columns,
data,
},
useSortBy
);
return (
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
// Add the sorting props to control sorting. For this example
// we can add them into the header props
<th {...column.getHeaderProps(column.getSortByToggleProps())}>
{column.render("Header")}
{/* Add a sort direction indicator */}
<span>{column.isSorted ? (column.isSortedDesc ? "⇩" : "⇧") : ""}</span>
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row, i) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return (
<td {...cell.getCellProps({ className: cell.column.className })}>
{cell.render("Cell")}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
);
}
const headers = [
{
Header: "Normal Column",
accessor: "normal_column",
// Cell: props => props.value, // default behaviour
},
{
Header: "Order count",
accessor: "order_count",
Cell: props => `${Number(props.value).toLocaleString("en")} 個`, // 5510 => 5,510 個
// here sorting works fine as the cell display value hasnt changed much
},
{
Header: "Other Column",
accessor: "column_name",
// BUG: sorting does not work properly as it still uses props.value
Cell: props => {
// Here I have to display the value in a different way, combining somethings from the original row data
// displays as expected, but the sorting is still done based on the default props.value under the hood
const { var1, var2, var3 } = props.row.original;
return `${var1}-${var2}-${var3}`; // this should be what sorting is based on, not props.value
},
},
];
Let's say I change a cell display value from the original 5510
to 5,510 個
(format the number with commas as thousands separators and put space+個 at the end). Sorting works fine with it as sorting results of 5,510 個 and 5510 values do not differ so much.
Here is when it gets tricky: I need a new column that combines two or three row values and outputs a certain display value as shown inside the headers
object of the Sample Code. Now the sorting does not work as expected (based on the return value of the Cell).
I tried overriding the props.value
from Cell
function inside my headers
object. But it is immutable. So this did not work. How should I go about figuring this out? What am I missing?
What about instead of trying to set the displayed value inside of your Cell function you do it before passing the props to your Table component, this is the only way I can think of without the changing the original sorting function from the react table hook since it's looking to sort directly with the props.value you provide at the beginning.
Maybe something like this:
const formatMyData = (searchResults)=>{
return searchResults.map((result)=>({...result, myFormattedColumn: `${result.data1}-${result.data2}-${result.data3}`}))
}
const data = useMemo(() => searchResults, [formatMyData(searchResults)]);