如何使用React的createContext全局共享API获取的数据?
问题分析与解决方案
你的代码核心问题在于上下文类型与实际共享的数据结构不匹配,同时缺少明确的类型注解和正确的上下文使用流程,以下是分步修正方案:
1. 修正上下文类型定义(DataContext.ts)
你原本定义的PostContextType是单个帖子的结构,但实际需要共享的是「加载状态 + 帖子数组」的组合,重新定义类型并设置合理初始值:
// DataContext.ts // 先定义单个帖子的类型 type Post = { userId: number; id: number; title: string; body: string; }; // 定义上下文要共享的数据结构 type PostContextType = { loaded: boolean; posts: Post[] | null; }; // 初始值必须严格匹配类型定义 const PostContext = createContext<PostContextType>({ loaded: false, posts: null, }); export default PostContext;
2. 调整DataProvider的value传递(DataProvider.tsx)
让Provider传递的value与上下文类型一致,改用对象形式提升可读性:
// DataProvider.tsx import PostContext from './DataContext'; import { useFetch } from './useFetch'; type PostProviderProps = { children: React.ReactNode; }; export default function DataProvider({ children }: PostProviderProps) { const [loaded, posts] = useFetch(`https://jsonplaceholder.typicode.com/posts`); return ( <PostContext.Provider value={{ loaded, posts }}> {children} </PostContext.Provider> ); }
3. 完善useFetch的类型与逻辑(useFetch.ts)
添加泛型支持和明确的返回类型,同时优化async/await的写法(避免混合.then):
// useFetch.ts import { useState, useEffect } from 'react'; import axios from 'axios'; // 泛型支持不同接口返回的数据类型 export const useFetch = <T>(url: string): [boolean, T | null] => { const [fetchedData, setFetchedData] = useState<T | null>(null); const [loaded, setLoaded] = useState(false); // 将url加入依赖,确保url变化时重新发起请求 useEffect(() => { getAllFetchedData(); }, [url]); const getAllFetchedData = async () => { try { const response = await axios.get(url); setFetchedData(response.data); setLoaded(true); } catch (error) { console.error(`Error: ${error}`); // 即使请求失败,也标记为加载完成,避免一直显示加载状态 setLoaded(true); } }; return [loaded, fetchedData]; };
4. 在根组件包裹DataProvider
确保所有需要访问共享数据的子组件都在Provider范围内,比如在App.tsx中:
// App.tsx import DataProvider from './DataProvider'; import PostList from './PostList'; function App() { return ( <DataProvider> <PostList /> </DataProvider> ); } export default App;
5. 在子组件中使用共享数据
创建子组件(比如PostList.tsx),通过useContext获取并展示数据:
// PostList.tsx import { useContext } from 'react'; import PostContext from './DataContext'; export default function PostList() { const { loaded, posts } = useContext(PostContext); if (!loaded) { return <div>加载中...</div>; } if (!posts) { return <div>加载失败,无数据</div>; } return ( <ul> {posts.map((post) => ( <li key={post.id}> <h3>{post.title}</h3> <p>{post.body}</p> </li> ))} </ul> ); }
内容的提问来源于stack exchange,提问作者ay_tee_em
相关产品推荐
相关产品推荐

