PaginationContainer

PaginationContainer 旨在简化在列表中加载更多项目的工作流程 - 在许多情况下,我们不想立即获取所有数据,而是延迟加载更多数据。它依赖于以标准化方式暴露连接的GraphQL服务器。有关详情,请查看 此页面

this.props.relay 公开以下API:

type Variables = {[name: string]: any};
type RefetchOptions = {
  force?: boolean, // Refetch from the server ignoring anything in the cache.
};
type Disposable = {
  dispose(): void,
};

/**
 * Check if there is at least one more page.
 */
hasMore: () => boolean,

/**
 * Check if there are pending requests.
 */
isLoading: () => boolean,

/**
 * Execute the pagination query. Relay will infer the pagination direction (either 'forward'
 * or 'backward') from the query parameters. `pageSize` is the additional number of items
 * to load.
 */
loadMore: (
  pageSize: number,
  callback: ?(error: ?Error) => void,
  options: ?RefetchOptions
) => ?Disposable,

/**
 * Refetch the items in the connection (with potentially new variables).
 */
refetchConnection:(
  totalCount: number,
  callback: (error: ?Error) => void,
  refetchVariables: ?Variables,
) => ?Disposable,

@connection 指令 #

分页容器期望连接字段使用@connection(key: ...) 指令进行注释,其中 key 期望在父User类下是唯一字段标识符 。 一个好的做法可以是 <ComponentName>_<fieldName | fieldAlias>。默认情况下,Relay根据用户提供的 key 和该字段的所有非过滤变量生成存储密钥。Relay 还提供了一个高级功能 @connection(key: 'FriendsList_friends', filters:['orderBy', ...]) ,允许您明确指定应使用哪些变量来生成存储键。特别是,如果你写 @connection(key: ..., filters:[]), Relay 会忽略所有的变量。

graphql`
  fragment Feed_user on User {
    feed(first: $count, after: $cursor) @connection(key: "Feed_feed") {
      edges {
        node {
          id,
          ...Story_story
        }
    }
  }
`,

示例 #

const {
  createPaginationContainer,
  graphql,
} = require('react-relay');

class Feed extends React.Component {
  render() {
    return (
      <div>
        {this.props.user.feed.edges.map(
          edge => <Story story={edge.node} key={edge.node.id} />
        )}
        <button
          onPress={() => this._loadMore()}
          title="Load More"
        />
      </div>
    );
  }

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

    this.props.relay.loadMore(
      10, // Fetch the next 10 feed items
      e => {
        console.log(e);
      },
    );
  }
}

module.exports = createPaginationContainer(
  Feed,
  {
    user: graphql`
      fragment Feed_user on User {
        feed(
          first: $count
          after: $cursor
          orderby: $orderBy # other variables
        ) @connection(key: "Feed_feed") {
          edges {
            node {
              id
              ...Story_story
            }
          }
        }
      }
    `,
  },
  {
    direction: 'forward',
    getConnectionFromProps(props) {
      return props.user && props.user.feed;
    },
    getFragmentVariables(prevVars, totalCount) {
      return {
        ...prevVars,
        count: totalCount,
      };
    },
    getVariables(props, {count, cursor}, fragmentVariables) {
      return {
        count,
        cursor,
        // in most cases, for variables other than connection filters like
        // `first`, `after`, etc. you may want to use the previous values.
        orderBy: fragmentVariables.orderBy,
      };
    },
    query: graphql`
      query FeedPaginationQuery(
        $count: Int!
        $cursor: String
        $orderby: String!
      ) {
        user {
          # You could reference the fragment defined previously.
          ...Feed_user
        }
      }
    `
  }
);