使用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
相关产品推荐
相关产品推荐

