Apify-Client在React项目中运行报错问题求助
问题原因
- 导出逻辑错误:你的
apify.js中把导出语句注释了,即使解开注释,export default getItems()的写法也是错误的——你导出的是函数执行后的返回值(Promise对象),而非函数本身,导致React组件导入的getItems不是可调用的函数。 - Node专属API不兼容浏览器环境:
apify.js中的require('dotenv').config()配置、__dirname变量都是Node.js运行环境下的专属能力,React代码最终运行在浏览器中,不存在这些API,直接运行会抛出未定义错误。 - 多余的全局执行逻辑:
apify.js末尾的getItems()会导致该模块被导入时就自动执行一次函数,不符合你在useEffect中按需调用的预期。 - 可选:你使用的
apify-client@1.2.4默认是为Node环境构建的,部分依赖可能不兼容浏览器环境。
解决步骤
1. 重写apify.js文件
移除所有Node专属代码,修正导出逻辑:
import { ApifyClient } from 'apify-client'; const client = new ApifyClient({ token: process.env.REACT_APP_API_TOKEN, }); const input = {}; const getItems = async () => { // Run the actor and wait for it to finish const run = await client.actor('petrpatek/covid-19-aggregator').call(input); // Fetch and print actor results from the run's dataset (if any) console.log('Results from dataset'); const { items } = await client.dataset(run.defaultDatasetId).listItems(); items.forEach((item) => { console.dir(item); }); return items; }; // 正确导出函数本身,不要加执行括号 export default getItems;
同时确认你的.env文件放在项目根目录(与package.json同级),变量名格式符合React要求,以REACT_APP_开头:
REACT_APP_API_TOKEN=你的Apify接口令牌
2. (可选)替换为原生fetch调用,避免依赖兼容问题
如果修改后仍报apify-client相关错误,可以直接用浏览器原生fetch调用接口,不需要引入额外依赖,兼容性更好:
const API_TOKEN = process.env.REACT_APP_API_TOKEN; const ACTOR_ID = 'petrpatek/covid-19-aggregator'; const getItems = async () => { // 发起actor运行请求 const runRes = await fetch(`https://api.apify.com/v2/acts/${ACTOR_ID}/runs?token=${API_TOKEN}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}) }); const runData = await runRes.json(); const runId = runData.data.id; // 轮询等待任务运行完成 let runStatus; do { await new Promise(resolve => setTimeout(resolve, 1000)); const statusRes = await fetch(`https://api.apify.com/v2/acts/runs/${runId}?token=${API_TOKEN}`); const statusData = await statusRes.json(); runStatus = statusData.data.status; } while (runStatus === 'RUNNING' || runStatus === 'READY'); // 拉取运行结果 const itemsRes = await fetch(`https://api.apify.com/v2/datasets/${runData.data.defaultDatasetId}/items?token=${API_TOKEN}`); const items = await itemsRes.json(); console.log('Results from dataset', items); return items; }; export default getItems;
3. 组件中适配异步逻辑,存储返回数据
如果需要在页面渲染接口返回的内容,可以用useState存储数据,修改组件代码如下:
import { useEffect, useState } from 'react'; import CountryCard from '../components/countryCard'; import Header from '../components/header'; import getItems from '../APIs/apify'; const AllCountriesPage = () => { const [countryList, setCountryList] = useState([]); useEffect(() => { // 处理异步调用 const fetchData = async () => { const data = await getItems(); setCountryList(data); }; fetchData(); }, []); return ( <div className="allCountriesPage"> <Header /> <CountryCard className="bannerCountry" /> <p className="allCountriesText">All countries</p> <div className="allCountriesContainer"> {/* 遍历渲染国家卡片 */} {countryList.map((country, index) => ( <CountryCard key={index} data={country} /> ))} </div> </div> ); }; export default AllCountriesPage;
注意事项
直接将API令牌放在前端代码中会导致令牌泄露,任何人都可以通过前端代码拿到你的令牌调用Apify接口、消耗你的账户配额,生产环境建议增加后端代理层,前端只请求自己的后端接口,由后端携带令牌请求Apify接口返回数据。
内容的提问来源于stack exchange,提问作者Ayman Jabr
相关产品推荐
相关产品推荐

