skip to Main Content

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

Check the render method of UserSidebar. See https://reactjs.org/link/warning-keys for more information.

This is the code that causes the error shown above:

import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import Drawer from "@material-ui/core/Drawer";
import { Avatar, Button } from "@material-ui/core";
import { CryptoState } from "../CryptoContext";
import { signOut } from "firebase/auth";
import { auth, db } from "../firebase";
import { numberWithCommas } from "./Banner/Carousel";
import { AiFillDelete } from "react-icons/ai";
import { doc, setDoc } from "firebase/firestore";

const useStyles = makeStyles({
  container: {
    width: 350,
    padding: 25,
    height: "100%",
    display: "flex",
    flexDirection: "column",
    fontFamily: "monospace",
  },
  profile: {
    flex: 1,
    display: "flex",
    flexDirection: "column",
    alignItems: "center",
    gap: "20px",
    height: "92%",
  },
  logout: {
    height: "8%",
    width: "100%",
    backgroundColor: "#EEBC1D",
    marginTop: 20,
  },
  picture: {
    width: 200,
    height: 200,
    cursor: "pointer",
    backgroundColor: "#EEBC1D",
    objectFit: "contain",
  },
  watchlist: {
    flex: 1,
    width: "100%",
    backgroundColor: "grey",
    borderRadius: 10,
    padding: 15,
    paddingTop: 10,
    display: "flex",
    flexDirection: "column",
    alignItems: "center",
    gap: 12,
    overflowY: "scroll",
  },
  coin: {
    padding: 10,
    borderRadius: 5,
    color: "black",
    width: "100%",
    display: "flex",
    justifyContent: "space-between",
    alignItems: "center",
    backgroundColor: "#EEBC1D",
    boxShadow: "0 0 3px black",
  },
});

export default function UserSidebar() {
  const classes = useStyles();
  const [state, setState] = React.useState({
    right: false,
  });
  const { user, setAlert, watchlist, tokens, symbol } = CryptoState();

  const toggleDrawer = (anchor, open) => (event) => {
    if (
      event.type === "keydown" &&
      (event.key === "Tab" || event.key === "Shift")
    ) {
      return;
    }

    setState({ ...state, [anchor]: open });
  };

  const logOut = () => {
    signOut(auth);
    setAlert({
      open: true,
      type: "success",
      message: "Logout Successfull!",
    });

    toggleDrawer();
  };

  const removeFromWatchlist = async (coin) => {
    const coinRef = doc(db, "watchlist", user.uid);
    try {
      await setDoc(
        coinRef,
        { tokens: watchlist.filter((wish) => wish !== coin?.id) },
        { merge: true }
      );

      setAlert({
        open: true,
        message: `${coin.name} Removed from the Watchlist !`,
        type: "success",
      });
    } catch (error) {
      setAlert({
        open: true,
        message: error.message,
        type: "error",
      });
    }
  };

  return (
    <div>
      {["right"].map((anchor) => (
        <React.Fragment key={anchor}>
          <Avatar
            onClick={toggleDrawer(anchor, true)}
            style={{
              height: 38,
              width: 38,
              marginLeft: 15,
              cursor: "pointer",
              backgroundColor: "#EEBC1D",
            }}
            src={user.photoURL}
            alt={user.displayName || user.email}
          />
          <Drawer
            anchor={anchor}
            open={state[anchor]}
            onClose={toggleDrawer(anchor, false)}
          >
            <div className={classes.container}>
              <div className={classes.profile}>
                <Avatar
                  className={classes.picture}
                  src={user.photoURL}
                  alt={user.displayName || user.email}
                />
                <span
                  style={{
                    width: "100%",
                    fontSize: 25,
                    textAlign: "center",
                    fontWeight: "bolder",
                    wordWrap: "break-word",
                  }}
                >
                  {user.displayName || user.email}
                </span>
                <div className={classes.watchlist}>
                  <span style={{ fontSize: 15, textShadow: "0 0 5px black" }}>
                    Watchlist
                  </span>
                  {tokens.map((coin) => {
                    if (watchlist.includes(coin.id))
                      return (
                        <div key={coin.id} className={classes.coin}>
                          <span>{coin.name}</span>
                          <span style={{ display: "flex", gap: 8 }}>
                            {symbol}{" "}
                            {numberWithCommas(coin.current_price.toFixed(2))}
                            <AiFillDelete
                              style={{ cursor: "pointer" }}
                              fontSize="16"
                              onClick={() => removeFromWatchlist(coin)}
                            />
                          </span>
                        </div>
                      );
                    else return <></>;
                  })}
                </div>
              </div>
              <Button
                variant="contained"
                className={classes.logout}
                onClick={logOut}
              >
                Log Out
              </Button>
            </div>
          </Drawer>
        </React.Fragment>
      ))}
    </div>
  );
}

I have already provided keys at specific places where it was required, yet I can’t find the mistake in the code.

2

Answers


  1. You have to give unique key to all tags inside map builder.

    In this code :

    <div className={classes.watchlist}>
                      <span style={{ fontSize: 15, textShadow: "0 0 5px black" }}>
                        Watchlist
                      </span>
                      {tokens.map((coin) => {
                        if (watchlist.includes(coin.id))
                          return (
                            <div key={coin.id} className={classes.coin}>
                              <span>{coin.name}</span>
                              <span style={{ display: "flex", gap: 8 }}>
                                {symbol}{" "}
                                {numberWithCommas(coin.current_price.toFixed(2))}
                                <AiFillDelete
                                  style={{ cursor: "pointer" }}
                                  fontSize="16"
                                  onClick={() => removeFromWatchlist(coin)}
                                />
                              </span>
                            </div>
                          );
                        else return <></>;
                      })}
                    </div>
    

    You only give key to <div key={coin.id} className={classes.coin}> this tag. but not on other tags like <span> etc.

    One solution is to give all tags a unique key.

    Second and preferred solution is to export a functional component and give single tag to it.

    for example :

    function CoinCard({ coin }) {
        return <div className={classes.coin}>
            <span>{coin.name}</span>
            <span style={{ display: "flex", gap: 8 }}>
                {symbol}{" "}
                {numberWithCommas(coin.current_price.toFixed(2))}
                <AiFillDelete
                    style={{ cursor: "pointer" }}
                    fontSize="16"
                    onClick={() => removeFromWatchlist(coin)}
                />
            </span>
        </div>
    }
    

    and use this CoinCard and give key –

    <div className={classes.watchlist}>
            <span style={{ fontSize: 15, textShadow: "0 0 5px black" }}>
                Watchlist
            </span>
            {tokens.map((coin, key) => {
                if (watchlist.includes(coin.id))
                    return (
                        <CoinCard coin={coin} key={key} />
                    );
                else return null;
            })}
        </div>
    

    to understand, read this official docs

    Let me know if you understand well

    Login or Signup to reply.
  2. else return <></>
    

    so <></> is returned without a key.

    you can simply return an emty string to avoid the warining

    else return ''
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search