1

So I'm having the problem of having duplicate information into an array useState variable. This is my code:


const [tokens, setTokens] = useState([]);

const getTokens = async () => {
    const nftContract = await getContract(true);
    const tokensIds = await nftContract.getTokenIds();
    setTokens([]);

    for (var i = 0; i < tokensIds.length; i++) {
      const id = tokensIds[i].toNumber();
      if (id != 0) {
        const atts = await nftContract.getTokenAttrs(tokensIds[i]);
        const data = { tokenId: id, product: atts[2], quantity: atts[3], unit: atts[4], state: atts[5] };

        setTokens(
          state => [...state, data]
        )
      }
    } 
    setLoading(false);
  };

useEffect(() => {

    const nftContract = new Contract(NFT_CONTRACT_ADDRESS, abi, props.provider);
    var currentAccount;
    props.provider.send("eth_requestAccounts", [])
      .then(function (result) {
        currentAccount = utils.getAddress(result[0]);
      });

    getTokens()
      .then(
        // listen to all events triggered for all minted tokens from this account
        nftContract.on(nftContract.filters.Transaction(currentAccount, null, 0), (_from, _tokenId, _state) => {
          console.log("Listener triggered FARMER - 1");
          getTokens();
        })
      )
    );

    // we remove all the events to avoid they fire multiple timess
    return () => {
      props.provider.removeAllListeners()
    }

}, []);

As you can see, in the useEffect, there is a listener that when an event is triggered, will run the getTokens() function. The problem comes when there are two events that triggers this function, making the tokens useState variable have duplicate values. I've tried to initialize the variable at the beginning of the function with setTokens([]) but it doesn't work... Any solution that you can propose me?

asusrid
  • 63
  • 7

1 Answers1

0

Initialise state as a Map object. Each record in the map should be keyed by token id. That way you guarantee no duplicate entries.

const [tokens, setTokens] = useState(new Map());


const getTokens = async () => {
    const nftContract = await getContract(true);
    const tokensIds = await nftContract.getTokenIds();
    setTokens([]);

    for (var i = 0; i < tokensIds.length; i++) {
      const id = tokensIds[i].toNumber();
      if (id != 0) {
        const atts = await nftContract.getTokenAttrs(tokensIds[i]);
        const data = { tokenId: id, product: atts[2], quantity: atts[3], unit: atts[4], state: atts[5] };
        tokens.set(id, data);
        setTokens(tokens);
      }
    } 
    setLoading(false);
  };

useEffect(async() => {

    const nftContract = new Contract(NFT_CONTRACT_ADDRESS, abi, props.provider);
    var currentAccount;
    props.provider.send("eth_requestAccounts", [])
      .then(function (result) {
        currentAccount = utils.getAddress(result[0]);
      });

    await getTokens();
     
    // listen to all events triggered for all minted tokens from this account
    nftContract.on(nftContract.filters.Transaction(currentAccount, null, 0), async (_from, _tokenId, _state) => {
          console.log("Listener triggered FARMER - 1");
          await getTokens();
        })
      )
    );

    // we remove all the events to avoid they fire multiple timess
    return () => {
      props.provider.removeAllListeners()
    }

}, []);

You can get the entry values with

tokens.values();
Oluwafemi Sule
  • 36,144
  • 1
  • 56
  • 81