我有一个带有SemanticUI的表,该表呈现公司列表,并允许通过单击表头对列表进行重新排序。我以为我已经把它整理好了(开发环境正在向我发送一个预先排序的列表),但是在编写测试时,我意识到我不能保证该列表是预先排序的。因此,我编辑了初始的useState
逻辑以具有排序功能,该功能与标题单击的逻辑相同:
[之前(有效):const [data, setData] = useState(companies);
之后(不起作用):const [data, setData] = useState(companySortData(companies, COLUMN_NAME.NAME));
初始的UI在以上两个方面看起来都不错,但是当我单击标题时,这就是问题所在:UI不变(重新渲染)。
在我遍历代码时,我看到在那里有正确的RE排序数组,但是在React内部,该数组不会触发状态更改。
我尝试了很多选择,包括:1)更改状态,以使data
是sortedColumnData
的一部分,2)制作一个useEffect
挂钩,以允许初始公司数据存在,然后我们setData
。 3)尝试创建一个比较usePrevious
的sortedColumnData
钩子,然后在依赖关系发生变化时调用setData
。 4)从Functional更改为PureComponent,但这也不能完全解决它。
我知道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>
);
};
我不确定为什么从具有重新排序数组的设置状态重新渲染失败...
之所以发生,是因为您传递了props的引用以对函数进行排序并尝试将其设置为状态,因此您无法对prop进行突变,这是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;
});
};