АполлонПотребитель и кеш

В настоящее время я использую React и Graphql с Apollo и react-apollo. Когда я хочу загрузить данные из Graphql, я обычно использую компонент <Query> из response-apollo, но если я хочу вызвать после события, такого как щелчок, насколько я знаю, мне нужно сделать это с помощью ApolloConsumer и client.query.

Но при этом, когда кеш обновляется или сбрасывается, все, что было загружено через ApolloConsumer, не обновляется. Вот пример:

import React, { Component } from "react";
import { render } from "react-dom";

import ApolloClient from "apollo-boost";
import { ApolloProvider, ApolloConsumer, Query } from "react-apollo";
import gql from "graphql-tag";

const client = new ApolloClient({
  uri: `https://m08pj5j9k9.lp.gql.zone/graphql`
});

class App extends Component {
  state = { client: [] };

  renderQuery = () => {
    return (
      <Query query = {gql`{test01 {id, name}}`}>
        {({ loading, error, data }) => {
          if (loading) return "Loading...";
          if (error) return "Error";

          return (
            <ul>
              {data.test01.map(data => <li key = {data.id}>{data.name}</li>)}
            </ul>
          );
        }}
      </Query>
    );
  };

  btnQueryClick = async client => {
    const data = await client.query({ query: gql`{test02 {id, name}}` });
    this.setState({ client: data.data.test02 });
  };

  render() {
    return (
      <ApolloProvider client = {client}>
        <div>
          <h2>Query test</h2>
          {this.renderQuery()}

          <ApolloConsumer>
            {client => (
              <div>
                <h2>Client query test</h2>
                <button onClick = {() => this.btnQueryClick(client)}>
                  Test!
                </button>
                <ul>
                  {this.state.client.map(data => (
                    <li key = {data.id}>{data.name}</li>
                  ))}
                </ul>

                <h2>Store reset</h2>
                <button
                  onClick = {() => {
                    client.resetStore();
                  }}
                >
                  {" "}
                  Reset!
                </button>
              </div>
            )}
          </ApolloConsumer>
        </div>
      </ApolloProvider>
    );
  }
}

render(<App />, document.getElementById("root"));

А вот ссылка, чтобы попробовать вживую: https://codesandbox.io/s/5460952y3k

Во всех запросах я добавил случайное число, поэтому я знаю, изменились ли данные. Как видите, данные в разделе «Тест запроса» будут обновлены, если я нажму кнопку сброса, но не данные в разделе «Тест запроса клиента».

Есть ли способ имитировать такие же обновления с ApolloConsumer?

Спасибо

Причина, по которой данные остаются, заключается в том, что вы сохраняете их в состоянии при вызове this.setState({ client: data.data.test02 });. Когда вы сбрасываете хранилище, данных больше не будет в кеше, но они все равно будут в состоянии компонента. Вы можете обойти это, вручную сбросив состояние компонента, нажав кнопку сброса.

TLadd 21.09.2018 23:23

@TLadd, но даже если я не сохранил данные в состоянии, если я посмотрю на сетевые вкладки в браузере, я вижу, что test01 обновляется только после того, как я сбросил хранилище.

Etienne 22.09.2018 00:05
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
2
2 223
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Да, я думаю, что для вашего конкретного случая использования client.query, вероятно, не подходит. Вот код, в котором, как мне кажется, вы ищете: https://codesandbox.io/s/yw779qx8qv

И источник:

import React, { Component } from "react";
import { render } from "react-dom";

import ApolloClient from "apollo-boost";
import { ApolloProvider, ApolloConsumer, Query } from "react-apollo";
import gql from "graphql-tag";

const client = new ApolloClient({
  uri: `https://m08pj5j9k9.lp.gql.zone/graphql`
});

class App extends Component {
  state = { showOtherQuery: false };

  renderQuery = () => {
    return (
      <Query query = {gql`{test01 {id, name}}`}>
        {({ loading, error, data }) => {
          if (loading) return "Loading...";
          if (error) return "Error";

          return (
            <ul>
              {data.test01.map(data => <li key = {data.id}>{data.name}</li>)}
            </ul>
          );
        }}
      </Query>
    );
  };

  renderOtherQuery() {
    return (
      <Query query = {gql`{test02 {id, name}}`}>
        {({ loading, error, data }) => {
          if (loading) return "Loading...";
          if (error) return "Error";

          return (
            <ul>
              {data.test02.map(data => <li key = {data.id}>{data.name}</li>)}
            </ul>
          );
        }}
      </Query>
    );
  }

  render() {
    return (
      <ApolloProvider client = {client}>
        <div>
          <h2>Query test</h2>
          {this.renderQuery()}

          <div>
            <h2>Client query test</h2>
            <button onClick = {() => this.setState({ showOtherQuery: true })}>
              Test!
            </button>
            {this.state.showOtherQuery && this.renderOtherQuery()}

            <h2>Store reset</h2>
            <button
              onClick = {() => {
                client.resetStore();
              }}
            >
              {" "}
              Reset!
            </button>
          </div>
        </div>
      </ApolloProvider>
    );
  }
}

render(<App />, document.getElementById("root"));

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

Альтернативой является ручной вызов client.query и повторная установка состояния (что в основном и делает компонент Query) при нажатии кнопки сброса.

Вы не можете ожидать автоматического обновления запросов, запускаемых вручную.

Даже повторно отображаемый (если это произошло, но это не так) потребитель не будет «обновлять» событие, а затем не запрашивать, не обновлять состояние (и представление).

Запрос не создает никаких наблюдаемых - вы, вероятно, хотите смешивать ручные запросы с подписками.

Почему вам нужно следить за другими обновлениями кеша?

Попробуйте использовать «традиционные» HOC Apollo и сочинить - IMHO намного более читабельным, управляемым и подходящим для более сложных сценариев.

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