Как поддерживать производное состояние в актуальном состоянии с помощью Apollo / GraphQL? - PullRequest
0 голосов
/ 26 мая 2020

Моя ситуация такова: на мой взгляд, у меня есть несколько компонентов, которые в конечном итоге зависят от одних и тех же данных, но в некоторых случаях состояние представления получено из данных. Как мне убедиться, что все мое представление синхронизировано c при изменении базовых данных? Я проиллюстрирую это примером с использованием всеми любимого API Звездных войн .

Сначала я покажу список всех фильмов с таким запросом:

# ALL_FILMS
query {
  allFilms {
    id
    title
    releaseDate
  }
}

Затем я хочу, чтобы в пользовательском интерфейсе был выделен отдельный компонент для выделения самого последнего фильма. Для этого нет запроса, поэтому я реализую его с помощью распознавателя на стороне клиента. Запрос будет выглядеть следующим образом:

# MOST_RECENT_FILM
query {
  mostRecentFilm @client {
    id
    title
  }
}

И преобразователь:

function mostRecentFilmResolver(parent, variables, context) {
    return context.client.query({ query: ALL_FILMS }).then(result => {
        // Omitting the implementation here since it's not relevant
        return deriveMostRecentFilm(result.data);
    })
}

Теперь, когда это становится интересным, когда SWAPI начинает добавлять Последние джедаи и The Rise of Skywalker в его список фильмов. Мы можем предположить, что я опрашиваю в списке, чтобы он периодически обновлялся. Отлично, теперь пользовательский интерфейс моего списка обновлен. Но пользовательский интерфейс моего "последнего фильма" не знает, что что-то изменилось - он все еще застрял в 2015 году, показывая Пробуждение силы , хотя пользователь может ясно видеть, что есть более новые фильмы.

Может я избалован; Я пришел из мира MobX , где такие вещи, как это Just Works ™. Но это не такая уж редкая проблема. Есть ли лучшая практика в области Apollo / GraphQL для синхронизации c? Неправильно ли я подхожу к этой проблеме?

Несколько идей, которые у меня возникли:

  • Мой запрос "самого последнего фильма" также может периодически опрашиваться. Но вы не хотите часто опрашивать слишком ; в конце концов, фильмы по «Звездным войнам» выходят примерно раз в два года. (Спасибо, Дисней!) И в зависимости от того, как интервалы опроса перекрываются, все равно будет большое окно, в котором все не синхронизируется c.
  • Вместо этого deriveMostRecentFilm logi c в резолвере , просто поместите его в компонент и поделитесь запросом ALL_FILMS между компонентами. Это сработало бы, но это в основном ответ: «Как мне заставить это работать в Apollo?» с «Не используйте Apollo».
  • Некоторая сложная система отслеживания зависимостей между запросами и цепочкой обновлений на основе этого. (Я не стремлюсь изобретать это, если я могу этого избежать!)

1 Ответ

0 голосов
/ 27 мая 2020

В Apollo наблюдаемые (в компонентах) превышают запрашиваемые значения (кэшированные данные 'слоты'), но ваш mostRecentFilm не является наблюдаемым, не основан на кэшированных значениях (они кэшируются), а на одноразовом результате запроса ( обновляется по запросу).

Вам не хватает только «обновляемого соединения», например:

# ALL_FILMS
query {
  allFilms {
    id
    title
    releaseDate
    isMostRecentFilm @client
  }
}

Используйте isMostRecentFilm локальный преобразователь для обновления mostRecentFilm значения в кеше.

Любой запрос (useQuery), связанный с mostRecentFilm @client, будет обновлен автоматически. Всё без дополнительных запросов, опрос и т.д. c. - Просто работает? (не тестировал, должно работать);)

...