【问题标题】:ApolloConsumer and cacheApollo 消费者和缓存
【发布时间】:2019-02-26 06:43:36
【问题描述】:

我目前正在将 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 模拟相同类型的更新?

谢谢

【问题讨论】:

  • 数据保留的原因是您在调用this.setState({ client: data.data.test02 });时将其存储在状态中。当您重置存储时,数据将不再在缓存中,但仍将处于组件状态。您也可以通过在单击重置按钮时手动重置组件状态来解决此问题。
  • @TLadd 但是即使我没有在状态下存储数据,如果我查看浏览器上的网络选项卡,我只会在重置存储后看到 test01 被重新获取。

标签: reactjs graphql react-apollo


【解决方案1】:

是的,我认为对于您的特定用例,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 手动发出查询,而是设置一个布尔值来呈现一个额外的 Query 组件,然后当商店重置时,它将按照您的预期重新获取。

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

【讨论】:

    【解决方案2】:

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

    即使重新渲染(如果它发生了,但它没有),消费者也不会“重新触发”事件,然后没有请求,也没有状态(和视图)更新。

    查询不会创建任何类型的可观察对象 - 您可能正在寻找将手动查询与订阅混合的方式。

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

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

    【讨论】:

      猜你喜欢
      • 2013-06-18
      • 2016-08-11
      • 2020-10-24
      • 2015-07-16
      • 2021-02-10
      • 2018-01-09
      • 2016-03-31
      • 2017-04-07
      • 1970-01-01
      相关资源
      最近更新 更多