современная ретрансляция бесконечной прокрутки (v11) с использованием контейнера для разбиения на страницы и loadMore

#reactjs #graphql #relay #relaymodern #react-relay

Вопрос:

Используя react 17 и relay-modern 11, я хочу создать список, с помощью которого, когда кто-то дойдет до конца, они могут нажать кнопку с надписью «Загрузить больше», и она добавит больше записей в список. Вот что у меня есть на данный момент. Строки-это имя и курсор

введите описание изображения здесь

смотрите, я должен нажать «Загрузить больше», и он должен добавить дополнительные 5 строк данных. Вот что происходит, когда я нажимаю загрузить больше

введите описание изображения здесь

Смотрите, он получил 5 новых узлов. Я могу сказать это, потому что курсоры уникальны. Однако он не добавил его в список, как я хотел.

Как я могу заставить этот список продолжать создаваться все время, пока я продолжаю нажимать «Загрузить больше», пока больше не останется данных?

Вот мой код:

корень компонента:

 // 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;
 

вот компонент, в котором должен быть указан объект

 // 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 amp;amp;  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: {},
      };
    },
  }
);
 

Я получил вдохновение для этого подхода от https://github.com/facebook/relay/issues/1705

Примечание: Я пытался использовать @stream_connection, но абсент Эликсира на бэкэнде, похоже, не поддерживает его.

Я знаю, что это долго, поэтому, пожалуйста, любая помощь будет оценена по достоинству 🙂

Комментарии:

1. Вы уверены return props.pagination?.profiles , что в getConnectionFromProps методе это не должно быть чем-то подобным return props.profiles ? Потому что у меня точно такие же запросы, как у вас, но разница только в этой строке.

2. И чтобы исправить все проблемы с разбиением на страницы с помощью реле, я использую эти крючки для использования из пакета крючков реле.

3. даст ли это мне эффект бесконечной прокрутки, который я ищу, или фактическую разбивку на страницы? .. кстати, спасибо

4. чтобы отключить функцию loadMore от usePagination, я создал такую функцию: const handleScrollForPagination = (e: any) => { if ( e.target.scrollTop > 0 amp;amp; Math.ceil(e.target.scrollTop e.target.clientHeight) >= e.target.scrollHeight ) { loadMore(); } }; поэтому, когда вы находитесь в нижней части полосы прокрутки, вызывается метод loadMore (). И я добавляю его в onScroll реквизит контейнера для разбиения на страницы

5. огромное спасибо. Я наконец-то заставил его работать…. эта ссылка также помогла всем, кто исследует это github.com/facebook/relay/issues/2938#issuecomment-552888060