Получение подсчета кэшированных данных без попадания на сервер

Допустим, у меня есть следующий компонент React:

import { Query } from 'react-apollo'

const MovieListContainer = () => (
  <Query query={QUERY}>
    {
      ({ loading, error, data }) => {
        if (loading) return (<p>Loading...</p>)
        if (error && !data) return (<p>Error...</p>)
        return <MovieList movies={ data.movies }
      }
    }
  </Query>
)

По сути, это используется для получения списка фильмов из кэша GraphQL (при необходимости попадания на сервер) для отображения. Я хочу минимизировать время, когда пользователь увидит экран "Загрузка", поэтому я мог бы сделать что-то подобное при инициализации моего приложения:

import { MOVIE_QUERY } from './queries'

const client = new ApolloClient({
  uri: 'http://example.com:3000/graphql'
})
// Query the movies immediately, and refresh every 30 seconds
client.query({ query: MOVIE_QUERY })
client.watchQuery({query: MOVIE_QUERY }, pollInterval: 30000)

const App = () => (
  <ApolloProvider client={client}>
    <Layout />
  </ApolloProvider>
)

Это хорошо работает. Проблема в том, что теперь, скажем, я хочу сделать еще один компонент, который отображает количество фильмов в списке....

const MovieTab = ({ count }) => {
  <Tab>
    <span>Movies</span>
    <Badge>{ count }</Badge>
  </Tab>
}

Как создать контейнер для подключения MovieTab до кэша Apollo, чтобы получить список фильмов, не вызывая попадания в базу данных (при необходимости отображая знак "??")? Некоторые вещи, которые я пробовал:

  • Оберните это в Queryгде запрос просто что-то вроде movies { id }, Я отправил это как ответ, но я все еще не без ума от этого.
  • Оберните это в Queryгде запрос MOVIE_QUERY. Кажется, идет вразрез с идеей использования GraphQL, чтобы получить только необходимые данные.
  • Оберните его в ApolloConsumer, чтобы получить доступ к клиенту, затем позвоните readQuery чтобы получить список фильмов. Это гарантирует, что я не попаду в базу данных, но не сработает, пока кэш не заполнится данными.

2 ответа

Вот как я сейчас это делаю:

const QUERY = gql`
movies { id }
`

const MovieTabContainer = () => (
  <Query query={ QUERY } fetchPolicy='cache-only'>
    ({ data }) => {
      const count = data.movies ? data.movies.length : '??'
      return (
        <MovieTab count={ count } />
      )
    }
  </Query>
)

Указав, что политика выборки только для кэша, мы сразу передадим data (который будет пустым объектом). Мы можем принять это как признак того, что еще не знаем счет. Как только кеш будет заполнен путем выполнения полного запроса фильма, компонент MovieTab будет перерисован для включения фактической длины.

Если запрос уже получен в другом месте, я думаю, используя MOVIE_QUERY с cache-only это хороший и простой обходной путь. Предполагая, что у вас нет доступа к общедоступному API или, по крайней мере, вы можете контролировать то, как разработан API, самое чистое решение на самом деле может быть серверным.

Вместо того, чтобы структурировать вашу схему следующим образом:

type Query {
  movies: [Movies!]!
}

вместо этого вы можете смешать некоторые метаданные, как минимум, примерно так:

type Query {
  movies: QueryResult
}

type QueryResult {
  total: Int
  items: [QueryItem!]!
}

union QueryItem = Movie | Actor | Director

Это позволило бы вам запросить ваш кеш для общего количества напрямую.

Другие вопросы по тегам