0

Using react 17 and relay-modern 11 I want to build a list, with which, when one reaches the end, they can click a button that says load more and it adds more entries to the list. Here is what I have so far. The rows are name and cursor

enter image description here

see I should click load more and it should add an extra 5 rows of data. This is what happens when I click load more

enter image description here

See it did fetch 5 new nodes. I can tell because the cursors are unique. However it did not append it to the list like I wanted.

How can I get this list to continue to build all the time as I keep clicking load more, until there is no more data?

Here is my code:

the root of the component:

// index.js
import React, { useState } from "react";
import { Text, View } from "react-native";
import { QueryRenderer, useRelayEnvironment } from "react-relay";
import PaginatedProfilesListContainer from "./PaginatedProfilesListContainer";

const ProfilesList = () => {
  const environment = useRelayEnvironment();
  const [count, setCount] = useState(5);
  const [name, setName] = useState("");

  const query = graphql`
    query ProfilesListQuery(
      $count: Int!
      $cursor: String
      $filter: ProfileFilter
    ) {
      ...PaginatedProfilesListContainer_list
    }
  `;

  const filter = {
    name,
  };
  const variables = {
    count: 5,
    cursor: null,
    filter,
  };

  const render = ({ error, props, retry }) => {
    if (error) {
      return (
        <View>
          <Text>{error.message}</Text>
        </View>
      );
    } else if (props) {
      return (
        <View>
          <PaginatedProfilesListContainer
            pagination={props}
            count={count}
            setCount={setCount}
            name={name}
            setName={setName}
            filter={filter}
          />
        </View>
      );
    } else {
      return (
        <View>
          <Text>loading profiles list...</Text>
        </View>
      );
    }
  };
  console.log("vriable", variables)

  return (
    <QueryRenderer
      environment={environment}
      query={query}
      variables={variables}
      render={render}
    />
  );
};

export default ProfilesList;

here is the component that should be listing the object

// PaginatedProfilesListContainer.js
import React from "react";
import { Text, View } from "react-native";
import { Button } from "react-native-paper";
import { createPaginationContainer } from "react-relay";
import { FadoTextInput } from "../forms/fadoTextInput";

const PaginatedProfilesListContainer = (props) => {
  console.log(props);
  console.log("createPaginationContainer", createPaginationContainer)
  // console.log(pagination)
  const { pagination, count, setCount, name, setName, relay, filter } = props;
  const { hasMore, loadMore, refetchConnection } = relay;
  console.log(loadMore)
  const { profiles } = pagination;
  const { edges, pageInfo } = profiles;
  return (
    <View>
      <View>
        <FadoTextInput
          dense={true}
          isNumeric={true}
          graphqlErrors={[]}
          label="count"
          errorKey="count"
          // savedValue={price.amount}
          value={count}
          onChangeText={setCount}
        />
        <FadoTextInput
          dense={true}
          isNumeric={false}
          graphqlErrors={[]}
          label="name"
          errorKey="name"
          // savedValue={price.amount}
          value={name}
          onChangeText={setName}
        />
      </View>
      {edges.map(({ cursor, node: { name } }) => (
        <View key={cursor} style={{ display: "flex", flexDirection: "row"}}>
          <Text>{name}</Text>
          <Text>{cursor}</Text>
        </View>
      ))}
      <Button disabled={!hasMore()} onPress={() => loadMore(count, (error) => { error &&  console.log("error", error); })}>
        Load More
      </Button>
    </View>
  );
};
export default createPaginationContainer(
  PaginatedProfilesListContainer,
  {
    pagination: graphql`
      fragment PaginatedProfilesListContainer_list on RootQueryType {
        profiles(first: $count, after: $cursor, filter: $filter)
          @connection(key: "PaginatedProfilesListContainer_profiles") {
          pageInfo {
            endCursor
            hasNextPage
            hasPreviousPage
            startCursor
          }
          edges {
            cursor
            node {
              name
            }
          }
        }
      }
    `,
  },
  {
    direction: 'forward',
    query: graphql`
      query PaginatedProfilesListContainerQuery(
        $count: Int!
        $cursor: String
        $filter: ProfileFilter
      ) {
        ...PaginatedProfilesListContainer_list
      }
    `,
    getConnectionFromProps(props) {
      console.log(props)
      return props.pagination?.profiles
    },
    getFragmentVariables(prevVars, totalCount) {
      return {
        ...prevVars,
        count: totalCount,
      };
    },
    getVariables(props, { count, cursor }, fragmentVariables) {
      return {
        count,
        cursor,
        filter: {},
      };
    },
  }
);

I got the inspiration for this approach from https://github.com/facebook/relay/issues/1705

Note: I tried to use the @stream_connection, but the Elixir Absinthe on the backend doesn't seem tpo support it.

I know this is long so please any help appreciated :)

Joey Gough
  • 2,753
  • 2
  • 21
  • 42
  • Are you sure of `return props.pagination?.profiles` in `getConnectionFromProps` method it should not be something like `return props.profiles`? Because I've got exactly the same queries as yours but the only difference is this line. – antoineso Mar 13 '21 at 09:21
  • 1
    And to fix all pagination issues with relay I use this [usePagination](https://github.com/relay-tools/relay-hooks/blob/master/docs/usePagination.md) hooks from relay hook package. – antoineso Mar 13 '21 at 09:28
  • is this going to give me the infinite scroll effect I am looking for, or actual pagination? .. thanks btw – Joey Gough Mar 22 '21 at 16:25
  • 1
    to trig the loadMore function from usePagination I made a function like this: `const handleScrollForPagination = (e: any) => { if ( e.target.scrollTop > 0 && Math.ceil(e.target.scrollTop + e.target.clientHeight) >= e.target.scrollHeight ) { loadMore(); } };` so when you are near the bottom of your scroll bar the loadMore() methos is called. And I add it to the `onScroll`props of the pagination container – antoineso Mar 22 '21 at 16:33
  • 1
    thanks a millioin. I finally got it working.... this link also helped for anyone else who is researching this https://github.com/facebook/relay/issues/2938#issuecomment-552888060 – Joey Gough Mar 23 '21 at 23:08

0 Answers0