You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FluentUI DetailsList自定义列排序功能的类型错误修复求助

修复FluentUI DetailsList排序功能的TypeScript类型错误

核心问题梳理

原代码的类型错误主要来自三个方面:

  • React Hooks使用违规:在事件处理函数_onColumnClick内部声明useState,违反Hooks必须在组件顶层调用的规则
  • 状态类型定义错误:用useState<[]>定义固定长度的空数组,而非实际需要的IColumn[]和业务数据类型数组
  • 类型安全缺失:未处理状态可能为undefined的情况,排序函数未对可比较类型做约束

分步修复方案

1. 定义明确的数据类型

先声明列表项和组件属性的类型(根据业务实际调整):

import { IColumn, DetailsList } from '@fluentui/react';
import { useSelector, useState } from 'react';

// 列表项的业务类型
interface IName {
  name: string;
  age: number;
}

// 组件属性类型
interface INamesListProps {
  // 补充你的自定义属性
}

2. 把状态移到组件顶层

删除_onColumnClick内部的useState,将状态声明在组件函数的顶层:

export const NamesListBase: React.FunctionComponent<INamesListProps> = (props: INamesListProps) => {
  // 初始化列配置并作为状态管理
  const [columns, setColumns] = useState<IColumn[]>(buildColumns());
  // 从Redux获取原始数据,维护本地排序后的状态
  const originalNames = useSelector<RootState, IName[]>(selectAllNames);
  const [sortedNames, setSortedNames] = useState<IName[]>(originalNames);

  // 以下定义_onColumnClick和_copyAndSort函数
  // ...
}

3. 修复排序函数的类型约束

给_copyAndSort添加类型约束,确保排序的属性是可比较的string | number类型:

function _copyAndSort<T extends Record<string, string | number>>(items: T[], columnKey: keyof T, isSortedDescending?: boolean): T[] {
  return [...items].sort((a, b) => {
    if (isSortedDescending) {
      return a[columnKey] < b[columnKey] ? 1 : -1;
    }
    return a[columnKey] > b[columnKey] ? 1 : -1;
  });
}

4. 修复列点击事件的类型错误

调整_onColumnClick,处理列状态更新,同时避免空值访问:

const _onColumnClick = (ev: React.MouseEvent<HTMLElement>, targetColumn: IColumn): void => {
  // 复制列数组,避免直接修改原状态
  const newColumns = [...columns].map(col => {
    if (col.key === targetColumn.key) {
      // 切换排序方向,默认从升序开始
      const newIsSortedDescending = !col.isSortedDescending;
      return {
        ...col,
        isSorted: true,
        isSortedDescending: newIsSortedDescending
      };
    }
    // 其他列取消排序状态
    return { ...col, isSorted: false, isSortedDescending: false };
  });

  // 获取当前点击的列,校验字段存在性
  const currColumn = newColumns.find(col => col.key === targetColumn.key);
  if (!currColumn?.fieldName) return;

  // 执行排序并更新状态
  const sortedItems = _copyAndSort(originalNames, currColumn.fieldName as keyof IName, currColumn.isSortedDescending);
  setColumns(newColumns);
  setSortedNames(sortedItems);
}

5. 修正buildColumns函数

确保buildColumns引用组件内部的_onColumnClick:

const buildColumns = (): IColumn[] => {
  return [
    {
      key: "name",
      name: "Name",
      fieldName: "name",
      minWidth: 75,
      maxWidth: 75,
      isResizable: false,
      onColumnClick: _onColumnClick
    },
    {
      key: "age",
      name: "Age",
      fieldName: "age",
      minWidth: 200,
      maxWidth: 200,
      isResizable: false,
      onColumnClick: _onColumnClick
    }
  ];
}

6. 调整DetailsList的数据源

使用排序后的本地状态数据渲染列表:

return (
  <div>
    <DetailsList items={sortedNames} columns={columns} />
  </div>
);

关键错误解释

  • useState<[]>问题:[]在TypeScript中是固定长度的空数组类型,无法添加元素,必须显式声明为IColumn[]或IName[]
  • 事件函数内用Hooks:React要求Hooks必须在组件顶层调用,不能嵌套在事件处理、循环等函数内
  • undefined处理:通过初始化状态时传入默认值(buildColumns()、originalNames),以及使用可选链?.避免空值访问

内容的提问来源于stack exchange,提问作者user989988

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 22:34:53