如何使用 React 功能组件通过循环回调获取 api
Posted
技术标签:
【中文标题】如何使用 React 功能组件通过循环回调获取 api【英文标题】:How to fetch api via looped callbacks with React functional components 【发布时间】:2021-10-14 09:49:22 【问题描述】:所以我有一个 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" 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 在控制台上显示数据,但不知道如何显示数据。任何帮助都会很棒。谢谢!
【问题讨论】:
尝试用useCallback
包装你的GetURI函数
您可以为您的用例找到这个article interesting。它解释了如何将反应式编程与 React 功能组件一起使用。
@Picci 我没有发现这有帮助。他似乎在努力磨练而不是出去。我也有这个无限循环问题。我的前端看起来不错,但很快我什至无法检查页面。有人可以公然解决这种严重的循环吗?
【参考方案1】:
在大家的帮助下,我找到了最好的方法,所以谢谢!
我将 GetURI 函数放在显示图像组件中,并且每次有新的令牌 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" 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>
)
【讨论】:
【参考方案2】:您可能应该缓存来自 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" src=`https://ipfs-asdf/$tokenId` />
</div>
)
【讨论】:
【参考方案3】:对你的情况有用的两件事
在组件外部声明的函数不会重新创建每次渲染
useState 和 useEffect 配对将调用限制为仅在 tokenId 更改时才调用 API
// 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" 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" src=`https://ipfs-asdf/$tokenId` />
</div>
)
;
顺便说一句,在 GetURI 中
return (data.name || [])
看起来应该是
return data.name || ''
【讨论】:
【参考方案4】:不同的方法可以吗?我会将显示图像放入它自己的组件中。
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" src=`https://ipfs-asdf/$_tokenId` />
</div>
)
;
然后
return (
<div>
array.map(index) =>
//Some Other Code//
<DisplayImage tokenId=tokenId />
</div>
)
【讨论】:
不会 useEffect 只在挂载时调用该函数吗?我打算多次调用这个函数。我有 75 个不同的令牌 ID 将调用此 API。谢谢。 我用不同的方法编辑了答案。希望有帮助 不幸的是没有工作。我收到一个错误 - 在初始化之前无法访问“GetURI” - 是否允许这样使用挂钩?以上是关于如何使用 React 功能组件通过循环回调获取 api的主要内容,如果未能解决你的问题,请参考以下文章