#reactjs #typescript #graphql #apollo-client
#reactjs #typescript #graphql #apollo-client
Вопрос:
Я создал базовый пример, который считывает данные с сервера graphql. Я заметил, что мои сетевые вызовы делают запрос после того, как я запустил свою мутацию. Я пытаюсь обновить кеш, чтобы предотвратить этот сетевой вызов, но когда я затем пытаюсь прочитать кеш.
Этот метод работает для извлечения данных, но он не выполняет автоматическое чтение из кэша:
Запрос использования
const { data } = useQuery(GET_PLAYERS);
Используйте запрос с директивой @client для указания get cache — сбой
const GET_PLAYERS = gql`
query getPlayers {
players @client {
__typename
_id
name
score
}
}
`;
const { data } = useQuery(GET_PLAYERS);
ошибка =
MissingFieldError {сообщение: «Не удается найти поле ‘players’ в объекте ROOT_QUERY», путь: Массив (1), запрос: {…}, переменные: {…}}
сообщение: «Не удается найти поле «игроки» в объекте ROOT_QUERY»
использование 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 amp;amp; 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 amp;amp; 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 amp;amp;
data.players instanceof Array amp;amp;
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;
Любой совет, спасибо
Ответ №1:
Во-первых, директива @client просто использует для запроса данных, которые вы должны инициировать в players
поле в кэше с помощью __typename
. Вот так:
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] },
},
})
},
}
}
)
Комментарии:
1. Спасибо за предложение. Просто смотрю это. Кажется, есть несколько способов сделать что-то, и на сайте Apollo не хватает полных примеров. Ваш пример, похоже, относится к — apollo-link-state, который является другим способом записи данных. Я изучаю это, но я все равно хотел бы знать, как записывать кеш обоими способами, т. Е. Используя @apollo / client include.