はじめに
material-uiでテーブルをソートしたかったのですが、
例を見たときにcheckboxやページ切り替えが混ざりコードが多すぎたので整理しました
今回はmaterial-uiのBasic tableをもとにソートだけを実装しています
必要そうな処理
- ソート方法の保持処理
- ソート対象の保持処理
- ソート対象、方法の変更処理
- ソート実行処理
- 比較処理
- JSXの修正
- TableSortLabelの追加
- TableHeadのTableCellにsortDirection追加
- TableBodyのTableCellをソート順に表示
※見やすいようにTableHeadのTableCellも表示方法も修正しています
変更後のコード
import {useState} from "react";
import TableSortLabel from "@mui/material/TableSortLabel";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableCell from "@mui/material/TableCell";
import TableContainer from "@mui/material/TableContainer";
import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import Paper from "@mui/material/Paper";
function createData(name: string, calories: number, fat: number, carbs: number, protein: number) {
return { name, calories, fat, carbs, protein };
}
const rows = [
createData("Frozen yoghurt", 159, 6.0, 24, 4.0),
createData("Ice cream sandwich", 237, 9.0, 37, 4.3),
createData("Eclair", 262, 16.0, 24, 6.0),
createData("Cupcake", 305, 3.7, 67, 4.3),
createData("Gingerbread", 356, 16.0, 49, 3.9),
];
function createColumn(
id: string,
label: string,
align: "left" | "right" | "center" | "inherit" | "justify" | undefined
) {
return { id, label, align };
}
const columns = [
createColumn("name", "Dessert (100g serving)", "left"),
createColumn("calories", "Calories", "right"),
createColumn("fat", "Fat (g)", "right"),
createColumn("carbs", "Carbs (g)", "right"),
createColumn("protein", "Protein (g)", "right"),
];
export default function BasicTable() {
//ソート方法
const [order, setOrder] = useState<"desc" | "asc">("desc");
//ソート対象
const [orderBy, setOrderBy] = useState<string>("calories");
//ソート対象、方法の変更
const handleRequestSort = (event:any, property:any) => {
const isAsc = orderBy === property && order === "asc";
setOrder(isAsc ? "desc" : "asc");
setOrderBy(property);
};
const createSortHandler = (property:any) => (event:any) => {
handleRequestSort(event, property);
};
//ソート実行
function stableSort(array:any, comparator:any) {
const stabilizedThis = array.map((el:any, index:any) => [el, index]);
stabilizedThis.sort((a:any, b:any) => {
const order = comparator(a[0], b[0]);
if (order !== 0) {
return order;
}
return a[1] - b[1];
});
return stabilizedThis.map((el:any) => el[0]);
}
//比較処理
function descendingComparator(a:any, b:any, orderBy:any) {
if (b[orderBy] < a[orderBy]) {
return -1;
}
if (b[orderBy] > a[orderBy]) {
return 1;
}
return 0;
}
function getComparator(order:any, orderBy:any) {
return order === "desc"
? (a:any, b:any) => descendingComparator(a, b, orderBy)
: (a:any, b:any) => -descendingComparator(a, b, orderBy);
}
return (
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead>
<TableRow>
{columns.map((column) => (
<TableCell align={column.align} sortDirection={orderBy === column.id ? order : 'desc'}>
{column.label}
<TableSortLabel
active={orderBy === column.id}
direction={orderBy === column.id ? order : "asc"}
onClick={createSortHandler(column.id)}
></TableSortLabel>
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{stableSort(rows, getComparator(order, orderBy)).map((row:any) => (
<TableRow key={row.name} sx={{ "&:last-child td, &:last-child th": { border: 0 } }}>
<TableCell component="th" scope="row">
{row.name}
</TableCell>
<TableCell align="right">{row.calories}</TableCell>
<TableCell align="right">{row.fat}</TableCell>
<TableCell align="right">{row.carbs}</TableCell>
<TableCell align="right">{row.protein}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
}
注意として、ソートはcolumnsのidを元にソート対象を判断しているため、
rowsのキーとcolumnsのidは同じにします
終わり
Reactを勉強し始めたばっかりなので、間違いあれば教えてください