路由参数更新时用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
相关产品推荐
相关产品推荐

