NextJS+Solidity项目部署Fleek后axios.get失效求助
问题分析与解决方案
核心问题定位
你的Cards组件存在两个关键问题:
- 直接在组件渲染流程中调用异步函数
updateUI,每次组件状态更新(如setImageHash/setName)都会重新执行组件代码,触发updateUI形成无限重渲染循环。本地开发环境因缓存或宽松规则未暴露问题,但Fleek生产环境的优化会放大该问题,导致请求被浏览器或边缘节点限制。 - 未规范处理异步请求的生命周期,违反React渲染逻辑。
修复步骤
1. 规范异步调用逻辑(使用useEffect)
将updateUI放入useEffect钩子,仅在ipfs参数变化时执行,避免无限调用:
import { useState, useEffect } from "react" import axios from 'axios' export default function Cards({ ipfs, tokenId }) { function handleClick() { localStorage.setItem("Index Clicked", tokenId); document.getElementById("hideNavbar").style.display = 'flex'; } const [imageHash, setImageHash] = useState(ipfs); const [name,setName] = useState(null); useEffect(() => { async function updateUI(){ console.log(ipfs); try { const response = await axios.get(`https://ipfs.io/ipfs/${ipfs}`); setImageHash(response.data.imageHash); setName(response.data.name); } catch (error) { console.error('IPFS请求失败:', error); } } if(ipfs){ updateUI(); } }, [ipfs]); // 仅当ipfs变化时执行 let extension = "" if(name!=null){ extension = name.slice(name.indexOf('.') + 1,); } return ( <div className="card select" onClick={handleClick}> <div className="top-left"></div> <div className="extension">{extension}</div> <div className="name">{name}</div> {imageHash ? <div className="ipfs">IPFS: {imageHash.slice(0, 4)}...{imageHash.slice(40,)}</div> : <div>Hash unavailable..</div>} </div> ) }
2. 优化Fleek部署配置
- 添加CORS配置到
next.config.js,避免跨域限制:
module.exports = { async headers() { return [ { source: '/api/:path*', headers: [ { key: 'Access-Control-Allow-Credentials', value: 'true' }, { key: 'Access-Control-Allow-Origin', value: '*' }, { key: 'Access-Control-Allow-Methods', value: 'GET,OPTIONS,PATCH,DELETE,POST,PUT' }, { key: 'Access-Control-Allow-Headers', value: 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version' }, ], }, ]; }, };
- 替换IPFS网关:若
https://ipfs.io访问不稳定,可改用https://cloudflare-ipfs.com或https://gateway.pinata.cloud。
axios替代方案
1. 原生Fetch API(无额外依赖)
直接使用浏览器原生API实现请求:
useEffect(() => { async function updateUI(){ if(!ipfs) return; try { const response = await fetch(`https://ipfs.io/ipfs/${ipfs}`); const data = await response.json(); setImageHash(data.imageHash); setName(data.name); } catch (error) { console.error('请求失败:', error); } } updateUI(); }, [ipfs]);
2. SWR(NextJS推荐方案)
自带缓存、重新验证功能,适合NextJS项目:
首先安装依赖:
npm install swr
修改组件代码:
import { useState } from "react" import useSWR from 'swr' const fetcher = async (url) => { const res = await fetch(url); return res.json(); }; export default function Cards({ ipfs, tokenId }) { function handleClick() { localStorage.setItem("Index Clicked", tokenId); document.getElementById("hideNavbar").style.display = 'flex'; } const [imageHash, setImageHash] = useState(ipfs); const { data } = useSWR(ipfs ? `https://ipfs.io/ipfs/${ipfs}` : null, fetcher); const name = data?.name || null; useEffect(() => { if(data?.imageHash){ setImageHash(data.imageHash); } }, [data]); let extension = "" if(name!=null){ extension = name.slice(name.indexOf('.') + 1,); } return ( <div className="card select" onClick={handleClick}> <div className="top-left"></div> <div className="extension">{extension}</div> <div className="name">{name}</div> {imageHash ? <div className="ipfs">IPFS: {imageHash.slice(0, 4)}...{imageHash.slice(40,)}</div> : <div>Hash unavailable..</div>} </div> ) }
3. TanStack Query(React Query)
功能强大的数据管理库,支持缓存、重试、背景更新:
首先安装依赖:
npm install @tanstack/react-query
在_app.js中配置全局Provider:
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; const queryClient = new QueryClient(); function MyApp({ Component, pageProps }) { return ( <QueryClientProvider client={queryClient}> <Component {...pageProps} /> </QueryClientProvider> ); } export default MyApp;
修改Cards组件:
import { useState, useEffect } from "react" import { useQuery } from '@tanstack/react-query'; export default function Cards({ ipfs, tokenId }) { function handleClick() { localStorage.setItem("Index Clicked", tokenId); document.getElementById("hideNavbar").style.display = 'flex'; } const [imageHash, setImageHash] = useState(ipfs); const { data } = useQuery({ queryKey: ['ipfsData', ipfs], queryFn: async () => { const res = await fetch(`https://ipfs.io/ipfs/${ipfs}`); return res.json(); }, enabled: !!ipfs, // 仅当ipfs存在时执行请求 }); const name = data?.name || null; useEffect(() => { if(data?.imageHash){ setImageHash(data.imageHash); } }, [data]); let extension = "" if(name!=null){ extension = name.slice(name.indexOf('.') + 1,); } return ( <div className="card select" onClick={handleClick}> <div className="top-left"></div> <div className="extension">{extension}</div> <div className="name">{name}</div> {imageHash ? <div className="ipfs">IPFS: {imageHash.slice(0, 4)}...{imageHash.slice(40,)}</div> : <div>Hash unavailable..</div>} </div> ) }
内容的提问来源于stack exchange,提问作者Ashutosh Jha
相关产品推荐
相关产品推荐

