尽管数据在缓存中可用,但 Apollo 客户端对 graphql 服务器的 offsetLimitPagination 请求

Apollo client's offsetLimitPagination requests for graphql server although the data is available in cache

每当我导航到不同的页面时,数据都会添加到 Apollo 的缓存中。但是当我导航到之前的页面时,虽然数据在缓存中可用。 Apollo 向 graphql 服务器发出网络请求。

const cache = new InMemoryCache({
    typePolicies: {
        Query: {
            fields: {
                users: {
                    ...offsetLimitPagination(),
                    read(existing, { args }) {
                        return (
                            existing &&
                            existing.slice(
                                args?.offset,
                                args?.offset + args?.limit
                            )
                        )
                    },
                }
            },
        },
    },
})

const client = new ApolloClient({
    uri: "https://api.spacex.land/graphql/",
    cache,
    connectToDevTools: true,
})

我的组件:

const Users: React.FC = () => {
    const [offset, setOffset] = useState(0)
    const { loading, data, error, fetchMore } = useUsersQuery({ \ Generated via graphql-code-gen
        variables: { offset, limit: 2 },
    })

    const fetchMoreHandler = (): void => {
        const currentLength = data?.users.length || 0
        fetchMore({
            variables: { offset: offset + currentLength, limit: 2 },
        }).then(() => {
            setOffset((ofsset) => ofsset + currentLength)
        })
    }

    const fetchPrevHandler = (): void => {
        let currentLength = data?.users.length || 0
        if (currentLength === 0) {
            currentLength = 2
        }
        fetchMore({
            variables: { offset: offset - currentLength, limit: 2 },
        }).then(() => {
            setOffset((ofsset) => ofsset - currentLength)
        })
    }
    if (loading) {
        return <div>Loading....</div>
    }
    if (error) {
        return <div>Something went wrong!</div>
    }

    return (
        <div className={classes.root}>
            {offset > 0 && (
                <button type="button" onClick={fetchPrevHandler}>
                    Prev
                </button>
            )}

            <div>
                {data?.users.map((user) => (
                    <div key={user.id}>
                        <h6>{user.name}</h6>
                    </div>
                ))}
            </div>
            {(data?.users.length || 0) > 0 && (
                <button type="button" onClick={fetchMoreHandler}>
                    Next
                </button>
            )}
        </div>
    )
}

export default Users

这是查询:

query Users($offset: Int, $limit: Int) {
  users(offset:$offset, limit: $limit, order_by:[{timestamp:desc}]) {
    id
    name
    rocket
    timestamp
    twitter
  }
}

当我浏览我的缓存时看起来像这样: _APOLLO_CLIENT_.cache.data.data:

{
    "users:a75bf714-30e4-4219-8335-e413f8f127ef": {
        "id": "a75bf714-30e4-4219-8335-e413f8f127ef",
        "__typename": "users",
        "name": "HI",
        "rocket": "FRIENDS",
        "timestamp": "2021-12-22T18:38:09.805832+00:00",
        "twitter": null
    },
    "users:c2317843-8481-4cb6-87e1-16d8f4aa7092": {
        "id": "c2317843-8481-4cb6-87e1-16d8f4aa7092",
        "__typename": "users",
        "name": "simeooone",
        "rocket": "tha_rocket",
        "timestamp": "2021-12-22T16:14:50.431972+00:00",
        "twitter": "@galfh"
    },
    "ROOT_QUERY": {
        "__typename": "Query",
        "users": [
            {
                "__ref": "users:a75bf714-30e4-4219-8335-e413f8f127ef"
            },
            {
                "__ref": "users:c2317843-8481-4cb6-87e1-16d8f4aa7092"
            },
            {
                "__ref": "users:f6358c49-7ce3-491e-8103-48e9e4b847cd"
            },
            {
                "__ref": "users:a04c9b78-3406-4585-ba16-0a4c540fdc23"
            }
        ]
    },
    "users:f6358c49-7ce3-491e-8103-48e9e4b847cd": {
        "id": "f6358c49-7ce3-491e-8103-48e9e4b847cd",
        "__typename": "users",
        "name": "aemilio",
        "rocket": "yo_mum",
        "timestamp": "2021-12-22T16:11:14.728876+00:00",
        "twitter": "@yo_mum"
    },
    "users:a04c9b78-3406-4585-ba16-0a4c540fdc23": {
        "id": "a04c9b78-3406-4585-ba16-0a4c540fdc23",
        "__typename": "users",
        "name": "",
        "rocket": "oy",
        "timestamp": "2021-12-22T16:10:24.420815+00:00",
        "twitter": "asd"
    }
}

当我导航回来显示这些确切的项目时,apollo 仍然发出网络请求!

对于其他像我这样刚接触 Apollo 并有这个问题的人,我发现 fetchMore 功能无论如何总是强制网络请求。这是设计使然。如果你想从缓存中读取你不应该使用 fetchMore 而是做这样的事情:

    const [offset, setOffset] = useState(0)
    const { loading, data, error } = useUsersQuery({
        variables: { offset, limit: 2 },
    })
   const fetchMoreHandler = (): void => {
        const currentLength = data?.users.length || 0
        setOffset((ofsset) => ofsset + currentLength)
    }

    const fetchPrevHandler = (): void => {
        let currentLength = data?.users.length || 0
        if (currentLength === 0) {
            currentLength = 2
        }
        setOffset((ofsset) =>
            ofsset - currentLength < 0 ? 0 : ofsset - currentLength
        )
    }

这将是您的 InMemoryCache 实例:

const cache = new InMemoryCache({
    typePolicies: {
        Query: {
            fields: {
                users: {
                    ...offsetLimitPagination(),
                    read(existing, { args }) {
                        let res
                        if (existing) {
                            res = existing.slice(
                                args?.offset,
                                args?.offset + args?.limit
                            )
                        }
                        return res && res.length === args?.limit
                            ? res
                            : undefined
                    },
                },
            },
        },
    },
})