首页 > 解决方案 > 如果初始排序完成,使用排序数组的 React useState 不会导致 SemanticUI 表的重新渲染

问题描述

我有一个带有 SemanticUI 的表,它呈现公司列表,并允许根据单击表的标题来重新选择列表。我以为我已经完成了这项工作(开发环境正在向我发送一个预先排序的列表),但是在编写测​​试时,我意识到我不能保证该列表是预先排序的。
所以我编辑了我的初始useState逻辑以具有一个排序功能,该功能与标题点击的逻辑相同:

之前(工作): const [data, setData] = useState(companies);

之后(不起作用): const [data, setData] = useState(companySortData(companies, COLUMN_NAME.NAME));

上面的初始 UI 看起来都不错,但是当我单击标题时,问题就出现了:UI 没有改变(重新渲染)。

在我逐步执行代码时,我看到正确的 RE-sorted 数组在那里,但是在 React 内部的某个地方,该数组不会触发状态更改。

我尝试了很多选项,包括:1)更改状态,使其data成为. 3)尝试创建一个钩子来比较,然后在依赖项发生变化时调用。4) 从 Functional 更改为 PureComponent,但这也没有完全解决它。sortedColumnDatauseEffectsetDatausePrevioussortedColumnDatasetData

我知道 React 只有浅差异,所以这可能是它的一部分,但数据数组形状本身很浅,所以我认为这会被拾取(如果我不初始排序数据,就会这样做):

{
  id: "newnew",
  name: "A New New Company",
  subdomain: "newnew",
  createdAt: "2019-10-28T21:54:30.253Z",
  updatedAt: "2019-10-28T21:54:30.253Z"
},

所以,这里有一个 CodeSandBox 链接:https ://codesandbox.io/s/wonderful-thompson-vg2x1

这是组件本身:

export const CompanyTable = ({ companies }) => {
  const [sortedColumnData, setSortedColumnData] = useState({
    data: companySortData(companies, COLUMN_NAME.NAME), // swap this initial sorting with just the `companies` and this table works fine
    direction: DIRECTION.ASCENDING,
    columnName: COLUMN_NAME.NAME
  });

  const handleClick = clickedColumn => {
    if (!clickedColumn) return;

    if (sortedColumnData.columnName !== clickedColumn) {
      setSortedColumnData({
        data: companySortData(sortedColumnData.data, clickedColumn),
        columnName: clickedColumn,
        direction: DIRECTION.ASCENDING
      });
      return;
    }

    setSortedColumnData({
      data: sortedColumnData.data.reverse(),
      columnName: clickedColumn,
      direction:
        sortedColumnData.direction === DIRECTION.ASCENDING
          ? DIRECTION.DESCENDING
          : DIRECTION.ASCENDING
    });
  };
  return (
    <Table celled selectable sortable>
      <Table.Header>
        <Table.Row>
          {headerCells.map(cell => (
            <Table.HeaderCell
              key={`cell-${cell.testid}`}
              sorted={
                sortedColumnData.columnName === cell.clickHandlerText
                  ? sortedColumnData.direction
                  : undefined
              }
              data-testid={`header-${cell.testid}`}
              onClick={() => handleClick(cell.clickHandlerText)}
            >
              {cell.title}
            </Table.HeaderCell>
          ))}
        </Table.Row>
      </Table.Header>
      <Table.Body data-testid="company-table-body">
        {sortedColumnData.data.map(
          ({ id, name, subdomain, createdAt, updatedAt }) => {
            return (
              <Table.Row
                key={id}
                role="link"
                data-testid={id}
                style={{ cursor: "pointer" }}
              >
                <Table.Cell singleLine>{name}</Table.Cell>
                <Table.Cell singleLine>{subdomain}</Table.Cell>
                <Table.Cell singleLine>{createdAt}</Table.Cell>
                <Table.Cell singleLine>{updatedAt}</Table.Cell>
              </Table.Row>
            );
          }
        )}
      </Table.Body>
    </Table>
  );
};

我不确定为什么使用重新排序的数组从设置状态重新渲染失败...

标签: reactjsreact-hooks

解决方案


发生这种情况是因为您将 props 的引用传递给 sort 函数并尝试将其设置为状态,您不能改变 props,这是 React 的基础。如果您想将道具存储到状态中,请先杀死参考。希望它能回答你的疑问:)

  const companySortData = (data, sortBy) => {
  let copyData = JSON.parse(JSON.stringify(data));
  return copyData.sort((a, b) => {
    let x = a[sortBy];
    let y = b[sortBy];
    if (sortBy === COLUMN_NAME.CREATED || sortBy === COLUMN_NAME.UPDATED) {
      x = new Date(a.createdAt);
      y = new Date(b.createdAt);
    } else {
      x = a[sortBy].toLowerCase();
      y = b[sortBy].toLowerCase();
    }
    return x < y ? -1 : x > y ? 1 : 0;
  });
};

推荐阅读