React Dynamic Table 和嵌套地图

React Dynamic Table and Nested Maps

我必须做一个 users/permissions table,其中“权限”是 X 轴,“用户”是 Y 轴。 table 的其余部分填充了指示 X 用户是否具有 Y 权限的复选框。 这两个都是动态长度,每个 API 都可以某种方式访问​​另一个。即:Permissions API 对每个 Permission 都有一组具有该权限的用户。 反之亦然,用户 API 对每个用户都有一组用户拥有的权限。

  1. 我在使用嵌套地图时遇到问题,我觉得这样做成本很高? (如果有40个权限,350个用户,我们说的是14k个checkbox)

  2. 如何保存每个复选框的状态?没关系,我正在尝试使用检查 useState 做什么?我还需要一种方法来将更新的权限发送给另一个 API.

  3. 在 return 语句中使用“isChecked”常量,我强制复选框只为 true 或 false,并且在单击时无法更改。

  4. 在 return 声明中,我应该映射“支票”,但由于某种原因没有像我期望的那样被填充。

    [{ 用户ID:号码, permID:数字, 检查:布尔值 }, { 用户ID:号码, permID:数字, 检查:布尔值 }, ETC ]

代码看起来像这样:

const [checks, setChecks] = useState([]);

const users = //GET to users API
const permissions = //GET to permissions API

  const mapPermissions = () => {
    users.map((user: any) => {
      permissions.map((permission: any) => {
        setChecks((prevState: any) => [
          ...prevState,
          {
            userID: user.id,
            permID: permission.id,
            //group_lists is an array of Permissions ID that current user has.
            checked: user.group_lists ? user.group_lists.includes(permission.id) : false,
          },
        ]);
      });
    });
  };

  useEffect(() => {
    mapPermissions();
  }, []);

return (
    <TableContainer component={Paper}>
      <Table className={styles.table}>
        <TableHead>
          <TableRow>
            <TableCell className={styles.blank} />
            {permissions.map((permission) => (
              <TableCell key={permission.id} className={styles.header}>
                {permission.name}
              </TableCell>
            ))}
          </TableRow>
        </TableHead>
        <TableBody>

// Should be replacing this for "checks" state map.

              {users.map((user: any) => (
                <TableRow key={user.id}>
                  <TableCell
                    className={styles.left}
                  >{`${user.first_name} ${user.last_name} (${user.username})`}</TableCell>
                {permissions.map((permission: any) => {
                const isChecked = user.group_lists
                  ? user.group_lists.includes(permission.id)
                  : false;

                return (
                  <TableCell key={`${user.id}-${permission.id}`}>
                    <input
                      type="checkbox"
                      checked={isChecked}
                      onChange={(e: ChangeEvent<HTMLInputElement>) => {
                        console.log({
                          user: user.id,
                          permid: permission.id,
                          currentState: isChecked,
                          futureState: e.target.checked,
                        });
                      }}
                    />
                  </TableCell>
                );
              })}
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </TableContainer>
  );

如果需要,我愿意删除所有内容。提前致谢:)

我稍微简化了您的代码片段,让我更容易上手。我会选择这样的东西

type UpdatesType = {
  userId: number;
  permissionId: number;
  operation: 'add' | 'remove';
}
export const UserPermissionTable: React.FC = ({}) => {
  const [updates, setUpdates] = useState<UpdatesType[]>([]);
  const users =  // get from api
  const permissions =  // get from api

  return (
    <div>
      <table>
        <thead>
          <tr>
            <td />
            {permissions.map((permission) => (
              <td key={permission.id}>{permission.name}</td>
            ))}
          </tr>
        </thead>
        <tbody>
          {users.map((user: any) => (
            <tr key={user.id}>
              <td>{`${user.name}`}</td>
              {permissions.map((permission: any) => {
                const isChecked = user.group_lists
                  ? user.group_lists.includes(permission.id)
                  : false;

                return (
                  <td key={`${user.id}-${permission.id}`}>
                    <input
                      type="checkbox"
                      defaultChecked={isChecked}
                      onChange={(e) => {
                        setUpdates((prev) => [
                          ...prev,
                          {
                            userId: user.id,
                            permissionId: permission.id,
                            operation: e.target.checked ? "add" : "remove",
                          },
                        ]);
                      }}
                    />
                  </td>
                );
              })}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

要点:

  1. 您不需要自己处理每个复选框的状态,您可以使用 defaultChecked 属性并在复选框更改时更新 updates 对象
  2. 在我的示例中,我将所有更新放入一个数组中,然后您可以将此数组与操作一起发送到任何您想要的地方 - 您也可以在发送到 API 之前删除重复的操作,但这不是目的这个问题