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

路由参数更新时用useSWR调API并通过ContextAPI自定义Hook存值问题

错误原因

你遇到的报错是违反了React Hook的调用规则:所有Hook(包括自定义Hook)必须在React函数组件的最顶层调用,不能嵌套在useEffect、条件判断、循环等回调逻辑中。同时你的写法没有利用到useSWR的核心能力:只要传入useSWR的缓存key(第一个参数)发生变更,就会自动触发重新请求,完全不需要手动用useEffect包裹触发请求的逻辑。

解决方案

步骤1:将useFetch调用移到组件顶层

把useFetch从useEffect中挪到组件最外层,直接传入动态生成的查询参数即可,查询参数变化时useSWR会自动发起新请求。

步骤2:同步请求结果到Context

只需要监听useFetch返回的用户数据和错误状态,变更时更新到useUsers对应的Context状态即可。

修改后的UsersPage组件示例代码:

import { useUsers } from "../../hooks/useUsers";
import { useFetch } from "../../hooks/useFetch";
import { useParams, useEffect } from "react";

const UsersPage = () => {
  // 顶层调用所有Hook
  const { pageNumber, userId } = useParams();
  const {
    selectedGender,
    nationality,
    results,
    page,
    setUsers, // 需提前在useUsers的Context中暴露更新用户列表的方法
    setFetchError, // 可选,暴露更新请求错误的方法
    // 其余原有状态和方法保留
  } = useUsers();

  // 动态生成查询参数
  const query = `&gender=${selectedGender}&nat=${nationality}&page=${page}&results=${results}`;
  // 顶层调用useFetch,query变更时自动重发请求
  const { users, error } = useFetch(query);

  // 仅同步请求结果到Context
  useEffect(() => {
    if (users) setUsers(users);
    if (error) setFetchError(error);
  }, [users, error, setUsers, setFetchError]);

  // 其余组件渲染逻辑保留
}
优化建议

可以直接把请求逻辑整合到useUsers自定义Hook中,让业务逻辑更聚合,UsersPage不需要感知请求细节:

// useUsers.js 内部整合请求逻辑
import { useState, useEffect } from "react";
import useSWR from "swr";

// 原有Context相关逻辑保留
const useUsers = () => {
  // 原有状态:selectedGender、nationality、page、results等保留
  const [users, setUsers] = useState([]);
  const [fetchError, setFetchError] = useState(null);

  const API_URL = process.env.REACT_APP_API_URL;
  const fetcher = async (query) => {
    const formedURL = `${API_URL}${query}`;
    const response = await fetch(formedURL);
    const data = await response.json();
    return data.results;
  };

  // 内部处理请求逻辑
  const query = `&gender=${selectedGender}&nat=${nationality}&page=${page}&results=${results}`;
  const { data, error } = useSWR(query, fetcher);

  useEffect(() => {
    if (data) setUsers(data);
    if (error) setFetchError(error);
  }, [data, error]);

  // 暴露状态和方法给组件
  return {
    users,
    fetchError,
    selectedGender,
    nationality,
    // 其余原有状态和方法保留
  }
}

内容的提问来源于stack exchange,提问作者Romualdo Arrechea Hernández

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 03:12:00