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

使用useCallback时fetch函数未触发的原因排查

为什么useCallback包裹的函数不触发,useEffect却可以?

核心原因:两者的作用完全不同

  • useCallback只是缓存函数的引用:当依赖项search变化时,它会生成一个新的searchCharactersAPI函数,但它不会主动去执行这个函数——你得手动调用它才会触发API请求。
  • useEffect是副作用执行器:它的逻辑是“当依赖变化时,自动执行内部的回调”,所以把API请求放在useEffect里,search一变就会自动触发请求。

你的代码问题

你用useCallback包装了API请求函数,但没有在search变化时调用这个函数。函数只是被重新创建了,但没人执行它,自然不会发请求。

解决办法

如果你想保留useCallback来优化函数引用,可以结合useEffect来触发函数:

const searchCharactersAPI = useCallback(async () => {
    try {
        setLoading(true);
        const res = await fetch(
            `https://narutodb.xyz/api/character${
                search !== "" ? `/search?name=${search}` : ""
            }`,
        );
        const resJSON = await res?.json();

        setCharactersData(resJSON);
    } catch (error) {
        console.log("There was an error", error);
    } finally {
        setLoading(false);
    }
}, [search]);

// 监听search变化,自动调用API函数
useEffect(() => {
    // 空搜索时可以清空数据或者跳过请求
    if (search.trim()) {
        searchCharactersAPI();
    } else {
        setCharactersData(null);
        setLoading(false);
    }
}, [search, searchCharactersAPI]);

const handleSearch = (e: ChangeEvent<HTMLInputElement>) => {
    setSearch(e.target.value)
}

如果想彻底减少useEffect,可以在搜索处理函数里直接调用API,但建议加防抖避免频繁请求:

// 简单的防抖函数
const debounce = (fn: (val: string) => void, delay: number) => {
    let timer: NodeJS.Timeout;
    return (val: string) => {
        clearTimeout(timer);
        timer = setTimeout(() => fn(val), delay);
    };
};

// 带防抖的搜索处理
const handleSearch = useCallback(debounce(async (value: string) => {
    setSearch(value);
    if (!value.trim()) {
        setCharactersData(null);
        setLoading(false);
        return;
    }

    try {
        setLoading(true);
        const res = await fetch(
            `https://narutodb.xyz/api/character/search?name=${value}`
        );
        const resJSON = await res?.json();
        setCharactersData(resJSON);
    } catch (error) {
        console.log("There was an error", error);
    } finally {
        setLoading(false);
    }
}, 500), []);

// 输入框组件
<input 
    className="flex w-full border-0 outline-none focus-visible:false rounded-lg p-2 text-black" 
    placeholder="Search characters..." 
    type="text" 
    onChange={(e) => handleSearch(e.target.value)} 
    value={search} 
/>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 06:40:17