Hi. I tried using concatPagination, offsetLimitPagination and relayStylePagination to add pagination to my testing/learning (as I am still learning GraphQL) project following this tutorial. But it is not workin.
Intended outcome:
I can successfully paginate my results.
Actual outcome:
All caused an error. There is no documentation on how to use each method properly so maybe I am just using it wrong.
How to reproduce the issue:
Here is my sample code (you can freely changed concatPagination with offsetLimitPagination or relayStylePagination but it will still have an error) :
index.tsx
import React from "react";
import ReactDOM from "react-dom";
import {
ApolloClient,
InMemoryCache,
NormalizedCacheObject,
ApolloProvider,
} from "@apollo/client";
import { concatPagination } from "@apollo/client/utilities";
import Pages from "./pages";
import injectStyles from "./styles";
const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
launches: concatPagination(),
},
},
},
});
const client: ApolloClient<NormalizedCacheObject> = new ApolloClient({
uri: "http://localhost:4000/",
cache,
});
injectStyles();
ReactDOM.render(
<ApolloProvider client={client}>
<Pages />
</ApolloProvider>,
document.getElementById("root")
);
launches.tsx
import React, { Fragment } from "react";
import { gql, useQuery } from "@apollo/client";
import { LaunchTile, Header, Button, Loading } from "../components";
import { RouteComponentProps } from "react-router-dom";
import * as GetLaunchListTypes from "./__generated__/GetLaunchList";
export const LAUNCH_TILE_DATA = gql`
fragment LaunchTile on Launch {
__typename
id
isBooked
rocket {
id
name
}
mission {
name
missionPatch
}
}
`;
const GET_LAUNCHES = gql`
query launchList($after: String) {
launches(after: $after) {
cursor
hasMore
launches {
...LaunchTile
}
}
}
${LAUNCH_TILE_DATA}
`;
interface LaunchesProps extends RouteComponentProps {}
const Launches: React.FC<LaunchesProps> = () => {
const { data, loading, error, fetchMore } = useQuery<
GetLaunchListTypes.GetLaunchList,
GetLaunchListTypes.GetLaunchListVariables
>(GET_LAUNCHES);
if (loading) return <Loading />;
if (error) return <p>ERROR</p>;
if (!data) return <p>Not found</p>;
return (
<Fragment>
<Header />
{data.launches &&
data.launches.launches &&
data.launches.launches.map((launch: any) => (
<LaunchTile key={launch.id} launch={launch} />
))}
{data.launches && data.launches.hasMore && (
<Button
onClick={async () =>
await fetchMore({
variables: {
after: data.launches.cursor,
},
})
}
>
Load More
</Button>
)}
</Fragment>
);
};
export default Launches;
Versions
System:
OS: macOS 10.15.3
Binaries:
Node: 10.19.0 - ~/.nvm/versions/node/v10.19.0/bin/node
Yarn: 1.22.4 - ~/Work-related-tutorials/fullstack-tutorial/start/client/node_modules/.bin/yarn
npm: 6.14.7 - ~/.nvm/versions/node/v10.19.0/bin/npm
Browsers:
Chrome: 84.0.4147.105
Firefox: 70.0.1
Safari: 13.0.5
npmPackages:
@apollo/client: ^3.1.2 => 3.1.2
apollo: ^2.30.2 => 2.30.2
I can fix the pagination with a custom one like this one:
import React from "react";
import ReactDOM from "react-dom";
import {
ApolloClient,
InMemoryCache,
NormalizedCacheObject,
ApolloProvider,
} from "@apollo/client";
import { concat, getOr, isNil } from "lodash/fp";
import Pages from "./pages";
import injectStyles from "./styles";
const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
launches: {
keyArgs: false,
merge: function (existing, incoming) {
if (isNil(existing)) {
return incoming;
} else {
const existingLaunches = getOr([], "launches", existing);
const incomingLaunches = getOr([], "launches", incoming);
const concatenatedLaunches = concat(
existingLaunches,
incomingLaunches
);
return { ...incoming, launches: concatenatedLaunches };
}
},
},
},
},
},
});
const client: ApolloClient<NormalizedCacheObject> = new ApolloClient({
uri: "http://localhost:4000/",
cache,
});
injectStyles();
ReactDOM.render(
<ApolloProvider client={client}>
<Pages />
</ApolloProvider>,
document.getElementById("root")
);
But I think concatPagination needs to be revamp. Can we do it with the code above in mind? Thank you.
Those helpers are not meant to cover all possible pagination use cases, so much as to demonstrate how some common use cases can be implemented using field policies.
You're more than welcome to copy and adapt them to suit your needs. In particular, the concatPagination helper assumes the top-level value of the field is an array, so you're definitely going to need to implement your own version if the array is nested inside an object that has other properties that you want to maintain.
I'm open to considering new helper functions that implement common patterns in a general way, but of course the name of the array field would have be configurable, since we're not going to hard-code launches in a generic helper function.
@benjamn I created a new feature request. I think that is the proper channel to discuss this if you will agree according to the contributing guide. Thanks.
Most helpful comment
@benjamn I created a new feature request. I think that is the proper channel to discuss this if you will agree according to the contributing guide. Thanks.