Управление локальным состоянием с помощью 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) { returnLoading...
} return ( ) } export default ToggleTheme;
Это оно! Все компоненты, которые прослушивают локальное состояние, получат обновленное значение для appState
и впоследствии повторно выполнят рендеринг после обновления.