自定义React数据获取Hook出现无限循环问题求助
解决useCollection Hook的无限循环问题
核心原因
fetchItems的useCallback依赖数组遗漏了query参数,导致函数内部始终使用闭包捕获的旧query值;同时当query变化时,fetchItems的函数引用并未更新,但监听query变化的useEffect会反复触发执行,引发循环。- 存在潜在逻辑错误:WebSocket消息判断中
(message.event === 'init' || 'update')会始终返回true(因为'update'是真值),导致不必要的fetchItems调用。
修复后的代码
修改后的useCollection Hook
function useCollection<Collection extends keyof Omit<Schema, 'directus_users'>>( collection: Collection, query?: Query<Schema, CollectionType<Schema, Collection>>, ) { const client = useClient(); const [items, setItems] = useState<Schema[Collection][number][]>([]); const [loading, setLoading] = useState(false); const [error, setError] = useState<Error | null>(null); const [wsConnected, setWsConnected] = useState(false); const fetchItems = useCallback(async () => { try { setLoading(true); const results: Schema[Collection][number][] = await client.request< Schema[Collection][number][] >( readItems< Schema, Collection, Query<Schema, CollectionType<Schema, Collection>> >(collection, query ?? {}), ); setItems(() => results); } catch (err) { setError(err as Error); } finally { setLoading(false); } }, [client, collection, query]); // 新增query到依赖数组 useEffect(() => { fetchItems(); }, [fetchItems]); // 移除query依赖,query变化会触发fetchItems更新 useEffect(() => { const connectWs = async () => { if (wsConnected || !client.initialized) { return; } client.onWebSocket('message', function (message) { if ( message.type === 'subscription' && (message.event === 'init' || message.event === 'update') // 修复判断逻辑 ) fetchItems(); if (message.type === 'ping') { client.sendMessage({ type: 'pong', }); } }); client.onWebSocket('close', function () { console.log({ event: 'onclose' }); }); client.onWebSocket('error', function (error) { console.error({ event: 'onerror', error }); }); await client.subscribe(collection, { event: 'update', query: { fields: [] }, }); setWsConnected(true); }; connectWs(); }, [client, client.initialized, collection, fetchItems, wsConnected]); return { items, loading, error }; // 补充返回error,方便调用方处理 }
关键修改点说明
- 补全依赖数组:将
query加入useCallback的依赖列表,确保query变化时,fetchItems函数实例更新,内部使用最新的query参数。 - 简化useEffect依赖:监听数据更新的
useEffect只需依赖fetchItems,因为query变化会自动触发fetchItems更新,进而触发useEffect执行,避免重复监听导致的循环。 - 修复WebSocket判断逻辑:修正
message.event的判断条件,只有当事件确实是init或update时才调用fetchItems,减少不必要的数据请求。
额外注意事项
调用处的revisionsHistoryQuery已经用useMemo包裹,确保selected不变时query引用稳定,这部分无需修改,保持即可。
内容的提问来源于stack exchange,提问作者Beginner
相关产品推荐
相关产品推荐

