ApolloConsumer и кеш

В настоящее время я использую React и Graphql с Apollo и react-apollo. Когда я хочу загрузить данные из Graphql, я обычно использую компонент ‹ Query > из react-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?

Спасибо


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


Ответы (2)


Да, я думаю, что для вашего конкретного случая использования client.query, вероятно, не подходит. Вот codepen, в котором есть то, что, я думаю, вы ищете: 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) при нажатии кнопки сброса.

person TLadd    schedule 21.09.2018

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

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

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

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

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

person xadm    schedule 22.09.2018