跳到主要内容

如何在 React Table 中实现 Sort

前言

在本节中,我想向你展示如何使用 React Table Library 及其 useSort 插件来实现排序功能。在前面的例子中,你已经安装了 React Table Library 来创建一个 Table 组件。现在,我们将允许用户通过单击列标题对Table中的列进行排序。

实现

首先,导入 useSort Hook:

import { useSort } from '@table-library/react-table-library/sort';

其次,使用Table的数据对其进行初始化,并将其作为 prop 传递给 Table 组件:

const App = () => {
const data = { nodes };

const sort = useSort(data);

return (
<Table data={data} sort={sort}>
...
</Table>
);
};

之后,将你的标题列转换为可排序的:

import {
useSort,
HeaderCellSort ,
} from '@table-library/react-table-library/sort';

const App = () => {
...

return (
<Table data={data} sort={sort}>
{(tableList) => (
<>
<Header>
<HeaderRow>
<HeaderCellSort sortKey="TASK">
Task
</HeaderCellSort>
<HeaderCellSort sortKey="DEADLINE">
Deadline
</HeaderCellSort>
<HeaderCellSort sortKey="TYPE">
Type
</HeaderCellSort>
<HeaderCellSort sortKey="COMPLETE">
Complete
</HeaderCellSort>
</HeaderRow>
</Header>

<Body>
...
</Body>
</>
)}
</Table>
);
};

然后为每个排序键创建各自的排序函数:

const App = () => {
const data = { nodes };

const sort = useSort(data, null, {
sortFns: {
TASK: (array) =>
array.sort((a, b) => a.name.localeCompare(b.name)),
DEADLINE: (array) =>
array.sort((a, b) => a.deadline - b.deadline),
TYPE: (array) =>
array.sort((a, b) => a.type.localeCompare(b.type)),
COMPLETE: (array) =>
array.sort((a, b) => a.isComplete - b.isComplete),
},
});

return (
<Table data={data} sort={sort}>
...
</Table>
);
};

只需几行,你就有一个可排序的Table。我们可以按字符串排序(按字母顺序)、按日期排序、按布尔值排序和按枚举排序。由于自己传递了 sortBy 函数,因此如何对列进行排序取决于sortBy 函数。

可能缺少的获取当前排序的onChange事件。让我们看看它是如何与 useSort 结合使用的:

const App = () => {
const data = { nodes };

const sort = useSort(data,
{
onChange: onSortChange,
}, {
sortFns: ...,
}
);

function onSortChange(action, state) {
console.log(action, state);
}

...
};

onChange 回调函数使你可以访问触发排序更改的操作以及Table的实际排序状态。通过访问此信息,你可以基于它触发更多的Table或非Table事件(例如,服务器端排序等副作用)。

最后,值得注意的是,你传递给Table的排序对象包含排序状态——这使你能够随时访问它——以及以编程方式对列进行排序的所有函数。当在这个 React Table中使用自定义排序组件时,我们稍后会详细看到这一点。 无论如何,表中的列排序通常会带来更多要求。让我们来看看其中的两个:

例如,有时用户想要具有初始排序状态。这也可以通过 useSort 来实现,方法是传入一个默认的排序状态:

const App = () => {
...

const sort = useSort(data,
{
state: {
sortKey: 'TASK',
reverse: false,
},
onChange: onSortChange,
}, {
sortFns: ...,
}
);

...
};

另一个案例是将排序图标与来自第三方库(例如 Material UI)的自定义排序图标交换:

import UnfoldMoreOutlinedIcon from '@mui/icons-material/UnfoldMoreOutlined';
import KeyboardArrowUpOutlinedIcon from '@mui/icons-material/KeyboardArrowUpOutlined';
import KeyboardArrowDownOutlinedIcon from '@mui/icons-material/KeyboardArrowDownOutlined';

const App = () => {
...

const sort = useSort(
data,
{
onChange: onSortChange,
},
{
sortIcon: {
margin: '0px',
iconDefault: <UnfoldMoreOutlinedIcon />,
iconUp: <KeyboardArrowUpOutlinedIcon />,
iconDown: (
<KeyboardArrowDownOutlinedIcon />
),
},
sortFns: ...
}
);

...
};

排序功能还有更多选项。只需前往 React Table 文档以了解有关它们的更多信息。

最后,使用 React Table Library 可以完全用自定义组件交换排序组件。对于我们的表格排序插件,我们可能希望将排序标题组件与我们自己的来自第三方库的 HTML 按钮进行交换。下面,你将看到一个如何在 React 表库中使用 Material UI 组件的示例。

首先,从你的第三方库中导入自定义组件(和自定义图标):

import MaterialButton from '@mui/material/Button';
import UnfoldMoreOutlinedIcon from '@mui/icons-material/UnfoldMoreOutlined';
import KeyboardArrowUpOutlinedIcon from '@mui/icons-material/KeyboardArrowUpOutlined';
import KeyboardArrowDownOutlinedIcon from '@mui/icons-material/KeyboardArrowDownOutlined';

其次Table Header 使用第三方按钮:

const App = () => {
...

const getIcon = (sortKey) => {
if (sort.state.sortKey === sortKey && sort.state.reverse) {
return <KeyboardArrowDownOutlinedIcon />;
}

if (sort.state.sortKey === sortKey && !sort.state.reverse) {
return <KeyboardArrowUpOutlinedIcon />;
}

return <UnfoldMoreOutlinedIcon />;
};

return (
<Table data={data} sort={sort}>
{(tableList) => (
<>
<Header>
<HeaderRow>
<HeaderCell>
<MaterialButton
fullWidth
style={{ justifyContent: 'flex-start' }}
endIcon={getIcon('TASK')}
onClick={() =>
sort.fns.onToggleSort({
sortKey: 'TASK',
})
}
>
Task
</MaterialButton>
</HeaderCell>

...

</HeaderRow>
</Header>

<Body>
...
</Body>
</>
)}
</Table>
);
};

请注意 useSort 中的排序对象如何为你提供创建自定义组件所需的一切。这样,你可以为每个表格列自定义排序组件。通过使用排序状态和所有排序功能,你可以从任何地方读取和写入排序状态。