首页 > 解决方案 > 通过数组索引从基于数组的状态中删除是否安全?

问题描述

我刚开始使用 React,我想知道通过数组索引删除是否安全,或者这是否会导致某种竞争条件/时间问题。作为一个具体的例子,让我们考虑一个有 3 行的表,每行都有一个删除按钮:

在此处输入图像描述

所以我的状态包含:

first row  (index 0)
second row (index 1)
third row  (index 2)

现在用户删除了第二行,给我们留下了这个数组内容:

first row  (index 0)
third row  (now index 1 instead of 2)

接下来,用户在组件重新渲染之前单击第三行,因此第三行的删除按钮仍然引用索引 2 而不是已经索引 1。因此splice(index, 2)执行导致错误,因为索引 2 不再存在。

如果用户快速点击删除按钮,这在 React 中理论上是可能的吗?

示例代码 / Codesandbox

这是一些具体的代码示例,也可以在我的 Github 存储库中找到,尤其是在Codesandbox

App.tsx(相关代码摘录)

<MyTable
  initialRows={[
    { id: 101, content: 'first row' },
    { id: 102, content: 'second row' },
    { id: 103, content: 'third row' }
  ]}
/>

MyTable.tsx(相关代码摘录)

import { FC, useState } from 'react';

interface Row {
  id: number;
  content: string;
}

interface Props {
  initialRows: Row[];
}

export const MyTable: FC<Props> = function ({ initialRows }) {
  const [rows, setRows] = useState(initialRows);

  return (
    <table>
      <tbody>
        {rows.map((row, index) => (
          <tr key={`id${row.id}`}>
            <td>{row.content}</td>
            <td>
              <button
                type="button"
                onClick={() => {
                  const newRows = [...rows];
                  newRows.splice(index, 1);
                  setRows(newRows);
                }}
              >
                remove
              </button>
            </td>
          </tr>
        ))}
      </tbody>
    </table>
  );
};

标签: reactjsreact-hooksuse-state

解决方案


您的 onClick 处理程序应如下所示:

onClick={() => setRows(rows.filter(elem => elem.id != row.id ))}

如果您有一组对象,这是最好的方法。在现实世界的应用程序中,应该首先调用 API 来更改数据库中的数据,如果成功,然后才使用过滤器方法更新行状态。


推荐阅读