组件中超出了最大递归更新
我正在尝试构建这个非常简单的提取功能:
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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
几个小时后尝试,我发现我只需要删除
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