Apollo消费者和缓存

时间:2018-09-21 20:37:03

标签: reactjs graphql react-apollo

我目前正在将React和Graphql与Apollo和react-apollo结合使用。 当我想从Graphql加载数据时,通常使用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模拟相同类型的更新?

谢谢

2 个答案:

答案 0 :(得分:1)

是的,我认为对于您的特定用例,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手动发出查询,而是设置了一个布尔值,该布尔值呈现了一个附加的Query组件,然后将在重置存储时按您的期望进行重新提取。

另一种方法是单击重置按钮时手动调用client.query并再次设置状态(这基本上是Query组件正在做的事情)。

答案 1 :(得分:1)

您不能期望手动触发的查询会自动更新。

即使重新提交(如果发生了,但没有发生),消费者也不会“重新启动”事件,因此不会重新查询,也不会更新状态(和视图)。

查询不会创建任何可观察的内容-您可能正在寻找将手动查询与订阅混在一起的情况。

为什么需要注意其他缓存更新?

尝试使用“传统”阿波罗HOC并编写-IMHO更具可读性,易管理性,并且适合于更复杂的场景。