代码之家  ›  专栏  ›  技术社区  ›  Hiba Youssef

ReactJs:警告:列表中的每个孩子都应该有一个唯一的“键”道具

  •  -2
  • Hiba Youssef  · 技术社区  · 3 年前

    我做一个项目是为了经营一家承包公司,在某个地方我必须显示公司每个用户的所有收据,但我得到了这个错误:

    Warning: Each child in a list should have a unique "key" prop.
    

    虽然我查看了代码,但没有发现任何错误

    我怎样才能解决这个问题?

    通过这个文件,我显示了一个表,这个表显示了一个收据列表

    import FuseScrollbars from "@fuse/core/FuseScrollbars";
    import _ from "@lodash";
    import Checkbox from "@material-ui/core/Checkbox";
    import Icon from "@material-ui/core/Icon";
    import Table from "@material-ui/core/Table";
    import TableBody from "@material-ui/core/TableBody";
    import TableCell from "@material-ui/core/TableCell";
    import TablePagination from "@material-ui/core/TablePagination";
    import TableRow from "@material-ui/core/TableRow";
    import Typography from "@material-ui/core/Typography";
    import clsx from "clsx";
    import { motion } from "framer-motion";
    import { useEffect, useState } from "react";
    import { useDispatch, useSelector } from "react-redux";
    import { withRouter } from "react-router-dom";
    import FuseLoading from "@fuse/core/FuseLoading";
    import {
      getSalaryScales,
      selectSalaryScales,
    } from "../store/salaryScalesSlice";
    import SalaryScalesTableHead from "./SalaryScalesTableHead";
    import Moment from "react-moment";
    import IconButton from "@material-ui/core/IconButton";
    import KeyboardArrowDownIcon from "@material-ui/icons/KeyboardArrowDown";
    import KeyboardArrowUpIcon from "@material-ui/icons/KeyboardArrowUp";
    
    function SalaryScalesTable(props) {
      const dispatch = useDispatch();
      const salaryScales = useSelector(selectSalaryScales);
      const searchText = useSelector(
        ({ salaryScalesApp }) => salaryScalesApp.salaryScales.searchText
      );
    
      const [loading, setLoading] = useState(true);
      const [selected, setSelected] = useState([]);
      const [data, setData] = useState(salaryScales);
      const [page, setPage] = useState(0);
      const [rowsPerPage, setRowsPerPage] = useState(10);
      const [order, setOrder] = useState({
        direction: "asc",
        id: null,
      });
    
      const [open, setOpen] = useState(false);
      console.log("order: ", order);
    
      useEffect(() => {
        dispatch(getSalaryScales()).then(() => setLoading(false));
      }, [dispatch]);
    
      useEffect(() => {
        if (searchText.length !== 0) {
          setData(
            _.filter(salaryScales, (item) =>
              item.id.toLowerCase().includes(searchText.toLowerCase())
            )
          );
          setPage(0);
        } else {
          setData(salaryScales);
        }
      }, [salaryScales, searchText]);
    
      function handleRequestSort(event, property) {
        const id = property;
        let direction = "desc";
    
        if (order.id === property && order.direction === "desc") {
          direction = "asc";
        }
    
        setOrder({
          direction,
          id,
        });
      }
    
      function handleSelectAllClick(event) {
        if (event.target.checked) {
          setSelected(data.map((n) => n.id));
          return;
        }
        setSelected([]);
      }
    
      function handleDeselect() {
        setSelected([]);
      }
    
      function handleClick(item) {
        props.history.push(`/apps/salary-scales-section/salary-scales/${item.id}`);
      }
    
      function handleCheck(event, id) {
        const selectedIndex = selected.indexOf(id);
        let newSelected = [];
    
        if (selectedIndex === -1) {
          newSelected = newSelected.concat(selected, id);
        } else if (selectedIndex === 0) {
          newSelected = newSelected.concat(selected.slice(1));
        } else if (selectedIndex === selected.length - 1) {
          newSelected = newSelected.concat(selected.slice(0, -1));
        } else if (selectedIndex > 0) {
          newSelected = newSelected.concat(
            selected.slice(0, selectedIndex),
            selected.slice(selectedIndex + 1)
          );
        }
    
        setSelected(newSelected);
      }
    
      function handleChangePage(event, value) {
        setPage(value);
      }
    
      function handleChangeRowsPerPage(event) {
        setRowsPerPage(event.target.value);
      }
    
      if (loading) {
        return <FuseLoading />;
      }
    
      if (data.length === 0) {
        return (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1, transition: { delay: 0.1 } }}
            className="flex flex-1 items-center justify-center h-full"
          >
            <Typography color="textSecondary" variant="h5">
              There are no Salary Scales!
            </Typography>
          </motion.div>
        );
      }
    
      return (
        <div className="w-full flex flex-col">
          <FuseScrollbars className="flex-grow overflow-x-auto">
            <Table stickyHeader className="min-w-xl" aria-label="collapsible table">
              <SalaryScalesTableHead
                selectedSalaryScaleIds={selected}
                order={order}
                onSelectAllClick={handleSelectAllClick}
                onRequestSort={handleRequestSort}
                rowCount={data.length}
                onMenuItemClick={handleDeselect}
              />
    
              <TableBody>
                {_.orderBy(
                  data,
                  [
                    (o) => {
                      switch (order.id) {
                        case "categories": {
                          return o.categories[0];
                        }
                        default: {
                          return o[order.id];
                        }
                      }
                    },
                  ],
                  [order.direction]
                )
                  .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
                  .map((n) => {
                    const isSelected = selected.indexOf(n.id) !== -1;
                    return (
                      <>
                        <TableRow
                          className="h-72 cursor-pointer"
                          hover
                          role="checkbox"
                          aria-checked={isSelected}
                          tabIndex={-1}
                          key={n.id}
                          selected={isSelected}
                          onClick={(event) => handleClick(n)}
                        >
                          <TableCell
                            className="w-40 md:w-64 text-center"
                            padding="none"
                          >
                            <Checkbox
                              checked={isSelected}
                              onClick={(event) => event.stopPropagation()}
                              onChange={(event) => handleCheck(event, n.id)}
                            />
                          </TableCell>
                          <TableCell>
                            <IconButton
                              aria-label="expand row"
                              size="small"
                              onClick={() => setOpen(!open)}
                              className="w-40 md:w-64 text-center"
                              padding="none"
                            >
                              {open ? (
                                <KeyboardArrowUpIcon />
                              ) : (
                                <KeyboardArrowDownIcon />
                              )}
                            </IconButton>
                          </TableCell>
                          <TableCell
                            className="p-4 md:p-16"
                            component="th"
                            scope="row"
                            align="left"
                          >
                            {n.id}
                          </TableCell>
    
                          <TableCell
                            className="p-4 md:p-16"
                            component="th"
                            scope="row"
                            align="center"
                          >
                            <Moment>{n.createdAt}</Moment>
                          </TableCell>
    
                          <TableCell
                            className="p-4 md:p-16"
                            component="th"
                            scope="row"
                            align="center"
                          >
                            {n.isActive ? (
                              <Icon className="text-green text-20">
                                check_circle
                              </Icon>
                            ) : (
                              <Icon className="text-red text-20">
                                remove_circle
                              </Icon>
                            )}
                          </TableCell>
                        </TableRow>
                      </>
                    );
                  })}
              </TableBody>
            </Table>
          </FuseScrollbars>
    
          <TablePagination
            className="flex-shrink-0 border-t-1"
            component="div"
            count={data.length}
            rowsPerPage={rowsPerPage}
            page={page}
            backIconButtonProps={{
              "aria-label": "Previous Page",
            }}
            nextIconButtonProps={{
              "aria-label": "Next Page",
            }}
            onPageChange={handleChangePage}
            onRowsPerPageChange={handleChangeRowsPerPage}
          />
        </div>
      );
    }
    
    export default withRouter(SalaryScalesTable);
    
    3 回复  |  直到 3 年前
        1
  •  3
  •   Nick Vu    3 年前

    你的问题来自 <><TableRow key={n.id}></TableRow></>

    就你而言,我认为你不需要 <></> ,这样你就可以摆脱它,你的钥匙丢失问题就会得到解决

    return (
                        <TableRow
                          className="h-72 cursor-pointer"
                          hover
                          role="checkbox"
                          aria-checked={isSelected}
                          tabIndex={-1}
                          key={n.id}
                          selected={isSelected}
                          onClick={(event) => handleClick(n)}
                        >
                          <TableCell
                            className="w-40 md:w-64 text-center"
                            padding="none"
                          >
                            <Checkbox
                              checked={isSelected}
                              onClick={(event) => event.stopPropagation()}
                              onChange={(event) => handleCheck(event, n.id)}
                            />
                          </TableCell>
                          <TableCell>
                            <IconButton
                              aria-label="expand row"
                              size="small"
                              onClick={() => setOpen(!open)}
                              className="w-40 md:w-64 text-center"
                              padding="none"
                            >
                              {open ? (
                                <KeyboardArrowUpIcon />
                              ) : (
                                <KeyboardArrowDownIcon />
                              )}
                            </IconButton>
                          </TableCell>
                          <TableCell
                            className="p-4 md:p-16"
                            component="th"
                            scope="row"
                            align="left"
                          >
                            {n.id}
                          </TableCell>
    
                          <TableCell
                            className="p-4 md:p-16"
                            component="th"
                            scope="row"
                            align="center"
                          >
                            <Moment>{n.createdAt}</Moment>
                          </TableCell>
    
                          <TableCell
                            className="p-4 md:p-16"
                            component="th"
                            scope="row"
                            align="center"
                          >
                            {n.isActive ? (
                              <Icon className="text-green text-20">
                                check_circle
                              </Icon>
                            ) : (
                              <Icon className="text-red text-20">
                                remove_circle
                              </Icon>
                            )}
                          </TableCell>
                        </TableRow>
    

    如果你想保持 <>< (作为 <React.Fragment></React.Fragment> ).您需要显式调用

    <React.Fragment key={n.id}>
       <TableRow></TableRow>
    </React.Fragment>
    
        2
  •  2
  •   Sudip Shrestha    3 年前

    列表 必须有一个独特的 钥匙 绘制地图时。选择键的最佳方法是使用一个字符串,该字符串在其同级中唯一地标识列表项。大多数情况下,您会使用数据中的ID作为密钥。

        YourArray
        .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
        .map((n) => {
            const isSelected = selected.indexOf(n.id) !== -1;
              return (
                <React.Fragment key={n.id}>
                   <TableRow
                      className="h-72 cursor-pointer"
                      hover
                      role="checkbox"
                      aria-checked={isSelected}
                          tabIndex={-1}
                          key={n.id}
                          selected={isSelected}
                          onClick={(event) => handleClick(n)}
                        >
                          <TableCell
                            className="w-40 md:w-64 text-center"
                            padding="none"
                          >
                            <Checkbox
                              checked={isSelected}
                              onClick={(event) => event.stopPropagation()}
                              onChange={(event) => handleCheck(event, n.id)}
                            />
                          </TableCell>
                          <TableCell>
                            <IconButton
                              aria-label="expand row"
                              size="small"
                              onClick={() => setOpen(!open)}
                              className="w-40 md:w-64 text-center"
                              padding="none"
                            >
                              {open ? (
                                <KeyboardArrowUpIcon />
                              ) : (
                                <KeyboardArrowDownIcon />
                              )}
                            </IconButton>
                          </TableCell>
                          <TableCell
                            className="p-4 md:p-16"
                            component="th"
                            scope="row"
                            align="left"
                          >
                            {n.id}
                          </TableCell>
    
                          <TableCell
                            className="p-4 md:p-16"
                            component="th"
                            scope="row"
                            align="center"
                          >
                            <Moment>{n.createdAt}</Moment>
                          </TableCell>
    
                          <TableCell
                            className="p-4 md:p-16"
                            component="th"
                            scope="row"
                            align="center"
                          >
                            {n.isActive ? (
                              <Icon className="text-green text-20">
                                check_circle
                              </Icon>
                            ) : (
                              <Icon className="text-red text-20">
                                remove_circle
                              </Icon>
                            )}
                          </TableCell>
                        </TableRow>
                      </React.Fragment>
                    );
                  })
    
        3
  •  2
  •   Zia Yamin    3 年前

    给你 key 致第一组:

    return (
        <div key={n.id}>
            <TableRow
            className="h-72 cursor-pointer"
            hover
            role="checkbox"
            aria-checked={isSelected}
            tabIndex={-1}
            selected={isSelected}
            onClick={(event) => handleClick(n)}
            >
              <TableCell
               className="w-40 md:w-64 text-center"
               padding="none"
               >
                 <Checkbox
                 checked={isSelected}
                 onClick={(event) => event.stopPropagation()}
                 onChange={(event) => handleCheck(event, n.id)}
                 />
              </TableCell>
              <TableCell>
                 <IconButton
                  aria-label="expand row"
                  size="small"
                  onClick={() => setOpen(!open)}
                  className="w-40 md:w-64 text-center"
                  padding="none"
                  >
                    {open ? (
                        <KeyboardArrowUpIcon />
                     ) : (
                       <KeyboardArrowDownIcon />
                     )}
                  </IconButton>
                  </TableCell>
                  <TableCell
                     className="p-4 md:p-16"
                     component="th"
                     scope="row"
                     align="left"
                   >
                      {n.id}
              </TableCell>
    
              <TableCell
              className="p-4 md:p-16"
              component="th"
              scope="row"
              align="center"
              >
                  <Moment>{n.createdAt}</Moment>
              </TableCell>
    
               <TableCell
               className="p-4 md:p-16"
               component="th"
               scope="row"
               align="center"
               >
               {n.isActive ? (
                  <Icon className="text-green text-20">
                     check_circle
                  </Icon>
                  ) : (
                  <Icon className="text-red text-20">
                        remove_circle
                  </Icon>
                  )}
                  </TableCell>
              </TableRow>
            </div>
          );