Relay: Proposal: Add `refresh` method on QueryRenderer

Created on 20 Sep 2019  路  3Comments  路  Source: facebook/relay

Problem

It can be useful sometimes to refresh the data from outside a QueryRenderer using a ref. Currently refreshing is only possible from inside a RefetchContainer. In my case I use this to refetch data when the app comes in foreground. This is done in a simple component that wraps QueryRenderer and subscribe to app state changes.

Proposal

Add a refresh method on the QueryRenderer component. This would simply call the query fetcher with the current query and variables to fetch it again. This would not cause the component to change to a loading state. It would keep rendering its current content until we get new data.

Implementation

This is the current implementation I've been using:

  refresh(): void {
    const { query, environment, variables, cacheConfig } = this.props;
    if (!query) {
      return;
    }
    const { queryFetcher, retryCallbacks } = this.state;
    const request = getRequest(query);
    const operation = createOperationDescriptor(request, variables);
    queryFetcher.fetch({
      cacheConfig,
      environment,
      onDataChange: retryCallbacks.handleDataChange,
      operation,
    });
  }

Most helpful comment

In general we're planning to move away from the QueryRenderer/useQuery pattern, which we're referring to as "fetch-on-render". This design makes behavior unpredictable (rendering can happen arbitrarily due to changes in parent components, suspense can cause re-renders and doesn't guarantee cleanup). The alternative is "fetch-then-render" - perform your data-fetching based on some event (user interaction, navigation, timer, app initialization) and then consume that result during render. Then "how do i refetch?" has the same answer as "how do i fetch?". Expect to see more API changes in this direction.

All 3 comments

I am correct in assuming you are suggesting we add a method to the QueryRenderer which is only callable using refs? If so I must admit I'm not in love with that kind of design.

One alternative (I'm sure there's many more) would be to supply a refresh method to the render function.

With all that said, I can't help but think that it should be trivial to implement this using a refetch container as the outermost container - which can simply reissue the same query. Any thoughts on this?

In general we're planning to move away from the QueryRenderer/useQuery pattern, which we're referring to as "fetch-on-render". This design makes behavior unpredictable (rendering can happen arbitrarily due to changes in parent components, suspense can cause re-renders and doesn't guarantee cleanup). The alternative is "fetch-then-render" - perform your data-fetching based on some event (user interaction, navigation, timer, app initialization) and then consume that result during render. Then "how do i refetch?" has the same answer as "how do i fetch?". Expect to see more API changes in this direction.

@josephsavona Thanks for clarifying. I started using the new hooks api and implementing this in userland is trivial.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

HsuTing picture HsuTing  路  3Comments

jstejada picture jstejada  路  3Comments

sibelius picture sibelius  路  3Comments

johntran picture johntran  路  3Comments

amccloud picture amccloud  路  3Comments