Relay: [Modern] Load More is not working, hasMore() keep returning false

Created on 22 May 2017  路  3Comments  路  Source: facebook/relay

i'm currently working on RN using expo, the list just initially fine, until i follow the loadMore tutorial, load more is not working, the hasMore() function returning false, whereas my hasNextPage is true

my home screen has a record list inside it

this is my home

import Expo from 'expo';
import React, {Component} from 'react';
import {
  View,
  Text,
  ActivityIndicator,
  FlatList,
  TouchableOpacity
} from 'react-native';

import {
  Button
} from 'react-native-elements';

import {
  QueryRenderer,
  createPaginationContainer,
  graphql
} from 'react-relay';

import environment from '../createRelayEnvironment';
import DummyList from '../component/dummyList';

class Home extends Component {

  render() {
    return(
      <QueryRenderer
        environment={environment}
        query={graphql`
          query homeQuery(
            $count: Int!
            $cursor: String!
          ) {
            viewer {
              ...dummyList_viewer
            }
          }
        `}
        variables= {{
            count: 5,
            cursor: ''
          }
        }
        render={({error, props, retry}) => {
          if(props){
            return(
              <DummyList {...props} />
            );
          }

          return(
            <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
              <ActivityIndicator size="large" />
            </View>
          );
        }}
      />
    );
  }
}

export default Home;

this is my inner list child component

import Expo from 'expo';
import React, {Component} from 'react';
import {
  View,
  Text,
  FlatList,
  TouchableOpacity
} from 'react-native';

import {
  createPaginationContainer,
  graphql
} from 'react-relay';

class DummyList extends Component {
  renderItem(item) {
    return(
      <View style={{padding: 10}}>
        <Text key={item.node.id}>{item.node.title}</Text>
      </View>
    );
  }

  _loadMore() {
    console.log('this.props.relay.hasMore()', this.props.relay.hasMore());
    if(!this.props.relay.hasMore() || this.props.relay.isLoading()){
      return;
    }

    this.props.relay.loadMore(
      10,
      e => {
        console.log('e', e);
      }
    )
  }

  render() {
    console.log('apa aja nih props-nya', this.props);
    return(
      <View>
        <FlatList
          data={this.props.viewer.allDummies.edges}
          renderItem={({item}) => this.renderItem(item)}
          keyExtractor={(item, index) => item.node.id}
        />
        <TouchableOpacity style={{padding: 10}} onPress={() => this._loadMore()}>
          <Text>Load More</Text>
        </TouchableOpacity>
      </View>
    )
  }
}

export default createPaginationContainer(
  DummyList,
  {
    viewer: graphql`
      fragment dummyList_viewer on viewer {
        allDummies(first: $count, after: $cursor) @connection(key: "DummyList_allDummies"){
          pageInfo{
            hasNextPage
          }
          edges{
            cursor
            node {
              id
              title
            }
          }
        }
      }
    `
  },
  {
    direction: 'forward',
    getConnectionFromProps(props) {
      console.log('getConnectionFromProps props', props);
      return props.viewer;
      // return props.user && props.user.feed;
    },
    getFragmentVariables(prevVars, totalCount) {
      return {
        ...prevVars,
        count: totalCount
      }
    },
    getVariables(props, { count, cursor }, fragmentVariables) {
      return {
        count,
        cursor
      }
    },
    query: graphql`
      query dummyListQuery(
        $count: Int!
        $cursor: String
      ){
        viewer{
          ...dummyList_viewer
        }
      }
    `
  }
);

i couldn't find the reason why my hasMore() keep returning false, i have 1000 records FYI, and initially load 5

capture_1

Most helpful comment

actually the solution is very simple, i need to change

getConnectionFromProps(props) {
      console.log('getConnectionFromProps props', props);
      return props.viewer;
      // return props.user && props.user.feed;
    }

to

getConnectionFromProps(props) {
      console.log('getConnectionFromProps props', props);
      return props.viewer. allDummies;
      // return props.user && props.user.feed;
    }

i got the clue from _getConnectionData from ReactRelayPaginationContainer.js

@decebal my createRelayEnvironment

const {
  Environment,
  Network,
  RecordSource,
  Store
} = require('relay-runtime');

import {
  AsyncStorage
} from 'react-native';

// const auth_token = async() => {
//   await AsyncStorage.getItem('@authToken');
// }

const fetchQuery = async(operation, variables) => {
  const auth_token = await AsyncStorage.getItem('@authToken');

  return fetch('http://localhost:3000/graphql',{
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
      'Authorization': auth_token
    },
    body: JSON.stringify({
      query: operation.text,
      variables
    }),
  }).then(response => response.json());
}

const network = Network.create(fetchQuery);

const source = new RecordSource();
const store = new Store(source);

export default new Environment({
  network,
  store
});

All 3 comments

could you share your 'createRelayEnvironment' file, in my case I was using the modern setup which lead to some issues due to it's instability. RC3 fixed some of them.

actually the solution is very simple, i need to change

getConnectionFromProps(props) {
      console.log('getConnectionFromProps props', props);
      return props.viewer;
      // return props.user && props.user.feed;
    }

to

getConnectionFromProps(props) {
      console.log('getConnectionFromProps props', props);
      return props.viewer. allDummies;
      // return props.user && props.user.feed;
    }

i got the clue from _getConnectionData from ReactRelayPaginationContainer.js

@decebal my createRelayEnvironment

const {
  Environment,
  Network,
  RecordSource,
  Store
} = require('relay-runtime');

import {
  AsyncStorage
} from 'react-native';

// const auth_token = async() => {
//   await AsyncStorage.getItem('@authToken');
// }

const fetchQuery = async(operation, variables) => {
  const auth_token = await AsyncStorage.getItem('@authToken');

  return fetch('http://localhost:3000/graphql',{
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
      'Authorization': auth_token
    },
    body: JSON.stringify({
      query: operation.text,
      variables
    }),
  }).then(response => response.json());
}

const network = Network.create(fetchQuery);

const source = new RecordSource();
const store = new Store(source);

export default new Environment({
  network,
  store
});

Also, make sure to include pageInfo explicitly as part of your query.

          pageInfo{
            endCursor
            hasNextPage
          }
Was this page helpful?
0 / 5 - 0 ratings