React Suspense数据获取:如何将组件Props传入Promise?
解决React Suspense结合props传参的异步数据获取问题
原示例的问题在于用了全局的status和result变量,且请求逻辑在组件外部初始化,无法响应组件props中userId的变化。要解决这个问题,核心是为每个不同的userId维护独立的请求状态与缓存,避免全局变量的冲突。
修改方案
- 用缓存映射替代全局变量:创建一个对象存储每个
userId对应的请求状态、结果和Promise,确保不同用户的数据互不干扰。 - 让
fetchPosts根据传入的userId处理缓存逻辑:如果缓存中已有该用户的请求记录,直接复用;没有则发起新请求并更新缓存。 - 在组件内部调用
fetchPosts:每次组件渲染时,基于当前props的userId获取对应数据。
修改后的完整代码
import React from "react"; import Post from "./Post"; // 为每个userId维护独立的请求缓存,避免全局状态冲突 const postsCache = new Map(); // Posts组件:接收userId作为props const Posts = ({ userId }) => { // 根据当前props的userId获取数据 const posts = fetchPosts(userId)(); return ( <div style={{ display: "flex", flexWrap: "wrap", gap: "10px" }}> {posts.map((post, idx) => ( <Post post={post} key={idx} /> ))} </div> ); }; // 带缓存逻辑的异步数据获取函数 function fetchPosts(userId) { // 检查缓存中是否已有该userId的请求记录 if (postsCache.has(userId)) { const cacheEntry = postsCache.get(userId); return () => { if (cacheEntry.status === "pending") { throw cacheEntry.fetchPromise; // 触发Suspense } else if (cacheEntry.status === "rejected") { throw cacheEntry.result; // 抛出错误 } else { return cacheEntry.result; // 返回已获取的数据 } }; } // 没有缓存时,发起新请求 const cacheEntry = { status: "pending", result: null, fetchPromise: null }; postsCache.set(userId, cacheEntry); const url = `https://jsonplaceholder.typicode.com/posts${ userId ? `?userId=${userId}` : "" }`; cacheEntry.fetchPromise = fetch(url) .then(res => res.json()) .then(success => { cacheEntry.status = "fulfilled"; cacheEntry.result = success; }) .catch(error => { cacheEntry.status = "rejected"; cacheEntry.result = error; }); // 返回状态检查函数,触发Suspense或返回结果 return () => { if (cacheEntry.status === "pending") { throw cacheEntry.fetchPromise; } else if (cacheEntry.status === "rejected") { throw cacheEntry.result; } else { return cacheEntry.result; } }; } export default Posts;
关键说明
postsCache用Map存储,键为userId,值包含该用户请求的状态、结果和Promise,确保每个用户的数据独立。- 组件每次渲染时,都会根据当前props的
userId调用fetchPosts,自动复用已有缓存或发起新请求。 - 当
userId变化时,组件会触发新的请求,同时Suspense会处理加载状态,无需额外的loading状态管理。
内容的提问来源于stack exchange,提问作者spassvogel
相关产品推荐
相关产品推荐

