尽管数据在缓存中可用,但 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
},
},
},
},
},
})
每当我导航到不同的页面时,数据都会添加到 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
},
},
},
},
},
})