如何通过React功能组件的循环回调获取api



我有一个40+的循环调用另一个组件来显示图像。每个图像都有一个ID,有了这个ID,我可以通过另一个API调用获得更多关于图像的信息,如名称和描述。

,DisplayImage我希望它调用另一个回调函数,它将发送API调用该图像的元数据,将其存储在一个变量中,并将其显示为H1标签。

return (
<div>
{array.map(index) => {
// Some Other Code That return a TokenID //
<>
{displayImage(tokenId)}
</>

</div>
})
const displayImage = (tokenId) => {
const imageName = GetURI(tokenId)
return (
<div className="token-container">
<h1>{imageName}</h1>
<img className="artwork" width="250px" src={`https://ipfs-asdf/${tokenId}`} />
</div>
)
}
const GetURI = async (tokenId) => {
const res = await fetch("https://api"+tokenId , {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
}).then(data => {
console.log(data)
return data.json();
})
.then(data => {
return (data.name || [])
})
.catch(err => {
console.log(err);
});
}

数据正在控制台显示,但现在我遇到了一个无限循环的问题,我知道UseEffect可以解决,但我不能完全弄清楚。我设法使用[]属性在控制台上使用UseEffect显示数据,但不知道如何显示数据。任何帮助都会很棒的。谢谢你!

两件事对你的情况有用

  • 组件外声明的函数不重新创建每个渲染

  • useState和useEffect配对限制呼叫仅当tokenId更改时

// Put this function outside the component
// so it does not need a useCallback
// i.e not reconstructed each render of DisplayImage
const GetURI = async (tokenId) => {
...
});
const DisplayImage = (tokenId) => {
const [imageName, setImageName] = useState()
// limit calls to API to when tokenId changes
// and if eslint complains add GetURI to dependency list
// - but GetURI never changes, so no un-needed calls from it
useEffect(() => {
setImageName(GetURI(tokenId))
}, [tokenId, GetURI])   

return (
<div className="token-container">
<h2>{imageName}</h2>
<img className="artwork" width="250px" src={`https://ipfs-asdf/${tokenId}`} />
</div>
)
};

也可以抽象为自定义钩子useImageName()

const GetURI = async (tokenId) => {
...
});
const useImageName = (tokenId) => {
const [imageName, setImageName] = useState()
useEffect(() => {
setImageName(GetURI(tokenId))
}, [tokenId, GetURI])   
return imageName
})
const DisplayImage = (tokenId) => {
const imageName = useImageName(tokenId)
return (
<div className="token-container">
<h2>{imageName}</h2>
<img className="artwork" width="250px" src={`https://ipfs-asdf/${tokenId}`} />
</div>
)
};

BTW in GetURI this

return (data.name || [])

看起来应该是

return data.name || ''

另一种方法可以吗?我将把display image放到它自己的组件中。

const DisplayImage = ({tokenId: {_tokenId}}) => {
const imageName = GetURI(_tokenId)

const GetURI = useCallback(async () => {
await fetch("https://api"+tokenId , {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
}).then(data => {
console.log(data)
return data.json();
})
.then(data => {
return (data.name || [])
})
.catch(err => {
console.log(err);
});
})
});
useEffect(() => {
if (_tokenId) GetURI();
}, [GetURI]);
return (
<div className="token-container">
<h2>{imageName}</h2>
<img className="artwork" width="250px" src={`https://ipfs-asdf/${_tokenId}`} />
</div>
)
};

return (
<div>
{array.map(index) => {
//Some Other Code//
<DisplayImage tokenId={tokenId} />

</div>
})

您应该缓存来自GetURI(tokenId)的响应。当使用相同的tokenId时,不需要两次请求相同的URI。一个简单的方法是使用react-query:

在App.js中设置:

// App.js
import { QueryClient, QueryClientProvider } from 'react-query'
const queryClient = new QueryClient()
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<Example />
</QueryClientProvider>
)
}

然后在DisplayImage组件中使用(而不是内联函数):

// DisplayImage.js
import { useQuery } from 'react-query'
export function DisplayImage(tokenId) {
const { isLoading, error, data: imageName } = useQuery(['images', tokenId], GetURI(tokenId))
return (
<div className="token-container">
<h1>{isLoading ? 'loading...' : imageName}</h1>
<img className="artwork" width="250px" src={`https://ipfs-asdf/${tokenId}`} />
</div>
)
}

我在大家的帮助下找到了最好的方法,所以谢谢!

我将GetURI函数放在show image组件中,并且每次有一个新的令牌ID时都有一个useEffect方法调用GetURI,然后我将状态变量设置为返回的值。

无循环,无错误👌


const DisplayImage = (data) => {
const [nftMetadata, setNftMetadata] = useState();
const GetURI = async (data) => {
const nftURI = await data.drizzle.contracts.Contract.methods.tokenURI(data.tokenId).call()
await fetch(nftURI , {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
"Access-Control-Allow-Origin": "*"
},
})
.then(data => {
return data.json();
})
.then(data => {
return setNftMetadata(data || []);
})
.catch(err => {
return console.log(err);
});
});
useEffect(() => {
GetURI(data);
}, [data.tokenId])   

return (
<div className="token-container">
<h2>{nftMetadata.name}</h2>
<img className="artwork" width="450px" src={`https://ipfs:/whatever/${nftMetadata.image}`} />
</div>
);
};
return (
<div>
{array.map(index) => {
// Some Other Code That returns a TokenID //
<>
<DisplayImage address={drizzle.contractList[0].address} tokenId={tokenId} drizzle={drizzle} drizzleState={drizzleState}/>
</>

</div>
})

相关内容

  • 没有找到相关文章

最新更新