首页 文章

如何在新的订阅到达react-apollo时重新获取查询

提问于
浏览
2

我想知道当订阅接收到新数据时,是否有一种优雅的方法可以在react-apollo中触发重新获取查询(这里的数据并不重要,并且与前一个数据相同) . 我只是在这里使用订阅作为通知触发器,告诉Query重新获取 .

我尝试使用Subscription组件和subscribeToMore来调用Query的子组件中的“refetch”方法,但这两种方法都会导致无限次重新提取 .

注意:我正在使用react-apollo v2.1.3和apollo-client v2.3.5

这是代码的简化版本

<Query
  query={GET_QUERY}
  variables={{ blah: 'test' }}
>
  {({ data, refetch }) => (
    <CustomComponent data={data} />
    //put subscription here? It'll cause infinite re-rendering/refetch loop
  )}
<Query>

2 回答

  • 2

    如果在Subscription渲染道具功能渲染的组件中使用 componentDidMountcomponentDidUpdate ,则可以使用 .

    该示例使用 recompose 更高阶的组件来避免过多的电镀设备 . 看起来像:

    /*
     * Component rendered when there's data from subscription
     */
    export const SubscriptionHandler = compose(
      // This would be the query you want to refetch
      graphql(QUERY_GQL, { 
        name: 'queryName'
      }),
      lifecycle({
    
        refetchQuery() {
          // condition to refetch based on subscription data received
          if (this.props.data) {  
            this.props.queryName.refetch()
          }
        },
    
        componentDidMount() {
          this.refetchQuery();
        },
    
        componentDidUpdate() {
          this.refetchQuery();
        }
      })
    )(UIComponent);
    
    
    /*
     * Component that creates the subscription operation
     */
    const Subscriber = ({ username }) => {
      return (
        <Subscription
          subscription={SUBSCRIPTION_GQL}
          variables={{ ...variables }}
        >
          {({ data, loading, error }) => {
            if (loading || error) {
              return null;
            }
            return <SubscriptionHandler data={data} />;
          }}
        </Subscription>
      );
    });
    

    完全分离查询和订阅组件的另一种方法是,在重新渲染时避免循环使用Apollo Automatic Cache updates

    +------------------------------------------+
                     |                                          |
        +----------->|  Apollo Store                            |
        |            |                                          |
        |            +------------------------------+-----------+
        +                                           |
    client.query                                    |
        ^            +-----------------+  +---------v-----------+
        |            |                 |  |                     |
        |            | Subscription    |  | Query               |
        |            |                 |  |                     |
        |            |                 |  | +-----------------+ |
        |            |  renderNothing  |  | |                 | |
        +------------+                 |  | | Component       | |
                     |                 |  | |                 | |
                     |                 |  | +-----------------+ |
                     |                 |  |                     |
                     +-----------------+  +---------------------+
    
    const Component =() => (
      <div>
        <Subscriber />
        <QueryComponent />
      </div>
    )
    
    /*
     * Component that only renders Query data 
     * updated automatically on query cache updates thanks to 
     * apollo automatic cache updates
     */
    const QueryComponent = graphql(QUERY_GQL, { 
      name: 'queryName'
    })(() => {  
      return (
        <JSX />
      );
    });
    
    /*
     * Component that creates the subscription operation
     */
    const Subscriber = ({ username }) => {
      return (
        <Subscription
          subscription={SUBSCRIPTION_GQL}
          variables={{ ...variables }}
        >
          {({ data, loading, error }) => {
            if (loading || error) {
              return null;
            }
            return <SubscriptionHandler data={data} />;
          }}
        </Subscription>
      );
    });
    
    /*
    * Component rendered when there's data from subscription
    */
    const SubscriptionHandler = compose(
    
      // This would be the query you want to refetch
      lifecycle({
    
        refetchQuery() {
          // condition to refetch based on subscription data received
          if (this.props.data) {  
            var variables = {
                ...this.props.data // if you need subscription data for the variables
            };
    
            // Fetch the query, will automatically update the cache
            // and cause QueryComponent re-render
            this.client.query(QUERY_GQL, {
              variables: {
                ...variables
              }
            });
          }
        },
    
        componentDidMount() {
          this.refetchQuery();
        },
    
        componentDidUpdate() {
          this.refetchQuery();
        }
      }),        
      renderNothing
    )();
    
    
    /*
    * Component that creates the subscription operation
    */
    const Subscriber = ({ username }) => {
        return (
            <Subscription
            subscription={SUBSCRIPTION_GQL}
            variables={{ ...variables }}
            >
            {({ data, loading, error }) => {
                if (loading || error) {
                return null;
                }
                return <SubscriptionHandler data={data} />;
            }}
            </Subscription>
        );
    });
    

    注意: composelifecyclerecompose方法,可以更轻松地实现更清晰的高阶组合 .

  • 2

    最后,我从佩德罗的回答中得到了灵感 .

    Thoughts: 问题我在订阅中使用了'm facing is that I want to call Query'的重新获取方法,但是,查询和订阅组件都只能在render方法中访问 . 这是无限重新/重新渲染的根本原因 . 为了解决这个问题,我们需要将订阅逻辑从render方法中移出并将其放在生命周期方法(即componentDidMount)中的某个位置,在触发重新获取后不会再次调用它 . 然后我决定使用graphql hoc而不是Query组件,这样我就可以在我的组件的顶层注入像reetch,subscribeToMore这样的道具,这使得它们可以从任何生命周期方法中访问 .

    Code sample (简化版):

    class CustomComponent extends React.Component {
      componentDidMount() {
        const { data: { refetch, subscribeToMore }} = this.props;
    
        this.unsubscribe = subscribeToMore({
          document: <SUBSCRIBE_GRAPHQL>,
          variables: { test: 'blah' },
          updateQuery: (prev) => {
            refetch();
            return prev;
          },     
        });
      }
    
      componentWillUnmount() {
        this.unsubscribe();
      }
    
      render() {
        const { data: queryResults, loading, error } } = this.props;
    
        if (loading || error) return null;
    
        return <WhatEverYouWant with={queryResults} />
      }
    }
    
    export default graphql(GET_QUERY)(CustomComponent);
    

相关问题