1"use strict";(self.webpackChunk=self.webpackChunk||[]).push([["15227"],{94801(n,e,i){i.r(e),i.d(e,{metadata:()=>t,default:()=>p,frontMatter:()=>s,contentTitle:()=>r,toc:()=>c,assets:()=>d});var t=JSON.parse('{"id":"guided-tour/list-data/advanced-pagination","title":"Advanced Pagination","description":"Relay guide for advanced pagination","source":"@site/docs/guided-tour/list-data/advanced-pagination.mdx","sourceDirName":"guided-tour/list-data","slug":"/guided-tour/list-data/advanced-pagination/","permalink":"/docs/next/guided-tour/list-data/advanced-pagination/","draft":false,"unlisted":false,"editUrl":"https://github.com/facebook/relay/tree/main/website/docs/guided-tour/list-data/advanced-pagination.mdx","tags":[],"version":"current","frontMatter":{"id":"advanced-pagination","title":"Advanced Pagination","slug":"/guided-tour/list-data/advanced-pagination/","description":"Relay guide for advanced pagination","keywords":["pagination","usePaginationFragment","prefetching"]},"sidebar":"docs","previous":{"title":"Pagination with Connections","permalink":"/docs/next/guided-tour/list-data/pagination/"},"next":{"title":"GraphQL subscriptions","permalink":"/docs/next/guided-tour/updating-data/graphql-subscriptions/"}}'),a=i(74848),o=i(28453);i(86898),i(17352);let s={id:"advanced-pagination",title:"Advanced Pagination",slug:"/guided-tour/list-data/advanced-pagination/",description:"Relay guide for advanced pagination",keywords:["pagination","usePaginationFragment","prefetching"]},r,d={},c=[{value:"Pagination Over Multiple Connections",id:"pagination-over-multiple-connections",level:2},{value:"Bi-directional Pagination",id:"bi-directional-pagination",level:2}];function l(n){let e={a:"a",code:"code",em:"em",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,o.R)(),...n.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsxs)(e.p,{children:["In this section we're going to cover how to implement more advanced pagination use cases than the default cases covered by ",(0,a.jsx)(e.code,{children:"usePaginationFragment"}),"."]}),"\n",(0,a.jsx)(e.h2,{id:"pagination-over-multiple-connections",children:"Pagination Over Multiple Connections"}),"\n",(0,a.jsxs)(e.p,{children:["If you need to paginate over multiple connections within the same component, you can use ",(0,a.jsx)(e.code,{children:"usePaginationFragment"})," multiple times:"]}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsx)(e.code,{className:"language-js",children:"import type {CombinedFriendsListComponent_user$key} from 'CombinedFriendsListComponent_user.graphql';\nimport type {CombinedFriendsListComponent_viewer$key} from 'CombinedFriendsListComponent_viewer.graphql';\n\nconst React = require('React');\n\nconst {graphql, usePaginationFragment} = require('react-relay');\n\ntype Props = {\n user: CombinedFriendsListComponent_user$key,\n viewer: CombinedFriendsListComponent_viewer$key,\n};\n\nfunction CombinedFriendsListComponent(props: Props) {\n\n const {data: userData, ...userPagination} = usePaginationFragment(\n graphql`\n fragment CombinedFriendsListComponent_user on User {\n name\n friends\n @connection(\n key: \"CombinedFriendsListComponent_user_friends_connection\"\n ) {\n edges {\n node {\n name\n age\n }\n }\n }\n }\n `,\n props.user,\n );\n\n const {data: viewerData, ...viewerPagination} = usePaginationFragment(\n graphql`\n fragment CombinedFriendsListComponent_user on Viewer {\n actor {\n ... on User {\n name\n friends\n @connection(\n key: \"CombinedFriendsListComponent_viewer_friends_connection\"\n ) {\n edges {\n node {\n name\n age\n }\n }\n }\n }\n }\n }\n `,\n props.viewer,\n );\n\n return (...);\n}\n"})}),"\n",(0,a.jsx)(e.p,{children:"However, we recommend trying to keep a single connection per component, to keep the components easier to follow."}),"\n",(0,a.jsx)(e.h2,{id:"bi-directional-pagination",children:"Bi-directional Pagination"}),"\n",(0,a.jsxs)(e.p,{children:["In the ",(0,a.jsx)(e.a,{href:"../pagination/",children:"Pagination"})," section we covered how to use ",(0,a.jsx)(e.code,{children:"usePaginationFragment"})," to paginate in a single ",(0,a.jsx)(e.em,{children:'"forward"'})," direction. However, connections also allow paginating in the opposite ",(0,a.jsx)(e.em,{children:'"backward"'})," direction. The meaning of ",(0,a.jsx)(e.em,{children:'"forward"'})," and ",(0,a.jsx)(e.em,{children:'"backward"'})," directions will depend on how the items in the connection are sorted, for example ",(0,a.jsx)(e.em,{children:'"forward"'}),' could mean more recent*, and "backward"* could mean less recent.']}),"\n",(0,a.jsxs)(e.p,{children:["Regardless of the semantic meaning of the direction, Relay also provides the same APIs to paginate in the opposite direction, using ",(0,a.jsx)(e.code,{children:"usePaginationFragment"}),", as long as the ",(0,a.jsx)(e.code,{children:"before"})," and ",(0,a.jsx)(e.code,{children:"last"})," connection arguments are also used along with ",(0,a.jsx)(e.code,{children:"after"})," and ",(0,a.jsx)(e.code,{children:"first"}),":"]}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsx)(e.code,{className:"language-js",children:"import type {FriendsListComponent_user$key} from 'FriendsListComponent_user.graphql';\n\nconst React = require('React');\nconst {Suspense} = require('React');\n\nconst {graphql, usePaginationFragment} = require('react-relay');\n\ntype Props = {\n userRef: FriendsListComponent_user$key,\n};
1\n\nfunction FriendsListComponent(props: Props) {\n const {\n data,\n loadPrevious,\n hasPrevious,\n // ... forward pagination values\n } = usePaginationFragment(\n graphql`\n fragment FriendsListComponent_user on User {\n name\n friends(after: $after, before: $before, first: $first, last: $last)\n @connection(key: \"FriendsListComponent_user_friends_connection\") {\n edges {\n node {\n name\n age\n }\n }\n }\n }\n `,\n userRef,\n );\n\n return (\n <>\n <h1>Friends of {data.name}:</h1>\n <List items={data.friends?.edges.map(edge => edge.node)}>\n {node => {\n return (\n <div>\n {node.name} - {node.age}\n </div>\n );\n }}\n </List>\n\n {hasPrevious ? (\n <Button onClick={() => loadPrevious(10)}>\n Load more friends\n </Button>\n ) : null}\n\n {/* Forward pagination controls can go simultaneously here */}\n </>\n );\n}\n"})}),"\n",(0,a.jsxs)(e.ul,{children:["\n",(0,a.jsxs)(e.li,{children:["The APIs for both ",(0,a.jsx)(e.em,{children:'"forward"'})," and ",(0,a.jsx)(e.em,{children:'"backward"'})," are exactly the same, they're only named differently. When paginating forward, then the ",(0,a.jsx)(e.code,{children:"after"})," and ",(0,a.jsx)(e.code,{children:"first"})," connection arguments will be used, when paginating backward, the ",(0,a.jsx)(e.code,{children:"before"})," and ",(0,a.jsx)(e.code,{children:"last"})," connection arguments will be used."]}),"\n",(0,a.jsxs)(e.li,{children:["Note that the primitives for both ",(0,a.jsx)(e.em,{children:'"forward"'})," and ",(0,a.jsx)(e.em,{children:'"backward"'})," pagination are exposed from a single call to ",(0,a.jsx)(e.code,{children:"usePaginationFragment"}),", so both ",(0,a.jsx)(e.em,{children:'"forward"'})," and ",(0,a.jsx)(e.em,{children:'"backward"'})," pagination can be performed simultaneously in the same component."]}),"\n"]})]})}function p(n={}){let{wrapper:e}={...(0,o.R)(),...n.components};return e?(0,a.jsx)(e,{...n,children:(0,a.jsx)(l,{...n})}):l(n)}},86898(n,e,i){i.d(e,{A:()=>m});var t=i(74848),a=i(95310),o=i(17352),s=i(96540);function r(){let n=window.encodeURI(JSON.stringify({title:"Feedback about "+window.location.pathname,description:"**!!! Required !!!**\n\nPlease modify the task description to let us know how the docs can be improved.\n\n**Please do not ask support questions via this form! Instead, ask in fburl.com/relay_support**",tag_ids:{add:[0xac96423e5b680,0x64079768ac750]}}));window.open("https://www.internalfb.com/tasks/?n="+n)}function d({children:n}){return(0,t.jsxs)("div",{className:"docsRating",id:"docsRating",children:[(0,t.jsx)("hr",{}),n]})}let c=()=>{let[n,e]=s.useState(!1),i=n=>{e(!0),window.ga&&window.ga("send",{hitType:"event",eventCategory:"button",eventAction:"feedback",eventValue:n})};return n?"Thank you for letting us know!":(0,t.jsxs)(t.Fragment,{children:["Is this page useful?",(0,t.jsx)("svg",{className:"i_thumbsup",alt:"Like",id:"docsRating-like",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 81.13 89.76",onClick:()=>i(1),children:(0,t.jsx)("path",{d:"M22.9 6a18.57 18.57 0 002.67 8.4 25.72 25.72 0 008.65 7.66c3.86 2 8.67 7.13 13.51 11 3.86 3.11 8.57 7.11 11.54 8.45s13.59.26 14.64 1.17c1.88 1.63 1.55 9-.11 15.25-1.61 5.86-5.96 10.55-6.48 16.86-.4 4.83-2.7 4.88-10.93 4.88h-1.35c-3.82 0-8.24 2.93-12.92 3.62a68 68 0 01-9.73.5c-3.57 0-7.86-.08-13.25-.08-3.56 0-4.71-1.83-4.71-4.48h8.42a3.51 3.51 0 000-7H12.28a2.89 2.89 0 01-2.88-2.88 1.91 1.91 0 01.77-1.78h16.46a3.51 3.51 0 000-7H12.29c-3.21 0-4.84-1.83-4.84-4a6.41 6.41 0 011.17-3.78h19.06a3.5 3.5 0 100-7H9.75A3.51 3.51 0 016 42.27a3.45 3.45 0 013.75-3.48h13.11c5.61 0 7.71-3 5.71-5.52-4.43-4.74-10.84-12.62-11-18.71-.15-6.51 2.6-7.83 5.36-8.56m0-6a6.18 6.18 0 00-1.53.2c-6.69 1.77-10 6.65-9.82 14.5.08 5.09 2.99 11.18 8.52 18.09H9.74a9.52 9.52 0 00-6.23 16.9 12.52 12.52 0 00-2.07 6.84 9.64 9.64 0 003.65 7.7 7.85 7.85 0 00-1.7 5.13 8.9 8.9 0 005.3 8.13 6 6 0 00-.26 1.76c0 6.37 4.2 10.48 10.71 10.48h13.25a73.75 73.75 0 0010.6-.56 35.89 35.89 0 007.58-2.18 17.83 17.83 0 014.48-1.34h1.35c4.69 0 7.79 0 10.5-1 3.85-1.44 6-4.59 6.41-9.38.2-2.46 1.42-4.85 2.84-7.62a41.3 41.3 0 003.42-8.13 48 48 0 001.59-10.79c.1-5.13-1-8.48-3.35-10.55-2.16-1.87-4.64-1.87-9.6-1.88a46.86 46.86 0 01-6.64-.29c-1.92-.94-5.72-4-8.51-6.3l-1.58-1.28c-1.6-1.3-3.27-2.79-4.87-4.23-3.33-3-6.47-5.79-9.61-7.45a20.2 20.2 0 01-6.43-5.53 12.44 12.44 0 01-1.72-5.36 6 6 0 00-6-5.86z"})}),(0,t.jsx)("svg",{className:"i_thumbsdown",alt:"Dislike",id:"docsRating-dislike",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 81.13 89.76",onClick:()=>i(0),children:(0,t.jsx)("path",{d:"M22.9 6a18.57 18.57 0 002.67 8.4 25.72 25.72 0 008.65 7.66c3.86 2 8.67 7.13 13.51 11 3.86 3.11 8.57 7.11 11.54 8.45s13.59.26 14.64 1.17c1.88 1.63 1.55 9-.11 15.25-1.61 5.86-5.96 10.55-6.48 16.86-.4 4.83-2.7 4.88-10.93 4.88h-1.35c-3.82 0-8.24 2.93-12.92 3.62a68 68 0 01-9.73.5c-3.57 0-7.86-.08-13.25-.08-3.56 0-4.71-1.83-4.71-4.48h8.42a3.51 3.51 0 000-7H12.28a2.89 2.89 0 01-2.88-2.88 1.91 1.91 0 01.77-1.78h16.46a3.51 3.51 0 000-7H12.29c-3.21 0-4.84-1.83-4.84-4a6.41 6.41 0 011.17-3.78h19.06a3.5 3.5 0 100-7H9.75A3.51 3.51 0 016 42.27a3.45 3.45 0 013.75-3.48h13.11c5.61 0 7.71-3 5.71-5.52-4.43-4.74-10.84-12.62-11-18.71-.15-6.51 2.6-7.83 5.36-8.56m0-6a6.18 6.18 0 00-1.53.2c-6.69 1.77-10 6.65-9.82 14.5.08 5.09 2.99 11.18 8.52 18.09H9.74a9.52 9.52 0 00-6.23 16.9 12.52 12.52 0 00-2.07 6.84 9.64 9.64 0 003.65 7.7 7.85 7.85 0 00-1.7 5.13 8.9 8.9 0 005.3 8.13 6 6 0 00-.26 1.76c0 6.37 4.2 10.48 10.71 10.48h13.25a73.75 73.75 0 0010.6-.56 35.89 35.89 0 007.58-2.18 17.83 17.83 0 014.48-1.34h1.35c4.69 0 7.79 0 10.5-1 3.85-1.44 6-4.59 6.41-9.38.2-2.46 1.42-4.85 2.84-7.62a41.3 41.3 0 003.42-8.13 48 48 0 001.59-10.79c.1-5.13-1-8.48-3.35-10.55-2.16-1.87-4.64-1.87-9.6-1.88a46.86 46.86 0 01-6.64-.29c-1.92-.94-5.72-4-8.51-6.3l-1.58-1.28c-1.6-1.3-3.27-2.79-4.87-4.23-3.33-3-6.47-5.79-9.61-7.45a20.2 20.2 0 01-6.43-5.53 12.44 12.44 0 01-1.72-5.36 6 6 0 00-6-5.86z"})})]})},l=()=>(0,t.jsxs)("p",{children:["Let us know how these docs can be improved by",(0,t.jsx)("a",{className:"button",role:"button",tabIndex:0,onClick:r,children:"Filing a task"})]}),p=()=>(0,t.jsxs)("p",{children:["Help us make the site even better by"," ",(0,t.jsx)(a.default,{to:"https://www.surveymonkey.com/r/FYC9TCJ",children:"answering a few quick questions"}),"."]}),u=()=>(0,t.jsxs)(d,{children:[(0,t.jsx)(l,{}),(0,t.jsx)(c,{}),(0,t.jsx)(p,{})]}),g=()=>(0,t.jsxs)(d,{children:[(0,t.jsx)(c,{}),(0,t.jsx)(p,{})]}),m=()=>(0,o.fbContent)({internal:(0,t.jsx)(u,{}),external:(0,t.jsx)(g,{})})},28453(n,e,i){i.d(e,{R:()=>s,x:()=>r});var t=i(96540);let a={},o=t.createContext(a);function s(n){let e=t.useContext(o);return t.useMemo(function(){return"function"==typeof n?n(e):{...e,...n}},[e,n])}function r(n){let e;return e=n.disableParentContext?"function"==typeof n.components?n.components(a):n.components||a:s(n.components),t.createElement(o.Provider,{value:e},n.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.