组件中超出了最大递归更新

发布于 2025-02-04 15:53:09 字数 9172 浏览 1 评论 0原文

我正在尝试构建这个非常简单的提取功能:

const fetchUnstakedNFTs = async (): Promise<void> => {
    if (wallet.value && wallet.value.connected && publicKey.value) {
      const tokenAccountsFromWallet =
        await connection.getParsedTokenAccountsByOwner(publicKey.value, {
          programId: new PublicKey(
            "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
          ),
        });
      // Define and/or reset tokenAccounts Array
      const tokenAccounts: {
        pubkey: PublicKey;
        account: AccountInfo<ParsedAccountData>;
      }[] = [];

      for (const account of tokenAccountsFromWallet.value) {
        const metadata = await getMetadata(
          account.account.data.parsed.info.mint
        );
        // Add NFTs with matching creator and amount === 1 to tokenAccounts
        if (
          metadata &&
          metadata.creators &&
          metadata.creators[0].address === nftCreator.toString() &&
          account.account.data.parsed.info.tokenAmount.amount === "1"
        ) {
          tokenAccounts.push(account);
        }
      }

      // Add tokenAccounts to unstakedNFTs if they are not already in there
      for (const tokenAccount of tokenAccounts) {
        const metadata = await getMetadata(
          tokenAccount.account.data.parsed.info.mint
        );
        if (
          metadata &&
          metadata.creators &&
          metadata.creators[0].address == nftCreator.toString()
        ) {
          const { data } = await axios.get(metadata.uri);
          const newNFT = {
            name: data.name,
            symbol: metadata.symbol,
            image: data.image,
            mintId: tokenAccount.account.data.parsed.info.mint,
            tokenAccount: tokenAccount.pubkey.toString(),
            isStaking: false,
            isSelected: false,
          };
          // check if unstakedNFTs contains the NFT already
          if (
            !unstakedNFTs.value.find(
              (nft) =>
                nft.mintId === newNFT.mintId &&
                nft.tokenAccount === newNFT.tokenAccount
            )
          ) {
            // if it doesnt, add it to unstakedNFTs
            console.log("Adding NFT to unstakedNFTs", newNFT);
            unstakedNFTs.value.push(newNFT);
          }
        }
      }
    }
  };

但是我会收到此警告:

组件中超过的最大递归更新。这意味着您具有反应性效应,它正在突变自己的依赖性,从而递归触发自身。可能的来源包括组件模板,渲染功能,更新的钩子或观察器源功能。

instrumentations.<computed> @ reactivity.esm-bundler.js?89dc:439
fetchUnstakedNFTs @ createWalletStore.ts?a4c6:344

我不知道该怎么做。 查看这部分警告: fetchunstakednfts @ createwalletstore.ts?a4c6:344

您可以看到它指向我函数的这一行(行344):

unstakedNFTs.value.push(newNFT);

此处nftpane.vue component:component:component:component:component:

<template>
  <div class="m-4 p-2 h-full w-full flex flex-col bg-surface bg-opacity-30 frosted-glass rounded-lg">
    <div class="flex flex-wrap items-center justify-start" v-if="wallet.fetching && nfts.length == 0">
      <div v-for="item in shimmerArray" :key="item" class="h-52 w-52 relative m-2 bg-white bg-opacity-5 rounded-lg">
      </div>
    </div>
    <div v-else class="flex flex-wrap items-center justify-start">
      <button :disabled="nft.isStaking" @click="selectNFT(nft)" v-for="nft in nfts" :key="nft.image"
        class="h-52 w-52 relative m-2">
        <img
          :class="nft.isStaking ? 'transition-all duration-500 rounded-lg' : 'transition-all duration-500 rounded-lg'"
          :src="nft.image" />
        <div
          class="px-3 py-0.5 absolute right-2 top-2 text-lg text-center rounded-md frosted-glass bg-surface bg-opacity-20">
          #{{ getNFTNumber(nft.name) }}
        </div>
      </button>
    </div>
    <div class="flex flex-row justify-start items-center space-x-5">
      <button class="glow-button" @click="onStake()">
        <span>
          {{ stakeType == StakeType.unstaked ? 'Stake' : 'Unstake' }}
        </span>
      </button>
      <button class="glow-button" @click="onStakeAll()">
        <span>
          {{ stakeType == StakeType.unstaked ? 'Stake All' : 'Unstake All' }}
        </span>
      </button>
      <button v-if="stakeType == StakeType.staked" @click="claimAllRewards()" class="glow-button">
        <span>
          Claim Rewards
        </span>
      </button>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { defineProps, ref } from 'vue';
import { PublicKey } from '@solana/web3.js';
import { NFT, StakeType } from '@/types/types';
import { useWallet, useAnchorWallet } from '@/composables/useWallet/index';
import { claimNFTRewards } from '@/plugins/utils/claim_rewards/src/claim_rewards'
import { connection, stakePoolID } from '@/constants';
import { createToast } from '@/plugins/toast/createToast';
import { unstakeNFT } from '@/plugins/utils/unstake/src/unstake';
import { stakeNFT } from '@/plugins/utils/stake/src/stake';
import { getNFTNumber } from '@/composables/utils';
// import FadeLoader from 'vue-spinner/src/FadeLoader.vue';

const props = defineProps<{
  nfts: NFT[],
  stakeType: StakeType,
}>();

const wallet = useWallet();
const anchorWallet = useAnchorWallet();
const shimmerArray = Array(9)

const selectNFT = async (nft: NFT) => {
  nft.isSelected = !nft.isSelected;
}

const claimAllRewards = async () => {
  if (anchorWallet.value) {
    claimNFTRewards(
      connection,
      anchorWallet.value,
      {
        stakePoolId: stakePoolID,
        nfts: wallet.stakedNFTs.value,
        callback: () => {
          createToast('Successfully claimed rewards', {
            type: 'success',
          });
        }
      }
    );
  }
};

const onStakeAll = async () => {
  if (props.stakeType == StakeType.staked) {
    wallet.stakedNFTs.value = wallet.stakedNFTs.value.map(stakedNFT => {
      stakedNFT.isSelected = true;
      return stakedNFT;
    });
  }
  else {
    wallet.unstakedNFTs.value = wallet.unstakedNFTs.value.map(unstakedNFT => {
      unstakedNFT.isSelected = true;
      return unstakedNFT;
    });
  }
  await onStake();
}

const onStake = async () => {
  const alertIndex = ref(0);
  if (anchorWallet.value) {
    if (StakeType.staked == props.stakeType) {
      const nfts = wallet.stakedNFTs.value.filter(stakedNFT => stakedNFT.isSelected);
      nfts.forEach((nft) => nft.isStaking = true)
      wallet.staking.value = true;
      try {
        await unstakeNFT(connection, anchorWallet.value, {
          stakePoolId: stakePoolID,
          originalMintId: nfts.map(nft => new PublicKey(nft.mintId)),
          callback: () => {
            alertIndex.value++;
            if (nfts.length === 1) {
              createToast("Successfully Unstaked NFT", {
                type: "success",
                transition: "zoom",
                timeout: 5000,
                showIcon: true,
              });
            }
            else {
              createToast(`${alertIndex.value}/${nfts.length} Successfully Unstaked NFT`, {
                type: "success",
                transition: "zoom",
                timeout: 5000,
                showIcon: true,
              });
            }
            if (alertIndex.value == nfts.length) {
              alertIndex.value = 0;
              wallet.staking.value = false;
            }
            wallet.fetchNFTs();
          },
        });
      }
      catch (e) {
        wallet.staking.value = false;
        nfts.forEach((nft) => nft.isStaking = false)
      }
    } else {
      const nfts = wallet.unstakedNFTs.value.filter(stakedNFT => stakedNFT.isSelected);
      nfts.forEach((nft) => nft.isStaking = true)
      wallet.staking.value = true;
      try {
        await stakeNFT(connection, anchorWallet.value, {
          stakePoolId: stakePoolID,
          nfts: nfts,
          callback: () => {
            alertIndex.value++;
            if (nfts.length === 1) {
              createToast("Successfully Staked NFT", {
                type: "success",
                transition: "zoom",
                timeout: 5000,
                showIcon: true,
              });
            }
            else {
              createToast(`${alertIndex.value}/${nfts.length} Successfully Staked NFT`, {
                type: "success",
                transition: "zoom",
                timeout: 5000,
                showIcon: true,
              });
            }
            if (alertIndex.value == nfts.length) {
              alertIndex.value = 0;
              wallet.staking.value = false;
            }
            wallet.fetchNFTs();
          }
        })
      }
      catch (e) {
        wallet.staking.value = false;
        nfts.forEach((nft) => nft.isStaking = false)
      }
    }
    await wallet.fetchNFTs();
  }
}
</script>

I am trying to build this pretty simple fetching function:

const fetchUnstakedNFTs = async (): Promise<void> => {
    if (wallet.value && wallet.value.connected && publicKey.value) {
      const tokenAccountsFromWallet =
        await connection.getParsedTokenAccountsByOwner(publicKey.value, {
          programId: new PublicKey(
            "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
          ),
        });
      // Define and/or reset tokenAccounts Array
      const tokenAccounts: {
        pubkey: PublicKey;
        account: AccountInfo<ParsedAccountData>;
      }[] = [];

      for (const account of tokenAccountsFromWallet.value) {
        const metadata = await getMetadata(
          account.account.data.parsed.info.mint
        );
        // Add NFTs with matching creator and amount === 1 to tokenAccounts
        if (
          metadata &&
          metadata.creators &&
          metadata.creators[0].address === nftCreator.toString() &&
          account.account.data.parsed.info.tokenAmount.amount === "1"
        ) {
          tokenAccounts.push(account);
        }
      }

      // Add tokenAccounts to unstakedNFTs if they are not already in there
      for (const tokenAccount of tokenAccounts) {
        const metadata = await getMetadata(
          tokenAccount.account.data.parsed.info.mint
        );
        if (
          metadata &&
          metadata.creators &&
          metadata.creators[0].address == nftCreator.toString()
        ) {
          const { data } = await axios.get(metadata.uri);
          const newNFT = {
            name: data.name,
            symbol: metadata.symbol,
            image: data.image,
            mintId: tokenAccount.account.data.parsed.info.mint,
            tokenAccount: tokenAccount.pubkey.toString(),
            isStaking: false,
            isSelected: false,
          };
          // check if unstakedNFTs contains the NFT already
          if (
            !unstakedNFTs.value.find(
              (nft) =>
                nft.mintId === newNFT.mintId &&
                nft.tokenAccount === newNFT.tokenAccount
            )
          ) {
            // if it doesnt, add it to unstakedNFTs
            console.log("Adding NFT to unstakedNFTs", newNFT);
            unstakedNFTs.value.push(newNFT);
          }
        }
      }
    }
  };

But I am getting this warning:

Maximum recursive updates exceeded in component . This means you have a reactive effect that is mutating its own dependencies and thus recursively triggering itself. Possible sources include component template, render function, updated hook or watcher source function.

instrumentations.<computed> @ reactivity.esm-bundler.js?89dc:439
fetchUnstakedNFTs @ createWalletStore.ts?a4c6:344

I have no Idea what to try anymore.
Looking at this part of the warning:
fetchUnstakedNFTs @ createWalletStore.ts?a4c6:344

You can see that it points to this line of my function (line 344):

unstakedNFTs.value.push(newNFT);

Here the NFTPane.vue Component:

<template>
  <div class="m-4 p-2 h-full w-full flex flex-col bg-surface bg-opacity-30 frosted-glass rounded-lg">
    <div class="flex flex-wrap items-center justify-start" v-if="wallet.fetching && nfts.length == 0">
      <div v-for="item in shimmerArray" :key="item" class="h-52 w-52 relative m-2 bg-white bg-opacity-5 rounded-lg">
      </div>
    </div>
    <div v-else class="flex flex-wrap items-center justify-start">
      <button :disabled="nft.isStaking" @click="selectNFT(nft)" v-for="nft in nfts" :key="nft.image"
        class="h-52 w-52 relative m-2">
        <img
          :class="nft.isStaking ? 'transition-all duration-500 rounded-lg' : 'transition-all duration-500 rounded-lg'"
          :src="nft.image" />
        <div
          class="px-3 py-0.5 absolute right-2 top-2 text-lg text-center rounded-md frosted-glass bg-surface bg-opacity-20">
          #{{ getNFTNumber(nft.name) }}
        </div>
      </button>
    </div>
    <div class="flex flex-row justify-start items-center space-x-5">
      <button class="glow-button" @click="onStake()">
        <span>
          {{ stakeType == StakeType.unstaked ? 'Stake' : 'Unstake' }}
        </span>
      </button>
      <button class="glow-button" @click="onStakeAll()">
        <span>
          {{ stakeType == StakeType.unstaked ? 'Stake All' : 'Unstake All' }}
        </span>
      </button>
      <button v-if="stakeType == StakeType.staked" @click="claimAllRewards()" class="glow-button">
        <span>
          Claim Rewards
        </span>
      </button>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { defineProps, ref } from 'vue';
import { PublicKey } from '@solana/web3.js';
import { NFT, StakeType } from '@/types/types';
import { useWallet, useAnchorWallet } from '@/composables/useWallet/index';
import { claimNFTRewards } from '@/plugins/utils/claim_rewards/src/claim_rewards'
import { connection, stakePoolID } from '@/constants';
import { createToast } from '@/plugins/toast/createToast';
import { unstakeNFT } from '@/plugins/utils/unstake/src/unstake';
import { stakeNFT } from '@/plugins/utils/stake/src/stake';
import { getNFTNumber } from '@/composables/utils';
// import FadeLoader from 'vue-spinner/src/FadeLoader.vue';

const props = defineProps<{
  nfts: NFT[],
  stakeType: StakeType,
}>();

const wallet = useWallet();
const anchorWallet = useAnchorWallet();
const shimmerArray = Array(9)

const selectNFT = async (nft: NFT) => {
  nft.isSelected = !nft.isSelected;
}

const claimAllRewards = async () => {
  if (anchorWallet.value) {
    claimNFTRewards(
      connection,
      anchorWallet.value,
      {
        stakePoolId: stakePoolID,
        nfts: wallet.stakedNFTs.value,
        callback: () => {
          createToast('Successfully claimed rewards', {
            type: 'success',
          });
        }
      }
    );
  }
};

const onStakeAll = async () => {
  if (props.stakeType == StakeType.staked) {
    wallet.stakedNFTs.value = wallet.stakedNFTs.value.map(stakedNFT => {
      stakedNFT.isSelected = true;
      return stakedNFT;
    });
  }
  else {
    wallet.unstakedNFTs.value = wallet.unstakedNFTs.value.map(unstakedNFT => {
      unstakedNFT.isSelected = true;
      return unstakedNFT;
    });
  }
  await onStake();
}

const onStake = async () => {
  const alertIndex = ref(0);
  if (anchorWallet.value) {
    if (StakeType.staked == props.stakeType) {
      const nfts = wallet.stakedNFTs.value.filter(stakedNFT => stakedNFT.isSelected);
      nfts.forEach((nft) => nft.isStaking = true)
      wallet.staking.value = true;
      try {
        await unstakeNFT(connection, anchorWallet.value, {
          stakePoolId: stakePoolID,
          originalMintId: nfts.map(nft => new PublicKey(nft.mintId)),
          callback: () => {
            alertIndex.value++;
            if (nfts.length === 1) {
              createToast("Successfully Unstaked NFT", {
                type: "success",
                transition: "zoom",
                timeout: 5000,
                showIcon: true,
              });
            }
            else {
              createToast(`${alertIndex.value}/${nfts.length} Successfully Unstaked NFT`, {
                type: "success",
                transition: "zoom",
                timeout: 5000,
                showIcon: true,
              });
            }
            if (alertIndex.value == nfts.length) {
              alertIndex.value = 0;
              wallet.staking.value = false;
            }
            wallet.fetchNFTs();
          },
        });
      }
      catch (e) {
        wallet.staking.value = false;
        nfts.forEach((nft) => nft.isStaking = false)
      }
    } else {
      const nfts = wallet.unstakedNFTs.value.filter(stakedNFT => stakedNFT.isSelected);
      nfts.forEach((nft) => nft.isStaking = true)
      wallet.staking.value = true;
      try {
        await stakeNFT(connection, anchorWallet.value, {
          stakePoolId: stakePoolID,
          nfts: nfts,
          callback: () => {
            alertIndex.value++;
            if (nfts.length === 1) {
              createToast("Successfully Staked NFT", {
                type: "success",
                transition: "zoom",
                timeout: 5000,
                showIcon: true,
              });
            }
            else {
              createToast(`${alertIndex.value}/${nfts.length} Successfully Staked NFT`, {
                type: "success",
                transition: "zoom",
                timeout: 5000,
                showIcon: true,
              });
            }
            if (alertIndex.value == nfts.length) {
              alertIndex.value = 0;
              wallet.staking.value = false;
            }
            wallet.fetchNFTs();
          }
        })
      }
      catch (e) {
        wallet.staking.value = false;
        nfts.forEach((nft) => nft.isStaking = false)
      }
    }
    await wallet.fetchNFTs();
  }
}
</script>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

时常饿 2025-02-11 15:53:09

几个小时后尝试,我发现我只需要删除
getnftnumber(nft.name)函数从我的&lt; nftpane&gt;组件

After hours and hours of trying I found out that I just had to remove the
getNFTNumber(nft.name) function from my <NFTPane> Component

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文