Управление локальным состоянием с помощью Apollo Client и React Hooks
В этом посте мы узнаем, как работать с вашими локальными данными в Apollo Client.

Потребность в локальном состоянии
Современные веб и мобильные приложения стали чрезвычайно управляемыми данными. Создание больших одностраничных приложений является сложным процессом из-за постоянно меняющихся данных с течением времени. Обнаружение этих изменений данных и повторное отображение интерфейса каждый раз является болезненным.
Мы хотим получить доступ ко всем свойствам, хранящимся в различных компонентах нашего приложения, наиболее оптимальным способом.
Введенние в Apollo Client
Apollo Client имеет встроенные возможности обработки локальных состояний, которые позволяют вам хранить ваши локальные данные в кэше Apollo вместе с вашими удаленными данными. Чтобы получить доступ к вашим локальным данным, просто запросите их с помощью GraphQL. Вы даже можете запросить локальные и серверные данные в одном запросе! - Apollo Docs
Давайте углубимся в настройку клиента apollo и локального состояния:
Настройка клиента Apollo 🚀
const client = new ApolloClient({
link, // httpLink
cache,
resolvers
typeDefs,
});Теперь Apollo Client состоит из нескольких ключевых частей.
- Apollo link - используется для настройки клиента Apollo
network layer. Это означает, что ссылка apollo позволяет настроить способ отправки запросов по HTTP. - Cache - клиент Apollo использует экземпляр Apollo Cache для управления своей стратегией кэширования
- Resolvers - для реализации вашего локального обновления состояния в виде мутации GraphQL
- TypeDefs - Чтобы дополнительно установить на стороне клиента схему которая будет использоваться с Apollo Client. Эта схема используется для самоанализа в Apollo Client Devtools, где вы можете изучить свою схему в GraphiQL.
Позволяет подключить каждую из вышеуказанных частей. Мы установим локальное состояние для свойства под названием isDarkModeEnabled.
import { InMemoryCache, NormalizedCacheObject } from 'apollo-cache-inmemory';
import { ApolloClient } from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
// typedefs and resolvers
import StateResolvers from './resolvers';
import typeDefs from './typeDefs';
export function createClient(): ApolloClient {
const cache = new InMemoryCache();
// create http link
const httpLink = new HttpLink({
uri: 'https://example.com/graphql'
});
// Helper function to get data from the cache
const getState = (query: any): IState => {
return cache.readQuery({ query }).state;
};
// Helper function to write data back to the cache
const writeState = (state: IState) => {
return cache.writeData({ data: { state } });
};
// initial apollo local state
const initState = () => {
const state = {
appState: defaultAppState,
__typename: 'State',
};
writeState(state);
};
const client = new ApolloClient({
link,
cache,
resolvers: StateResolvers(getState, writeState),
typeDefs,
});
} Сначала мы создаем новый экземпляр Apollo InMemoryCache. Здесь будет жить наше локальное состояние. Затем мы определяем наш сетевой уровень, чтобы клиент apollo подключался к серверу GraphQL.
getState и writeState две вспомогательные функции, которые читают и записывают данные в кеш. Вспомогательные функции реализуют cache.readData и cache.writeData и действуют как методы получения и установки в кэше. Далее мы инициализируем наше состояние apollo значениями по умолчанию. Важно записать начальное состояние в кэш, чтобы любые компоненты, запрашивающие данные до запуска мутации (обновления локального состояния), не выдавали ошибку. Наконец, мы инициализируем наш клиент Apollo.
Давайте приступим к определению typeDefs и Resolvers. У нас есть простая схема, которая определяет состояние нашего приложения.
import gql from 'graphql-tag';
const typeDefs = gql `
type appState {
isDarkModeEnabled: Boolean
}
`;
export default typeDefs;Управление кешем 📝
Кеш Apollo - это единственный источник правды или «хранилище» в терминах редукции, когда вы используете Apollo Client для управления состоянием вашего приложения.
import gql from 'graphql-tag';
const getAppState = gql`
query {
state @client {
appState {
isDarkModeEnabled
}
}
}
`;
export default (getState, writeState) => {
return {
Mutation: {
updateAppState(_, appState) {
// получить текущее / начальное состояние из кеша
const state = getState(getAppState);
const newState = {
...state,
appState: Object.assign({}, state.appState, appState),
};
writeState(newState);
return newState;
},
}
}
}С помощью функций readState и writeState мы запрашиваем начальное / текущее состояние, а затем обновляем его новыми значениями. Для запроса локального состояния мы использовали директиву @client, указывающую, что она должна быть разрешена из кэша клиента Apollo или локальной функции распознавателя.
Теперь давайте посмотрим, как мы можем обновить состояние приложения на простом примере
import React from "react"
import { useMutation, useQuery } from "@apollo/react-hooks";
import gql from "graphql-tag";
const toggleAppTheme = gql`
mutation updateAppState{
isDarkModeEnabled
}
`;
const getAppState = gql`
query {
state @client {
appState {
isDarkModeEnabled
}
}
}
`;
const ToggleTheme = () => {
const { loading, error, data } = useQuery(getAppState)
const [toggleTheme] = useMutation(toggleAppTheme);
const handleToggle = () => {
const { isDarkModeEnabled } = data.state.appState;
const newAppState = {
isDarkModeEnabled: !isDarkModeEnabled,
__typename: 'AppState'
}
toggleTheme({variables: newAppState})
}
if(loading) {
return Loading...
}
return (
)
}
export default ToggleTheme;Это оно! Все компоненты, которые прослушивают локальное состояние, получат обновленное значение для appState и впоследствии повторно выполнят рендеринг после обновления.