Apollo 客户端延迟重新获取

Apollo Client lazy refetch

Apollo Client v3React 实现中,我使用钩子来使用订阅。当我从订阅中收到数据时,我想重新获取查询,但前提是查询先前已执行并在缓存中。有办法实现吗?

我从延迟查询开始,然后在收到订阅数据时手动检查缓存,然后尝试执行延迟查询和重新获取。它有效,但感觉笨重...

export const useMyStuffLazyRefetch = () => {
    const [refetchNeeded, setRefetchNeeded] = useState<boolean>(false);
    const client = useApolloClient();
    const [getMyStuff, { data, refetch }] = useLazyQuery<IStuffData>(GET_MY_STUFF);

    useEffect(() => {
        if (refetchNeeded) {
            setRefetchNeeded(false);
            refetch();
        }
    }, [refetchNeeded]);

    const refetchIfNeeded = async () => {
        const stuffData = client.cache.readQuery<IStuffData>({ query: GET_MY_STUFF });
        if (!stuffData?.myStuff?.length) return;
        getMyStuff();
        setRefetchNeeded(true);
    }

    return {
        refetchIfNeeded: refetchIfNeeded
    };
}

useLazyQuery有一个prop叫做called,这是一个布尔值,表示是否调用了查询函数,

也许你可以试试这个:

export const useMyStuffLazyRefetch = () => {
    const [refetchNeeded, setRefetchNeeded] = useState<boolean>(false);
    const client = useApolloClient();
    const [getMyStuff, { data, refetch, called }] = useLazyQuery<IStuffData>(GET_MY_STUFF);

    useEffect(() => {
        if (refetchNeeded) {
            setRefetchNeeded(false);

            if (called) {
              refetch();
            }
            else {
              getMyStuff()
            }
        }
    }, [refetchNeeded, called]);

    const refetchIfNeeded = async () => {
        const stuffData = client.cache.readQuery<IStuffData>({ query: GET_MY_STUFF });
        if (!stuffData?.myStuff?.length) return;
        getMyStuff();
        setRefetchNeeded(true);
    }

    return {
        refetchIfNeeded: refetchIfNeeded
    };
}

以防这对某人有所帮助。我创建了一个单独的挂钩,因此使用起来不那么碍眼。

如果数据在缓存中,这是重新获取的挂钩。如果数据不在缓存中,Apollo Client 错误而不是返回类似 undefinednull

的内容
import { useState, useEffect } from "react";
import { OperationVariables, DocumentNode, LazyQueryHookOptions, useApolloClient, useLazyQuery } from "@apollo/client";

export default function useLazyRefetch <TData = any, TVariables = OperationVariables>(query: DocumentNode, options?: LazyQueryHookOptions<TData, TVariables>) {
    const [refetchNeeded, setRefetchNeeded] = useState<boolean>(false);
    const [loadData, { refetch }] = useLazyQuery(query, options);
    const client = useApolloClient();

    useEffect(() => {
        if (refetchNeeded) {
            setRefetchNeeded(false);
            refetch();
        }
    }, [refetchNeeded]);

    const refetchIfNeeded = (variables: TVariables) => {
        try {
            const cachecData = client.cache.readQuery<
                TData,
                TVariables
            >({
                query: query,
                variables: variables
            });
            if (!cachecData) return;
            loadData({ variables: variables });
            setRefetchNeeded(true);
        }
        catch {}
    };

    return {
        refetchIfNeeded: refetchIfNeeded
    };
}

以及钩子使用示例:

const { refetchIfNeeded } = useLazyRefetch<
        IStuffData,
        { dataId?: string }
    >(GET_MY_STUFF);

//... And then you can just call it when you need to

refetchIfNeeded({ dataId: "foo" });

打字稿在您的

中抱怨
   useEffect(() => {
   if (refetchNeeded) {
       setRefetchNeeded(false);
       refetch();
   }
}, [refetchNeeded]);

refetch() says - Cannot invoke an object which is possibly 'undefined'.ts(2722)

const refetch: ((variables?: Partial<TVariables> | undefined) => Promise<ApolloQueryResult<TData>>) | undefined

    and in [refetchNeeded] dependency - 

React Hook useEffect 缺少依赖项:'refetch'。包含它或删除依赖项数组。eslintreact-hooks/exhaustive-deps const refetchNeeded:布尔值