如何在JS模块中导出依赖异步请求的非异步常量供React项目使用
解决方案
首先明确:客户端侧异步请求不可能直接返回完全同步的非异步常量,但可以通过以下两种方案实现最小程度的代码改动,原有使用TOKEN_MINTS的组件几乎不需要重写。
方案1:顶层预加载 + React Context 共享(推荐,改动最小)
这个方案只需要修改常量文件和应用入口文件,原有业务组件基本无需调整。
步骤1:修改常量TS文件
保留原有映射逻辑,新增初始化函数和Context导出:
import { createContext, useContext } from 'react'; import { PublicKey } from '@solana/web3.js'; // 替换为你实际的PublicKey导入路径 // 复用原有类型定义 export type TokenMintType = Array<{ address: PublicKey; name: string; }>; // 定义兜底默认值,防止加载过程中调用报错 let TOKEN_MINTS: TokenMintType = []; // 异步初始化加载函数 export async function initTokenMints() { try { const res = await fetch('你的JSON接口地址', { headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' } }); if (!res.ok) throw new Error('接口请求失败'); const rawMints = await res.json(); // 完全复用原有静态JSON的映射逻辑 TOKEN_MINTS = rawMints.map((mint) => { return { address: new PublicKey(mint.address), name: mint.name, }; }); return TOKEN_MINTS; } catch (e) { console.error('TOKEN_MINTS加载失败', e); return TOKEN_MINTS; } } // 导出Context供组件实时获取最新值 const TokenMintsContext = createContext<TokenMintType>(TOKEN_MINTS); export const TokenMintsProvider = TokenMintsContext.Provider; export const useTokenMints = () => useContext(TokenMintsContext); // 保留原有导出方式兼容老代码,加载完成前返回兜底值 export { TOKEN_MINTS };
步骤2:修改应用入口文件
在渲染根组件前先执行数据初始化,完成后再挂载应用:
import { initTokenMints, TokenMintsProvider, TOKEN_MINTS } from './你的常量文件路径'; import App from './App'; // 等待数据加载完成再渲染应用 initTokenMints().then(() => { ReactDOM.createRoot(document.getElementById('root')!).render( <TokenMintsProvider value={TOKEN_MINTS}> <App /> </TokenMintsProvider> ) });
步骤3:组件侧适配(可选,仅需修改一行导入)
如果需要保证组件拿到的永远是加载完成的最新值,只需要把原有导入逻辑替换为hooks调用即可,组件内部使用逻辑完全不用改:
// 原有导入写法 // import { TOKEN_MINTS } from 'xx' // 替换为 import { useTokenMints } from 'xx' const YourComponent = () => { const TOKEN_MINTS = useTokenMints(); // 后续原有逻辑完全复用 }
方案2:ES模块顶级await(无需修改组件代码,需适配构建配置)
如果你的项目使用ES模块规范,且构建工具(Webpack5+/Vite/Rollup)和目标浏览器支持顶级await特性,可以直接修改常量文件如下,原有组件的导入和使用逻辑完全不用调整:
import { PublicKey } from '@solana/web3.js'; // 顶级await会等待请求完成后再导出模块内容 const rawMints = await fetch('你的JSON接口地址', { headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' } }).then(res => { if (res.ok) return res.json(); // 请求失败返回兜底空数组 return []; }); // 原有导出逻辑完全复用 export const TOKEN_MINTS: Array<{ address: PublicKey; name: string; }> = rawMints.map((mint) => { return { address: new PublicKey(mint.address), name: mint.name, }; });
注意:该方案会阻塞模块加载直到请求完成,请求失败会导致模块加载异常,需要提前做好降级处理,同时确认你的构建配置开启了顶级await支持。
内容的提问来源于stack exchange,提问作者dahifi
相关产品推荐
相关产品推荐

