如果初始排序完成,使用排序数组反应 useState 不会导致重新渲染 SemanticUI 表 [英] React useState with sorted array does not cause re-render of SemanticUI table if initial sorting is done

查看:31
本文介绍了如果初始排序完成,使用排序数组反应 useState 不会导致重新渲染 SemanticUI 表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a table with SemanticUI that renders a list of companies and allows the list to be resorted based on clicking the header of the table. I thought I had this wrapped up working fine (the dev env is sending me a pre-sorted list), but when writing tests, I realized I cannot guarantee the list is pre-sorted.
So I edited my initial useState logic to have a sort function which is the same logic for the header click:

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

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

上述两个初始 UI 看起来都不错,但是当我单击标题时,这就是出现问题的地方:UI 没有改变(重新渲染).

The initial UI looks OK with both above, but when I click the header, this is where the issue appears: the UI does not change (re-render).

在我逐步执行代码时,我看到正确重新排序的数组在那里,但在 React 内部的某处,该数组不会触发状态更改.

In my stepping through the code, I see that the correctly RE-sorted array is there, but somewhere in the React internals, the array does not trigger a state change.

我尝试了多种选择,包括:1) 更改状态,使 data 成为 sortedColumnData 的一部分,2) 制作 useEffect 钩子,允许初始公司数据在那里,然后我们setData.3) 尝试创建一个 usePrevious 钩子来比较 sortedColumnData,然后在依赖项改变时调用 setData.4) 从 Functional 改为 PureComponent,但这也不能完全解决.

I have tried a plethora of options including: 1) changing the state so that the data is part of the sortedColumnData, 2) making an useEffect hook that allows for the initial company data to be there and then we setData. 3) trying to create a usePrevious hook that compares the sortedColumnData and then calls setData if that dependency changes. 4) changed from a Functional to PureComponent, but this isn't fully solving it either.

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

I know that React only shallow diffs so that might be part of it, but the data array shape itself is shallow so I thought this would be picked up (which is does if I do not initial sort data):

{
  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-汤普森-vg2x1

So, here is a CodeSandBox link: 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>
  );
};

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

I am not sure why the re-rendering from setting state with the re-sorted array is failing...

推荐答案

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

Its happening because you passed the reference of your props to sort function and trying to set it in state, you cannot mutate a prop, its the fundamental of React. If you want to store a prop into state kill the reference first. Hope it answers your doubt :)

  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;
  });
};

这篇关于如果初始排序完成,使用排序数组反应 useState 不会导致重新渲染 SemanticUI 表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆