如何结合useParams使用Context API共享农场数据?
实现农场数据的Context共享方案
1. 创建FarmContext与Provider组件
先单独创建一个FarmContext.js文件,把数据获取逻辑和Context定义整合在一起,这样所有子组件都能共享农场数据:
import React, { createContext, useState, useEffect, useContext } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import axios from 'axios'; import { toast } from 'react-toastify'; import UserContext from './UserContext'; // 导入你的UserContext // 创建FarmContext const FarmContext = createContext(); // 定义Provider组件,负责数据获取与状态管理 export const FarmProvider = ({ children }) => { const [farm, setFarm] = useState(null); const [isLoading, setIsLoading] = useState(true); const { username: urlUsername, farmId } = useParams(); const navigate = useNavigate(); const { username: contextUsername } = useContext(UserContext); useEffect(() => { let isMounted = true; // 优先用Context里的用户名,没有则取URL参数 const targetUsername = contextUsername || urlUsername; axios.get(`/api/farm/${targetUsername}/${farmId}`) .then(res => { if (!isMounted) return; if (res.data.status === 200) { setFarm(res.data.farm); setIsLoading(false); } else if (res.data.status === 404) { navigate('/'); toast.error(res.data.message, "error"); } }) .catch(err => { if (!isMounted) return; setIsLoading(false); toast.error('获取农场数据失败'); }); return () => { isMounted = false; }; }, [contextUsername, urlUsername, farmId, navigate]); // 向外暴露需要共享的状态与方法 const contextValue = { farm, isLoading, setFarm }; return ( <FarmContext.Provider value={contextValue}> {children} </FarmContext.Provider> ); }; // 自定义Hook,简化Context消费 export const useFarm = () => { const context = useContext(FarmContext); if (!context) { throw new Error('useFarm必须在FarmProvider内部使用'); } return context; }; export default FarmContext;
2. 在根组件中包裹Provider
确保所有需要访问农场数据的组件都被FarmProvider包裹,注意要放在UserProvider之后(因为FarmProvider依赖UserContext):
import { FarmProvider } from './FarmContext'; import { UserProvider } from './UserContext'; import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import FarmDetail from './FarmDetail'; import FarmStats from './FarmStats'; function App() { return ( <Router> <UserProvider> <FarmProvider> <Routes> <Route path="/farm/:username/:farmId" element={<FarmDetail />} /> <Route path="/farm/:username/:farmId/stats" element={<FarmStats />} /> </Routes> </FarmProvider> </UserProvider> </Router> ); }
3. 在子组件中消费共享数据
通过自定义HookuseFarm直接获取农场数据,无需重复请求:
import { useFarm } from './FarmContext'; function FarmDetail() { const { farm, isLoading } = useFarm(); if (isLoading) { return <div>加载中...</div>; } if (!farm) { return <div>未找到农场数据</div>; } return ( <div> <h1>{farm.name}</h1> <p>地址:{farm.address}</p> <p>占地面积:{farm.area} 亩</p> </div> ); } export default FarmDetail;
核心注意事项
- Provider的层级要正确:
UserProvider在外,FarmProvider在内,保证FarmProvider能拿到UserContext的数据。 useEffect的依赖要补全:把所有影响请求的变量(如用户名、农场ID)都加入依赖数组,确保参数变化时重新请求数据。- 初始化状态更合理:把
useState('')改成useState(null),符合农场对象的类型预期。
内容的提问来源于stack exchange,提问作者John Mark
相关产品推荐
相关产品推荐

