Relay: Use RefetchContainer to implement pull-to-refresh without variable change

Created on 28 Jul 2017  Â·  7Comments  Â·  Source: facebook/relay

I'm trying to find out how/if it is possible to trigger a refresh in a Relay Modern RefreshContainer without passing (new) variables?

I’m looking for a way to implement the good ol’ pull-to-refresh on a React Native list, that should simply refetch the original query - no variables needed?

According to docs (https://facebook.github.io/relay/docs/api-cheatsheet.html) this should be possible using

this.props.relay.refetch({}, callback, {force: true})

but I get an error saying "undefined is not an object ('evaluating taggedNode.modern')"

Is it not possible to force a refetch without a variable change? If not, consider this a feature request :-)

Most helpful comment

You need the third argument to createRefetchContainer to provide the query to be executed when refetch is called. It should look something like this:

export default createRefetchContainer(
  HistoryList,
  {
    entries: graphql`
      fragment HistoryList_entries on Viewer {
        allJournalEntries(orderBy: huntDate_DESC) {
          count
          edges {
            node {
              huntDate
              ...HistoryListItem_item
            }
          }
        }
      }
    `
  },
  graphql`
    query HistoryListRefetchQuery {
      viewer {
        ...HistoryList_entries
      }
    }
  `
);

All 7 comments

It looks like Relay can't find the query for your refetch container. Did you define one?

Yes :) I should have mentioned, of course, that the fragment and query works just fine if I use a fragmentContainer.

export default createFragmentContainer(MyComponent, graphql 'fragment MyComponent_entries on Viewer { ... } ' );

If I change to refetch-container and use this.props.relay.refetch({}, callback, {force: true}) when pull-to-refresh is activated, I get the error mentioned.

Note that createRefetchContainer requires a third argument: a query to use when refetching the fragment data. See the docs at https://facebook.github.io/relay/docs/refetch-container.html

It seems that the arguments of this.props.relay.refetch has been change to refetch(refetchVariables, renderVariables, callback, options) (in https://facebook.github.io/relay/docs/refetch-container.html). I'm not sure that in which version this has change, but you can give it a try and change your code to this.props.relay.refetch({}, null, callback, {force: true}), it works for me :)

Hey,

Thanks for the suggestion :-) You are totally right, but unfortunately, it doesn't work for me :-/

Here's some more code for clarification. Note that I don't use variables in the query at all - does that matter?

class HistoryList extends React.PureComponent<void, Props, State> {
  state = { refreshing: false };

  _renderRow = ({ item }) => {
    return <HistoryListItem item={item.node} />;
  };

  _renderHeader = ({ section }) => {
    return (
      <Text style={[cs.breadText, _styles.sectionHeader]}>
        {section.title}
      </Text>
    );
  };

  _onRefresh = () => {
    this.setState({ refreshing: true });
    this.props.relay.refetch({}, null, this._onRefreshDone, { force: true });
  };

  _onRefreshDone = () => {
    this.setState({ refreshing: false });
  };

  _sortDataIntoSections = (edges: Array<Node>) => {
    return _.chain(edges)
      .groupBy(element => {
        return moment(element.node.huntDate).format('MMMM YYYY');
      })
      .map((data, key) => {
        return { title: key, data: data };
      })
      .value();
  };

  render() {
    return (
      <View style={_styles.container}>
        <SectionList
          renderSectionHeader={this._renderHeader}
          sections={this._sortDataIntoSections(
            this.props.entries.allJournalEntries.edges
          )}
          renderItem={this._renderRow}
          keyExtractor={(item, index) => item.node.__id}
          onRefresh={this._onRefresh}
          refreshing={this.state.refreshing}
        />
      </View>
    );
  }
}

export default createRefetchContainer(
  HistoryList,
  graphql`
    fragment HistoryList_entries on Viewer {
      allJournalEntries(orderBy: huntDate_DESC) {
        count
        edges {
          node {
            huntDate
            ...HistoryListItem_item
          }
        }
      }
    }
  `
);

You need the third argument to createRefetchContainer to provide the query to be executed when refetch is called. It should look something like this:

export default createRefetchContainer(
  HistoryList,
  {
    entries: graphql`
      fragment HistoryList_entries on Viewer {
        allJournalEntries(orderBy: huntDate_DESC) {
          count
          edges {
            node {
              huntDate
              ...HistoryListItem_item
            }
          }
        }
      }
    `
  },
  graphql`
    query HistoryListRefetchQuery {
      viewer {
        ...HistoryList_entries
      }
    }
  `
);

Thank you very much, @robrichard - that worked beautifully! :-)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MartinDawson picture MartinDawson  Â·  3Comments

HsuTing picture HsuTing  Â·  3Comments

derekdowling picture derekdowling  Â·  3Comments

scotmatson picture scotmatson  Â·  3Comments

johntran picture johntran  Â·  3Comments