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

React自定义useFetch Hook因setSearchTerm触发无限循环求助

React自定义useFetch Hook触发无限循环问题解决

问题根源

你在AppProvider组件的顶层直接调用了setSearchTerm('s'),这会导致组件每次渲染时都执行状态更新:状态更新触发组件重新渲染,重新渲染时又会再次执行setSearchTerm,如此往复形成无限循环。useFetch的url变化触发请求只是循环过程中的附带现象,核心问题是未受控的状态更新调用。

解决方案

把setSearchTerm的调用放到useEffect中,通过依赖数组控制执行时机,确保只在组件挂载或特定条件下执行一次。

修改后的AppProvider代码

import React, { useContext, useState, useEffect } from "react";
import { useFetch } from "../hooks/useFetch";
const context = React.createContext();

const AppProvider = ({ children }) => {
    const url = "https://www.thecocktaildb.com/api/json/v1/1/search.php?s=";
    const [searchTerm, setSearchTerm] = useState("a");

    // 仅在组件挂载时执行一次状态更新
    useEffect(() => {
        setSearchTerm('s');
    }, []);

    useFetch(`${url}${searchTerm}`);

    return (
        <context.Provider value={"hello"}>
            {children}
        </context.Provider>
    )
}

const useGlobal = () => {
    return useContext(context);
}

export { AppProvider, useGlobal };

可选优化:useFetch Hook的稳定性提升

虽然不是当前循环的直接原因,但可以用useCallback包裹getData函数,避免每次组件渲染时创建新的函数实例,优化useEffect的触发逻辑:

import { useEffect, useState, useCallback } from "react";
export const useFetch = (url) => {
    const [data, setData] = useState([]);
    const [loading, setLoading] = useState(true);

    const getData = useCallback(async () => {
        try {
            setLoading(true);
            const response = await fetch(url);
            const jsonResponse = await response.json();
            setData(jsonResponse);
        } catch (err) {
            console.log(err);
        } finally {
            setLoading(false);
        }
    }, [url]);

    useEffect(() => {
        getData();
    }, [getData])

    return { data, loading };
}

内容的提问来源于stack exchange,提问作者mahziar_mohammadrezei

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 13:50:28