Home > database >  ReactJs: Warning: Each child in a list should have a unique "key" prop
ReactJs: Warning: Each child in a list should have a unique "key" prop

Time:04-11

I am doing a project in order to run a contracting company and somewhere I have to show all the receipts for each user of the company, but I got this error:

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

Although I looked at the code, I didn't find any errors

How can I solve the problem?

Through this file, I display a table, and this table displays a list of receipts

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

CodePudding user response:

Your problem is from <><TableRow key={n.id}></TableRow></>

In your case, I think you don't need to have <></>, so you can get rid of that, your key missing problem will be solved

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>

If you want to maintain <></> (as the shortcut for <React.Fragment></React.Fragment>). You need to explicitly call

<React.Fragment key={n.id}>
   <TableRow></TableRow>
</React.Fragment>

CodePudding user response:

List must have a unique key while mapping. The best way to pick a key is to use a string that uniquely identifies a list item among its siblings. Most often you would use IDs from your data as keys.

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

CodePudding user response:

Here you must give key to first div:

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>
      );
  • Related