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

自定义React数据获取Hook出现无限循环问题求助

解决useCollection Hook的无限循环问题

核心原因

  1. fetchItems的useCallback依赖数组遗漏了query参数,导致函数内部始终使用闭包捕获的旧query值;同时当query变化时,fetchItems的函数引用并未更新,但监听query变化的useEffect会反复触发执行,引发循环。
  2. 存在潜在逻辑错误: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,方便调用方处理
}

关键修改点说明

  1. 补全依赖数组:将query加入useCallback的依赖列表,确保query变化时,fetchItems函数实例更新,内部使用最新的query参数。
  2. 简化useEffect依赖:监听数据更新的useEffect只需依赖fetchItems,因为query变化会自动触发fetchItems更新,进而触发useEffect执行,避免重复监听导致的循环。
  3. 修复WebSocket判断逻辑:修正message.event的判断条件,只有当事件确实是init或update时才调用fetchItems,减少不必要的数据请求。

额外注意事项

调用处的revisionsHistoryQuery已经用useMemo包裹,确保selected不变时query引用稳定,这部分无需修改,保持即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 12:42:05