You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何结合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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 17:50:33