从react apollo客户端写入缓存后,读取缓存的正确方法是什么



我创建了一个从graphql服务器读取数据的基本示例。我注意到我的网络呼叫在我运行变异后会发出请求。我正在尝试更新缓存以防止网络调用,但当我尝试读取缓存时。

这种方法可以检索数据,但不会自动从缓存中读取:

使用查询

const { data } = useQuery(GET_PLAYERS);

使用@client指令的useQuery指示获取缓存-失败

const GET_PLAYERS = gql`
query getPlayers {
players @client {
__typename
_id
name
score
}
}
`;
const { data } = useQuery(GET_PLAYERS);

err=
MissingFieldError{message:"在ROOT_QUERY对象上找不到字段"players",路径:Array(1(,查询:{…},变量:{..}消息:";在ROOT_QUERY对象上找不到字段"players";

使用client.readQuery((在加载时和突变后都不返回任何结果:

const obj = client.readQuery({ query: GET_PLAYERS });

这是我的完整代码。

import React, { FC } from 'react';
import 'cross-fetch/polyfill'; // patch for tests: Error: fetch is not found globally and no fetcher passed, to fix pass a fetch for your environment
import {
gql,
useQuery,
useMutation,
ApolloClient,
InMemoryCache,
ApolloProvider
} from '@apollo/client';
const uri = 'http://localhost:4000/graphql';
const client = new ApolloClient({
uri,
cache: new InMemoryCache()
});
const ADD_PLAYER = gql`
mutation AddPlayer($name: String!) {
addPlayer(player: { name: $name }) {
_id
name
score
}
}
`;
// example with directive = @client to try to get cached version
// const GET_PLAYERS = gql`
//   query getPlayers {
//     players @client {
//       __typename
//       _id
//       name
//       score
//     }
//   }
// `;
const GET_PLAYERS = gql`
query getPlayers {
players {
_id
name
score
}
}
`;
interface IData {
data: {
players: Array<{ name: string }>;
};
loading: boolean;
}
interface IPlayer {
name: string | null;
}
const App: FC = () => {
const { data } = useQuery(GET_PLAYERS);
// const { data } = client.readQuery({ query: GET_PLAYERS });
// console.log('obj = ', obj);
// const data = obj && obj.data;
const [addPlayer] = useMutation(ADD_PLAYER, {
update: (cache, { data: mutationData }) => {
try {
const cacheGetPlayers: { players: Array<IPlayer> } | null = cache.readQuery({
query: GET_PLAYERS
});
const cachePlayers: Array<IPlayer> = (cacheGetPlayers && cacheGetPlayers.players) || [
{ name: null }
];
let playersUpdated: Array<IPlayer> = { ...cachePlayers };
const player = mutationData.addPlayer;
if (player) {
// ie not already existing !!!
if (playersUpdated) {
if (!cachePlayers.find((item: IPlayer) => player.name !== item.name)) {
playersUpdated.push(player);
}
} else {
playersUpdated = [player];
}
cache.writeQuery({
query: GET_PLAYERS,
data: {
getPlayers: {
players: playersUpdated
}
}
});
}
} catch (err) {
console.log('err = ', err);
}
}
});
const handleClick = () => {
const name = 'mary';
addPlayer({
variables: { name },
// example data:
// optimisticResponse: {
//   __typename: 'Mutation',
//   addPlayer: {
//     _id: ObjectId('4edd40c86762e0fb12000003'), // 4edd40c86762e0fb12000003
//     score: 0,
//     name
//   }
// },
refetchQueries: [{ query: GET_PLAYERS }]
});
};
return (
<div>
list of existing names = {data &&
data.players instanceof Array &&
data.players.map((item: { name: string }) => `,${item.name}`)}
<button type="button" onClick={handleClick}>
Click to add player
</button>
</div>
);
};
const Prov = () => (
<ApolloProvider client={client}>
<App />
</ApolloProvider>
);
export default Prov;

有什么建议,谢谢

首先,@client指令只用于查询应该用__typename在缓存中初始化players字段的数据。像这样:

const cache = new InMemoryCache()
const client = new ApolloClient({
cache,
link,
})
cache.writeData({
data: {
players: {
items: [],
__typename: Player
}
},
})
...
const GET_PLAYERS = gql`
query {
players @client {
__typename
items {
_id
name
score
}
}
}
`;
const { data } = useQuery(GET_PLAYERS);

其次,如果您想在突变后更新缓存,您应该使用update选项。像这样:

useMutation(UPDATE_PLAYER, {
update(cache, { data: { player } }) {
const { players } = cache.readQuery(options)
cache.writeQuery({
...options,
data: {
players: { ...players, items: [player, ...players.items] },
},
})
},
}
}
)

最新更新