[SOLVED] Child unique key _ Ethereum NFT Boilerplate

Hey guys
I’m still abit unsure of what I need to do to fix this error in my code. Is anyone able to explain what I need to do in my code? I’ve cross checked with the repo from the video aswell now and i still can’t get it to work.
Cheers

NFTBalance

import React, { useState } from "react";

import { useMoralis, useNFTBalances } from "react-moralis";

import { Card, Image, Tooltip, Modal, Input, Skeleton } from "antd";

import {

  FileSearchOutlined,

  SendOutlined,

  ShoppingCartOutlined,

} from "@ant-design/icons";

import { getExplorer } from "helpers/networks";

import AddressInput from "./AddressInput";

import { useVerifyMetadata } from "hooks/useVerifyMetadata";

const { Meta } = Card;

const styles = {

  NFTs: {

    display: "flex",

    flexWrap: "wrap",

    WebkitBoxPack: "start",

    justifyContent: "flex-start",

    margin: "0 auto",

    maxWidth: "1000px",

    width: "100%",

    gap: "10px",

  },

};

function NFTBalance() {

  const { data: NFTBalances } = useNFTBalances();

  const { Moralis, chainId } = useMoralis();

  const [visible, setVisibility] = useState(false);

  const [receiverToSend, setReceiver] = useState(null);

  const [amountToSend, setAmount] = useState(null);

  const [nftToSend, setNftToSend] = useState(null);

  const [isPending, setIsPending] = useState(false);

  const { verifyMetadata } = useVerifyMetadata();

  async function transfer(nft, amount, receiver) {

    console.log(nft, amount, receiver);

    const options = {

      type: nft?.contract_type?.toLowerCase(),

      tokenId: nft?.token_id,

      receiver,

      contractAddress: nft?.token_address,

    };

    if (options.type === "erc1155") {

      options.amount = amount ?? nft.amount;

    }

    setIsPending(true);

    try {

      const tx = await Moralis.transfer(options);

      console.log(tx);

      setIsPending(false);

    } catch (e) {

      alert(e.message);

      setIsPending(false);

    }

  }

  const handleTransferClick = (nft) => {

    setNftToSend(nft);

    setVisibility(true);

  };

  const handleChange = (e) => {

    setAmount(e.target.value);

  };

  console.log("NFTBalances", NFTBalances);

  return (

    <div style={{ padding: "15px", maxWidth: "1030px", width: "100%" }}>

      <h1>🖼 NFT Balances</h1>

      <div style={styles.NFTs}>

        <Skeleton loading={!NFTBalances?.result}>

          {NFTBalances?.result &&

            NFTBalances.result.map((nft, index) => {

              //Verify Metadata

              nft = verifyMetadata(nft);

              return (

                <Card

                  hoverable

                  actions={[

                    <Tooltip title="View On Blockexplorer">

                      <FileSearchOutlined

                        onClick={() =>

                          window.open(

                            `${getExplorer(chainId)}address/${

                              nft.token_address

                            }`,

                            "_blank",

                          )

                        }

                      />

                    </Tooltip>,

                    <Tooltip title="Transfer NFT">

                      <SendOutlined onClick={() => handleTransferClick(nft)} />

                    </Tooltip>,

                    <Tooltip title="Sell On OpenSea">

                      <ShoppingCartOutlined

                        onClick={() => alert("OPENSEA INTEGRATION COMING!")}

                      />

                    </Tooltip>,

                  ]}

                  style={{ width: 240, border: "2px solid #e7eaf3" }}

                  cover={

                    <Image

                      preview={false}

                      src={nft?.image || "error"}

                      fallback="data:image/png;base64,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"

                      alt=""

                      style={{ height: "300px" }}

                    />

                  }

                  key={index}

                >

                  <Meta title={nft.name} description={nft.token_address} />

                </Card>

              );

            })}

        </Skeleton>

      </div>

      <Modal

        title={`Transfer ${nftToSend?.name || "NFT"}`}

        visible={visible}

        onCancel={() => setVisibility(false)}

        onOk={() => transfer(nftToSend, amountToSend, receiverToSend)}

        confirmLoading={isPending}

        okText="Send"

      >

        <AddressInput autoFocus placeholder="Receiver" onChange={setReceiver} />

        {nftToSend && nftToSend.contract_type === "erc1155" && (

          <Input

            placeholder="amount to send"

            onChange={(e) => handleChange(e)}

          />

        )}

      </Modal>

    </div>

  );

}

export default NFTBalance;

This error does not seem to be specifically coming from the code you posted (or NFTBalance component). Check for any other uses of map in the project and put a key prop in the outer component, similar to the use of key={index} for the <Card> component.

1 Like

Thank you for your help glad. I found where i think it is lol :slight_smile:

import React, { useState } from "react";

import { useMoralis, useMoralisQuery } from "react-moralis";

import { useMoralisDapp } from "providers/MoralisDappProvider/MoralisDappProvider";

import { Table, Tag, Space } from "antd";

import { PolygonCurrency} from "./Chains/Logos";

import moment from "moment";

const styles = {

  table: {

    margin: "0 auto",

    width: "1000px",

  },

};

function NFTMarketTransactions() {

  const { walletAddress } = useMoralisDapp();

  const { Moralis } = useMoralis();

  const queryItemImages = useMoralisQuery("ItemImages");

  const fetchItemImages = JSON.parse(

    JSON.stringify(queryItemImages.data, [

      "nftContract",

      "tokenId",

      "name",

      "image",

    ])

  );

  const queryMarketItems = useMoralisQuery("MarketItems");

  const fetchMarketItems = JSON.parse(

    JSON.stringify(queryMarketItems.data, [

      "updatedAt",

      "price",

      "nftContract",

      "itemId",

      "sold",

      "tokenId",

      "seller",

      "owner",

    ])

  )

    .filter(

      (item) => item.seller === walletAddress || item.owner === walletAddress

    )

    .sort((a, b) =>

      a.updatedAt < b.updatedAt ? 1 : b.updatedAt < a.updatedAt ? -1 : 0

    );

  function getImage(addrs, id) {

    const img = fetchItemImages.find(

      (element) =>

        element.nftContract === addrs &&

        element.tokenId === id

    );

    return img?.image;

  }

  function getName(addrs, id) {

    const nme = fetchItemImages.find(

      (element) =>

        element.nftContract === addrs &&

        element.tokenId === id

    );

    return nme?.name;

  }

  const columns = [

    {

      title: "Date",

      dataIndex: "date",

      key: "date",

    },

    {

      title: "Item",

      key: "item",

      render: (text, record) => (

        <Space size="middle">

          <img src={getImage(record.collection, record.item)} style={{ width: "40px", borderRadius:"4px"}} />

          <span>#{record.item}</span>

        </Space>

      ),

    },

    {

      title: "Collection",

      key: "collection",

      render: (text, record) => (

        <Space size="middle">

          <span>{getName(record.collection, record.item)}</span>

        </Space>

      ),

    },

    {

      title: "Transaction Status",

      key: "tags",

      dataIndex: "tags",

      render: (tags) => (

        <>

          {tags.map((tag) => {

            let color = "geekblue";

            let status = "BUY";

            if (tag === false) {

              color = "volcano";

              status = "waiting";

            } else if (tag === true) {

              color = "green";

              status = "confirmed";

            }

            if (tag === walletAddress) {

              status = "SELL";

            }

            return (

              <Tag color={color} key={tag}>

                {status.toUpperCase()}

              </Tag>

            );

          })}

        </>

      ),

    },

    {

      title: "Price",

      key: "price",

      dataIndex: "price",

      render: (e) => (

        <Space size="middle">

          <PolygonCurrency/>

          <span>{e}</span>

        </Space>

      ),

    }

  ];

  const data = fetchMarketItems?.map((item, index) => ({

    key: index,

    date: moment(item.updatedAt).format("DD-MM-YYYY HH:mm"),

    collection: item.nftContract,

    item: item.tokenId,

    tags: [item.seller, item.sold],

    price: item.price / ("1e" + 18)

  }));

  return (

    <>

      <div>

        <div style={styles.table}>

          <Table columns={columns} dataSource={data} />

        </div>

      </div>

    </>

  );

}

export default NFTMarketTransactions;

const columns = [

  {

    title: "Date",

    dataIndex: "date",

    key: "date",

  },

  {

    title: "Item",

    key: "item",

  },

  {

    title: "Collection",

    key: "collection",

  },

  {

    title: "Transaction Status",

    key: "tags",

    dataIndex: "tags",

  },

  {

    title: "Price",

    key: "price",

    dataIndex: "price",

  }

];

Hey @alex
This is the part of code that gives me the error. I do have the key for tag and it still doesn’t work. What have i done wrong? :slight_smile:

{

      title: "Transaction Status",

      key: "tags",

      dataIndex: "tags",

      render: (tags) => (

        <>

          {tags.map((tag) => {

            let color = "geekblue";

            let status = "BUY";

            if (tag === false) {

              color = "volcano";

              status = "waiting";

            } else if (tag === true) {

              color = "green";

              status = "confirmed";

            }

            if (tag === walletAddress) {

              status = "SELL";

            }

            return (

              <Tag color={color} key={tag}>

                {status.toUpperCase()}

              </Tag>

            );

          })}

        </>

      ),

    },

So if you get rid of that map, the warning goes away? What happens if you use index instead of tag? Add index and pass into key:

{tags.map((tag, index) => {

That warning should go away as long as there’s anything inside key, even if it’s not valid e.g. duplicate keys with key={1}.

@alex When I get rid of that map I have the same error. When I use index instead of tag I get tag is not defined.

Screenshot 2022-07-24 140930 FOR GLAD

@alex I’ve been doing some trial and error with this part of the code but I still can’t get it to work. :slight_smile:

Can you share your current code again ?

1 Like

Hey Qudusayo
Here is my Code. Cheers

NFTBalance

import React, { useState } from "react";

import { useMoralis } from "react-moralis";

import { Card, Image, Tooltip, Modal, Input, Alert, Spin, Button } from "antd";

import { useNFTBalance } from "hooks/useNFTBalance";

import { FileSearchOutlined, ShoppingCartOutlined } from "@ant-design/icons";

import { useMoralisDapp } from "providers/MoralisDappProvider/MoralisDappProvider";

import { getExplorer } from "helpers/networks";

import { useWeb3ExecuteFunction } from "react-moralis";

const { Meta } = Card;

const styles = {

  NFTs: {

    display: "flex",

    flexWrap: "wrap",

    WebkitBoxPack: "start",

    justifyContent: "flex-start",

    margin: "0 auto",

    maxWidth: "1000px",

    gap: "10px",

  },

};

function NFTBalance() {

  const { NFTBalance, fetchSuccess } = useNFTBalance();

  const { chainId, marketAddress, contractABI } = useMoralisDapp();

  const { Moralis } = useMoralis();

  const [visible, setVisibility] = useState(false);

  const [nftToSend, setNftToSend] = useState(null);

  const [price, setPrice] = useState(1);

  const [loading, setLoading] = useState(false);

  const contractProcessor = useWeb3ExecuteFunction();

  const contractABIJson = JSON.parse(contractABI);

  const listItemFunction = "createMarketItem";

  const ItemImage = Moralis.Object.extend("ItemImages");

  async function list(nft, listPrice) {

    setLoading(true);

    const p = listPrice * ("1e" + 18);

    const ops = {

      contractAddress: marketAddress,

      functionName: listItemFunction,

      abi: contractABIJson,

      params: {

        nftContract: nft.token_address,

        tokenId: nft.token_id,

        price: String(p),

      },

    };

    await contractProcessor.fetch({

      params: ops,

      onSuccess: () => {

        console.log("success");

        setLoading(false);

        setVisibility(false);

        addItemImage();

        succList();

      },

      onError: (error) => {

        setLoading(false);

        failList();

      },

    });

  }

  async function approveAll(nft) {

    setLoading(true);  

    const ops = {

      contractAddress: nft.token_address,

      functionName: "setApprovalForAll",

      abi: [{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"}],

      params: {

        operator: marketAddress,

        approved: true

      },

    };

    await contractProcessor.fetch({

      params: ops,

      onSuccess: () => {

        console.log("Approval Received");

        setLoading(false);

        setVisibility(false);

        succApprove();

      },

      onError: (error) => {

        setLoading(false);

        failApprove();

      },

    });

  }

  const handleSellClick = (nft) => {

    setNftToSend(nft);

    setVisibility(true);

  };

  function succList() {

    let secondsToGo = 5;

    const modal = Modal.success({

      title: "Success!",

      content: `Your NFT was listed on the marketplace`,

    });

    setTimeout(() => {

      modal.destroy();

    }, secondsToGo * 1000);

  }

  function succApprove() {

    let secondsToGo = 5;

    const modal = Modal.success({

      title: "Success!",

      content: `Approval is now set, you may list your NFT`,

    });

    setTimeout(() => {

      modal.destroy();

    }, secondsToGo * 1000);

  }

  function failList() {

    let secondsToGo = 5;

    const modal = Modal.error({

      title: "Error!",

      content: `There was a problem listing your NFT`,

    });

    setTimeout(() => {

      modal.destroy();

    }, secondsToGo * 1000);

  }

  function failApprove() {

    let secondsToGo = 5;

    const modal = Modal.error({

      title: "Error!",

      content: `There was a problem with setting approval`,

    });

    setTimeout(() => {

      modal.destroy();

    }, secondsToGo * 1000);

  }

  function addItemImage() {

    const itemImage = new ItemImage();

    itemImage.set("image", nftToSend.image);

    itemImage.set("nftContract", nftToSend.token_address);

    itemImage.set("tokenId", nftToSend.token_id);

    itemImage.set("name", nftToSend.name);

    itemImage.save();

  }

  return (

    <>

      <div style={styles.NFTs}>

        {contractABIJson.noContractDeployed && (

          <>

            <Alert

              message="No Smart Contract Details Provided. Please deploy smart contract and provide address + ABI in the MoralisDappProvider.js file"

              type="error"

            />

            <div style={{ marginBottom: "10px" }}></div>

          </>

        )}

        {!fetchSuccess && (

          <>

            <Alert

              message="Unable to fetch all NFT metadata... We are searching for a solution, please try again later!"

              type="warning"

            />

            <div style={{ marginBottom: "10px" }}></div>

          </>

        )}

        {NFTBalance &&

          NFTBalance.map((nft, index) => (

            <Card

              hoverable

              actions={[

                <Tooltip title="View On Blockexplorer">

                  <FileSearchOutlined

                    onClick={() =>

                      window.open(

                        `${getExplorer(chainId)}address/${nft.token_address}`,

                        "_blank"

                      )

                    }

                  />

                </Tooltip>,

                <Tooltip title="List NFT for sale">

                  <ShoppingCartOutlined onClick={() => handleSellClick(nft)} />

                </Tooltip>,

              ]}

              style={{ width: 240, border: "2px solid #e7eaf3" }}

              cover={

                <Image

                  preview={false}

                  src={nft?.image || "error"}

                  fallback="data:image/png;base64,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"

                  alt=""

                  style={{ height: "240px" }}

                />

              }

              key={index}

            >

              <Meta title={nft.name} description={nft.contract_type} />

            </Card>

          ))}

      </div>

      <Modal

        title={`List ${nftToSend?.name} #${nftToSend?.token_id} For Sale`}

        visible={visible}

        onCancel={() => setVisibility(false)}

        onOk={() => list(nftToSend, price)}

        okText="List"

        footer={[

          <Button onClick={() => setVisibility(false)}>

            Cancel

          </Button>,

          <Button onClick={() => approveAll(nftToSend)} type="primary">

            Approve

          </Button>,

          <Button onClick={() => list(nftToSend, price)} type="primary">

            List

          </Button>

        ]}

      >

        <Spin spinning={loading}>

          <img

            src={`${nftToSend?.image}`}

            style={{

              width: "250px",

              margin: "auto",

              borderRadius: "10px",

              marginBottom: "15px",

            }}

          />

          <Input

            autoFocus

            placeholder="Listing Price in ETH"

            onChange={(e) => setPrice(e.target.value)}

          />

        </Spin>

      </Modal>

    </>

  );

}

export default NFTBalance;

NFTMarketTransactions

import React, { useState } from "react";

import { useMoralis, useMoralisQuery } from "react-moralis";

import { useMoralisDapp } from "providers/MoralisDappProvider/MoralisDappProvider";

import { Table, Tag, Space } from "antd";

import { PolygonCurrency} from "./Chains/Logos";

import moment from "moment";

const styles = {

  table: {

    margin: "0 auto",

    width: "1000px",

  },

};

function NFTMarketTransactions() {

  const { walletAddress } = useMoralisDapp();

  const { Moralis } = useMoralis();

  const queryItemImages = useMoralisQuery("ItemImages");

  const fetchItemImages = JSON.parse(

    JSON.stringify(queryItemImages.data, [

      "nftContract",

      "tokenId",

      "name",

      "image",

    ])

  );

  const queryMarketItems = useMoralisQuery("MarketItems");

  const fetchMarketItems = JSON.parse(

    JSON.stringify(queryMarketItems.data, [

      "updatedAt",

      "price",

      "nftContract",

      "itemId",

      "sold",

      "tokenId",

      "seller",

      "owner",

    ])

  )

    .filter(

      (item) => item.seller === walletAddress || item.owner === walletAddress

    )

    .sort((a, b) =>

      a.updatedAt < b.updatedAt ? 1 : b.updatedAt < a.updatedAt ? -1 : 0

    );

  function getImage(addrs, id) {

    const img = fetchItemImages.find(

      (element) =>

        element.nftContract === addrs &&

        element.tokenId === id

    );

    return img?.image;

  }

  function getName(addrs, id) {

    const nme = fetchItemImages.find(

      (element) =>

        element.nftContract === addrs &&

        element.tokenId === id

    );

    return nme?.name;

  }

  const columns = [

    {

      title: "Date",

      dataIndex: "date",

      key: "date",

    },

    {

      title: "Item",

      key: "item",

      render: (text, record) => (

        <Space size="middle">

          <img src={getImage(record.collection, record.item)} style={{ width: "40px", borderRadius:"4px"}} />

          <span>#{record.item}</span>

        </Space>

      ),

    },

    {

      title: "Collection",

      key: "collection",

      render: (text, record) => (

        <Space size="middle">

          <span>{getName(record.collection, record.item)}</span>

        </Space>

      ),

    },

    {

      title: "Transaction Status",

      key: "tags",

      dataIndex: "tags",

      render: (tags) => (

        <>

          {tags((tag, index) => {

            let color = "geekblue";

            let status = "BUY";

            if (tag === false) {

              color = "volcano";

              status = "waiting";

            } else if (tag === true) {

              color = "green";

              status = "confirmed";

            }

            if (tag === walletAddress) {

              status = "SELL";

            }

            return (

              <Tag color={color} key={index}>

                {status.toUpperCase()}

              </Tag>

            );

          })}

        </>

      ),

    },

    {

      title: "Price",

      key: "price",

      dataIndex: "price",

      render: (e) => (

        <Space size="middle">

          <PolygonCurrency/>

          <span>{e}</span>

        </Space>

      ),

    }

  ];

  const data = fetchMarketItems?.map((item, index) => ({

    key: index,

    date: moment(item.updatedAt).format("DD-MM-YYYY HH:mm"),

    collection: item.nftContract,

    item: item.tokenId,

    tags: [item.seller, item.sold],

    price: item.price / ("1e" + 18)

  }));

  return (

    <>

      <div>

        <div style={styles.table}>

          <Table columns={columns} dataSource={data} />

        </div>

      </div>

    </>

  );

}

export default NFTMarketTransactions;

const columns = [

  {

    title: "Date",

    dataIndex: "date",

    key: "date",

  },

  {

    title: "Item",

    key: "item",

  },

  {

    title: "Collection",

    key: "collection",

  },

  {

    title: "Transaction Status",

    key: "tags",

    dataIndex: "tags",

  },

  {

    title: "Price",

    key: "price",

    dataIndex: "price",

  }

];

Do you have a Panel component looks like it comes from there ?

No I don’t have a panel component

There wasn’t one in the final repository I don’t think @qudusayo :slight_smile:

Maybe you can share a link to the final repo. Hope you’ve also refreshed the page to be sure the error persist

@qudusayo Yes I have refreshed the page a few times and the error continues.
Here is the link to the repo.


Cheers

When I get rid of that map I have the same error

Then that map is not causing the warning.

const data = fetchMarketItems?.map((item, index) => ({

This doesn’t use a key, use one here in the outer div (and remove the empty <></>).

So I should add that line of code for data and add a unique key? :slight_smile:

No, you edit this existing map. It’s in that code you posted above. You can just test first with using index.

Ok I will test that now

I’ve tried using index and tag and I’ve tried adding a React.fragment and I’m still getting errors and I tried adding a key outside of the div in the fetchMarketItems.map. Have I done this wrong?

{

      title: "Transaction Status",

      key: "tags",

      dataIndex: "tags",

      render: (tags) => (

        <>

          {tags((tag, index) => {

            let color = "geekblue";

            let status = "BUY";

            if (tag === false) {

              color = "volcano";

              status = "waiting";

            } else if (tag === true) {

              color = "green";

              status = "confirmed";

            }

            if (tag === walletAddress) {

              status = "SELL";

            }

            return (

              <React.Fragment key={tag}>

                <Tag color={color} key={index}>

                {status.toUpperCase()}

                </Tag>

              </React.Fragment>            

            );

          })}

        </>

      ),

    },

    {

      title: "Price",

      key: "price",

      dataIndex: "price",

      render: (e) => (

        <Space size="middle">

          <PolygonCurrency/>

          <span>{e}</span>

        </Space>

      ),

    }

  ];

 

  const data = fetchMarketItems?.map((item, index) => ({

    key: index,

    date: moment(item.updatedAt).format("DD-MM-YYYY HH:mm"),

    collection: item.nftContract,

    item: item.tokenId,

    tags: [item.seller, item.sold],

    price: item.price / ("1e" + 18)

  }));

  return (

    <>

      <div>

        <div style={styles.table}>

          <Table columns={columns} dataSource={data} />

        </div>

        key{tag}

      </div>

    </>

  );

}

You need to find which map where each child in a list should have a unique "key" prop warning is coming from - delete each map that is rendering elements and test. This issue doesn’t happen on my end with the NFT boilerplate.

Or are you getting a different error(s) now?