如何为React Table 7提供自定义排序函数?

10

useSortBy的文档中描述了sortType属性:

sortType: String | Function(rowA: <Row>, rowB: <Row>, columnId: String, desc: Bool)

    Used to compare 2 rows of data and order them correctly.
    If a function is passed, it must be memoized. The sortType function should return -1 if rowA is larger, and 1 if rowB is larger. react-table will take care of the rest.
    String options: basic, datetime, alphanumeric. Defaults to alphanumeric.
    The resolved function from the this string/function will be used to sort the this column's data.
        If a string is passed, the function with that name located on either the custom sortTypes option or the built-in sorting types object will be used.
        If a function is passed, it will be used.
    For more information on sort types, see Sorting

但是它并没有完全解释如何使用它。

那么如何提供sortType函数呢?

5个回答

23

sortType函数的参数为:(rowA, rowB, columnId, desc)

columnId 表示行正在按哪一列进行排序,因此可以获得单元格的值。

desc 表示排序的方向。即使提供了desc,排序函数也不应该反转返回值。React表格会自动执行此操作。

例如:

sortType: React.useMemo((rowA, rowB, id, desc) => {
       if (rowA.values[id] > rowB.values[id]) return 1; 
       if (rowB.values[id] > rowA.values[id]) return -1;
        return 0;
})

如何使用sortType的示例:

const columns = [{       
        Header: ...
        accessor: ...
        sortType: /*sortType func goes here... */        
}, ...]

function MyTable(columns, data)
{
 const { /*...*/ } = useTable({columns,data})
}

谢谢您的回复,但我不确定您是如何从react-table文档中得出那个答案的...您怎么知道行将具有类型为对象的属性,并且可以使用id属性访问?由于我正在类组件中构建列,然后将它们传递给呈现组件来构建表格,所以我也遇到了“React Hook“React.useMemo”不能在类组件中调用”的错误。有没有解决方法? - rook218
1
https://react-table.tanstack.com/docs/api/useSortBy 的翻译你需要将这个函数传递给Columns。我仍在考虑如何自己完成,但我会在想到东西时发布。你不能在React类组件中使用hooks。我会把所有与react-table相关的内容放在功能组件中。所有文档都将它们放在同一个文件中,但我也试图进行一些分离。 - Eman4real
@Tom,针对你上面的排序函数,我怀疑大多数人会使用rowA.values[id]而不是rowA.original[id]。此外,常见的语义>可能会返回1而不是-1 - Ken Lin
@Eman4real,不需要内联您的函数。只需像我在这里所做的那样提供sortType与您的比较函数的名称(例如compareNumericString)即可。 - Ken Lin

9

根据您的文档引用,sortType是一个 列选项

任何传递给useTable()中的columns选项的Column对象都支持以下选项

例如,修改快速入门中的定义列如下:

const columns = React.useMemo(
  () => [
    {
      Header: 'Column 1',
      accessor: 'col1', // accessor is the "key" in the data
    },
    {
      Header: 'Column 2',
      accessor: 'col2',
      sortType: compareNumericString // custom function
    },
  ],
  []
)

function compareNumericString(rowA, rowB, id, desc) {
    let a = Number.parseFloat(rowA.values[id]);
    let b = Number.parseFloat(rowB.values[id]);
    if (Number.isNaN(a)) {  // Blanks and non-numeric strings to bottom
        a = desc ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY;
    }
    if (Number.isNaN(b)) {
        b = desc ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY;
    }
    if (a > b) return 1; 
    if (a < b) return -1;
    return 0;
}

这对于排序一行科学格式的数字(作为字符串返回到渲染器)非常有用。这样我们就不必关心它们是否被列为字符串。 - superk
唯一有效的解决方案。 - Daniel Danielecki

5

我也花了很多时间才理解这个问题。以下是我的做法。虽然是TypeScript,但如果需要纯JS,只需去掉所有类型定义即可。首先,这是自定义排序函数。它将排序字符串,并始终将null、空字符串和未定义的值放在末尾。

const customStringSort: any = (rowA: Row, rowB: Row, columnId: string, desc: boolean) => {
  const defaultVal = desc ? 'AAAAAAAAAAAA' : 'ZZZZZZZZ';
  return (rowA.values[columnId] ?? defaultVal)
    .localeCompare(rowB.values[columnId] ?? defaultVal);
};

关于此事,需要注意两点。

  1. 我无法理解为什么TypeScript不喜欢将返回值定义为数字,我不想使用 any,但这样可行。
  2. React 表的文档指出这必须进行记忆化,但是未进行记忆化仍能正常工作。

接下来,您需要将此函数添加到 sortTypes 中。

const sortTypes: Record<string, SortByFn<SomeObject>> = {
  customStringSort: customStringSort,
};

接下来,将sortTypes添加到useTable实例中。

const {
  getTableProps,
  getTableBodyProps
  headerGroups,
  rows,
  prepareRow,
  } = useTable(
    {
      columns,
      data,
      sortTypes
    },
  useSortBy
);

现在你可以将自定义函数添加到你的列定义中。

const columns: Column<SomeObject>[] = React.useMemo(() => 
  [
    { accessor: 'someColumnID', Header: 'Some Column', sortType:'customStringSort' },
  ],
  [],
);

希望这能帮到你!

--编辑:如果你想要记忆化函数,可以使用这个方法。只需要在适当的地方将customStringSort替换为customStringSortMemo。

const customStringSort: any = React.useCallback((rowA: Row, rowB: Row, columnId: string, desc: boolean) => 
  {
  const defaultVal = desc ? 'AAAAAAAAAAAA' : 'ZZZZZZZZ';
  return (rowA.values[columnId] ?? defaultVal).localeCompare(rowB.values[columnId] ?? defaultVal);
  },
[]);
    
const customStringSortMemo = React.useMemo(() => customStringSort[customStringSort]);

1
关于 TS 和 any,你的类型放错了位置。它应该在参数后面。例如:const customStringSort = (rowA: Row, rowB: Row, columnId: string, desc: boolean):number => { - Kildareflare

1

-1

在常量列中将自定义排序放在最后一个标题

const columns = React.useMemo(
            () => [
              {
                Header: 'ID',
                accessor: 'IDXX_GRPX'
              },
              {
                Header: 'Nama Group',
                accessor: 'NAMA_GRPX'
              },
              {
                Header: 'Kecamatan',
                accessor: 'KECX_DESC'
              },
              {
                Header: 'Kelurahan',
                accessor: 'AREA_DESC'
              },
              {
                Header: 'Unit',
                accessor: 'BUSS_CODE'
              },
              {
                Header: 'Kode Urut',
                accessor: 'KODE_URUT',
                sortType: (a, b) => {
                      if (a.values['KODE_URUT'] < b.values['KODE_URUT']) {
                          return -1;
                      } else if (a.values['KODE_URUT'] > b.values['KODE_URUT']) {
                          return 1;
                      };
    
                      return 0;
                  }
              }
            ],
            []
          );

1
目前你的回答不够清晰,请[编辑]以添加更多细节,帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community
1
这并没有回答问题。一旦您拥有足够的声望,您将能够评论任何帖子;相反,提供不需要询问者澄清的答案。- 来自审核 - MD. RAKIB HASAN

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接