Забавно, но с распространением интернета в мире все больше востребованы веб-приложения, работающие без подключения к сети. Пользователи (и клиенты) хотят функциональные интернет-приложения в онлайн, офлайн и в зонах с неустойчивой связью. А это… не просто. Посмотрим, как создать эффективное решение, работающее без подключения к сети, на React и слое данных GraphQL с применением Apollo Client. Статья разбита на две части. На этой неделе разберем оффлайновые запросы. На следующей неделе примемся за мутации. За спиной Apollo Client все тот же Redux. А это значит, вся экосистема Redux с многочисленными инструментами и библиотеками доступна в приложениях на Apollo. В сфере поддержки офлайн у Redux два основных игрока: Redux Persist и Redux Offline. Redux Persist прекрасный, но дающий лишь основу, инструмент для загрузки хранилища redux в localStorage и восстановления обратно (поддерживаются и другие места хранения). По принятой терминологии, восстановление также называется регидрацией. Redux Offline расширяет возможности Redux Persist дополнительным слоем функций и утилит. Redux Offline автоматически узнает о разрывах и восстановлениях связи и при разрыве позволяет ставить в очередь действия и операции, а при восстановлении – автоматически воспроизводит эти действия вновь. Redux Offline – это «заряженый» вариант для работы без сетевого подключения. Apollo Client и сам неплохо справляется с краткосрочными перебоями сетевых подключений. Когда сделан запрос, его результат помещается в собственное хранилище Apollo. Если тот же запрос делается повторно, результат немедленно берется из хранилища на клиенте и отдается запрашивающему компоненту, кроме случая, когда параметр fetchPolicy имеет значение network-only. Это значит, что при отсутствии сетевого подключения или недоступности сервера повторные запросы будут возвращать последний сохраненный результат. Однако стоит пользователю закрыть приложение, и хранилище пропадет. Как не потерять хранилище Apollo на клиенте между перезапусками приложения? На помощь приходит Redux Offline. Apollo держит свои данные в хранилище Redux (в ключе apollo). Записывая хранилище целиком в localStorage и восстанавливая при следующем запуске приложения, можно переносить результаты прошлых запросов между сеансами работы с приложением даже при отсутствии подключения к интернету. Использование Redux Offline и Apollo Client не обходится без нюансов. Посмотрим, как заставить работать вместе обе библиотеки. Обычно клиент Apollo создается довольно просто: Конструктор ApolloClient автоматически создает хранилище Apollo (и косвенно – хранилище Redux). Полученный экземпляр client подается в компонент ApolloProvider: При использовании Redux Offline необходимо вручную создавать хранилище Redux. Это позволяет подключить к хранилищу промежуточный обработчик (middleware) из Redux Offline. Для начала просто повторим то, что делает сам Apollo: Здесь хранилище store использует редьюсер и промежуточный обработчик (middleware) из экземпляра Apollo (переменная client), а в качестве исходного состояния указано undefined. Теперь можно подать store в компонент ApolloProvider: Превосходно. Создание хранилища Redux под контролем, и можно продолжать с Redux Offline. В простейшем случае добавление Redux Offline заключается в добавлении еще одного промежуточного обработчика к хранилищу. Без дополнительных настроек обработчик offline начнет автоматически записывать хранилище Redux в localStorage. Не верите? Откройте консоль и получите из localStorage эту запись: Выводится большой объект JSON, представляющий полное текущее состояние приложения Apollo. Великолепно! Теперь Redux Offline автоматически делает снимки хранилища Redux в записывает их в localStorage. При каждом запуске приложения сохраненное состояние автоматически берется из localStorage и восстанавливается в хранилище Redux. На все запросы, результаты которых находятся в этом хранилище, будут возвращены данные даже при отсутствии подключения к серверу. Увы, восстановление хранилища происходит не мгновенно. Если приложение делает запрос в то время, как Redux Offline восстанавливает хранилище, могут происходить Странные Вещи(tm). Если в Redux Offline включить логирование для режима autoRehydrate (что само по себе заставляет понервничать), при первоначальной загрузке приложения можно увидеть ошибки, на подобии: Разработчик Redux Persist признал проблему и предложил рецепт отложенного рендеринга приложения после восстановления. К сожалению, его решение основано на ручном вызове persistStore. Однако Redux Offline делает такой вызов автоматически. Посмотрим на другое решение. Создадим Redux action с названием REHYDRATE_STORE, а также соответствующий редьюсер, устанавливающий значение true для признака rehydrated в хранилище Redux: Подключим созданный редьюсер к хранилищу и настроим Redux Offline так, чтобы по окончанию восстановления выполнялось новое действие. Превосходно! Когда Redux Offline восстанавит хранилище, то вызовет функцию persistCallback, которая запустит действие REHYDRATE_STORE и в конечном счете установит признак rehydrate в хранилище. Добавление rehydrate в массив blacklist гарантирует, что эта часть хранилища не будет записана в localStorage и восстановлена из него. Теперь, когда в хранилище есть сведения об окончании восстановления, разработаем компонент, реагирующий на изменения поля rehydrate и визуализирующий дочерние компоненты, только если rehydrate равно true: Наконец, поместим компонент <App /> внутрь компонента <Rehydrated />, чтобы предотвратить вывод приложения до окончания регидрации: Уфф. Теперь приложение будет беспечно ждать, пока Redux Offline восстановит хранилище из localStorage, и только потом продолжит отрисовку и будет делать все последующие запросы или мутации GraphQL. Есть несколько странностей и требующих пояснения вещей при использовании Redux Offline вместе с клиентом Apollo. Во-первых, надо заметить, что в примерах этой статьи используется версия 1.9.0-0 пакета apollo-client. Для Apollo Client версии 1.9 заявлены исправления некоторых странных проявлений при работе с Redux Offline.  Другая странность этой пары в том, что Redux Offline, кажется, не слишком хорошо уживается с Apollo Client Devtools. Попытки использовать Redux Offline с установленным Devtools иногда приводят к неожиданным и, казалось бы, бессвязным ошибкам. Такие ошибки можно легко исключить, если при создании Apollo client не подключать его к Devtools. Redux Offline дает приложению на Apollo основые механизмы для выполнения запросов даже при перезагрузке приложения после отключения от сервера. Через неделю погрузимся в обработку офлайновых мутаций с помощью Redux Offline. Будьте на связи! Перевод статьи. Автор оригинала Pete Corey. frontend