如何在Remix.run(TSX)中并行调用API?支持构建/客户端异步渲染
在Remix.run中实现Strapi API并行调用与多场景渲染
一、API并行调用实现
在Remix的路由loader函数中,用Promise.all包裹多个Strapi API请求,就能实现并行调用——loader会等待所有请求完成后再返回数据,避免客户端串行请求的性能损耗。
代码示例
// app/routes/your-page.tsx import { json, LoaderFunctionArgs } from "@remix-run/node"; import { useLoaderData } from "@remix-run/react"; // 封装Strapi请求工具函数 async function fetchStrapi(endpoint: string) { const res = await fetch(`https://你的Strapi域名/api/${endpoint}`, { headers: { "Authorization": `Bearer ${process.env.STRAPI_API_TOKEN}` } }); if (!res.ok) throw new Error(`请求失败: ${endpoint}`); return res.json(); } // 路由loader:并行调用多个API export async function loader({}: LoaderFunctionArgs) { const [articles, categories, banners] = await Promise.all([ fetchStrapi("articles?populate=*"), fetchStrapi("categories"), fetchStrapi("banners?populate=image") ]); return json({ articles, categories, banners }); } export default function YourPage() { const { articles, categories, banners } = useLoaderData<typeof loader>(); return ( <div className="page-container"> <h2>文章列表</h2> {articles.data.map(item => ( <div key={item.id}>{item.attributes.title}</div> ))} {/* 其他组件渲染逻辑 */} </div> ); }
二、构建时预渲染(静态生成)
如果内容更新频率低,可以在构建阶段就拉取Strapi数据生成静态页面,提升首屏加载速度。
配置步骤
- 修改
remix.config.js启用静态输出:
/** @type {import('@remix-run/dev').AppConfig} */ export default { future: { unstable_singleFetch: true, }, output: "static", };
- 保持路由
loader的请求逻辑不变,执行remix build时,Remix会自动在构建阶段调用loader获取数据,生成静态HTML文件。
图片处理
Strapi返回的图片是相对路径,需要拼接完整URL后渲染:
// 工具函数:转换Strapi图片地址 function getStrapiImageUrl(image: any) { return `https://你的Strapi域名${image.data.attributes.url}`; } // 渲染示例 <img src={getStrapiImageUrl(banners.data[0].attributes.image)} alt="首页横幅" />
三、客户端异步调用
对于无需首屏加载的数据(如滚动加载、用户触发的内容),可以用useEffect或Remix的useFetcher实现客户端异步请求。
方法1:useEffect + fetch
import { useEffect, useState } from "react"; function HotArticles() { const [articles, setArticles] = useState<any[]>([]); const [loading, setLoading] = useState(true); useEffect(() => { async function fetchHotArticles() { try { const res = await fetch(`https://你的Strapi域名/api/articles?sort=view_count:desc&limit=3`, { headers: { "Authorization": `Bearer ${process.env.STRAPI_API_TOKEN}` } }); const data = await res.json(); setArticles(data.data); } catch (err) { console.error("获取热门文章失败", err); } finally { setLoading(false); } } fetchHotArticles(); }, []); if (loading) return <div>加载中...</div>; return ( <div className="hot-articles"> <h3>热门文章</h3> {articles.map(item => ( <div key={item.id}>{item.attributes.title}</div> ))} </div> ); }
方法2:使用Remix useFetcher
useFetcher是Remix官方推荐的客户端请求工具,自带加载状态管理:
import { useFetcher } from "@remix-run/react"; function HotArticles() { const fetcher = useFetcher(); useEffect(() => { fetcher.load("/api/hot-articles"); }, [fetcher]); if (fetcher.state === "loading") return <div>加载中...</div>; if (!fetcher.data) return null; const articles = fetcher.data.articles; return ( <div className="hot-articles"> <h3>热门文章</h3> {articles.map(item => ( <div key={item.id}>{item.attributes.title}</div> ))} </div> ); } // 新建API路由:app/routes/api/hot-articles.tsx import { json } from "@remix-run/node"; import { fetchStrapi } from "../../utils/strapi"; export async function loader() { const data = await fetchStrapi("articles?sort=view_count:desc&limit=3"); return json({ articles: data.data }); }
四、注意事项
- Strapi的API Token要存在根目录的
.env文件中,不要硬编码在代码里,Remix会自动读取环境变量。 - 所有API请求都要加错误处理:服务端
loader中抛出的错误,Remix会自动渲染错误页面;客户端请求要加try/catch捕获异常。 - 静态内容用构建时预渲染,动态内容用客户端异步调用,平衡加载速度和内容新鲜度。
内容的提问来源于stack exchange,提问作者BigChungus
相关产品推荐
相关产品推荐

