Skip to content

Instantly share code, notes, and snippets.

@necccc
Created October 20, 2019 13:53
Show Gist options
  • Save necccc/4ea946178bd295822d8058fad7071944 to your computer and use it in GitHub Desktop.
Save necccc/4ea946178bd295822d8058fad7071944 to your computer and use it in GitHub Desktop.
Gists for Next.js & Apollo GraphQL Performance Tuning: Lists & pagination
// our GraphQL Query,
// get the name and ID of some Starships
export const getStarships = gql`
query getStarships {
starshipList {
items {
name
id
}
}
}
`
// a small component to list the data above
const List = (props) => (<div>
<ul>
{
// data structure here matches the data structure in the query
props.data.starshipList.items.map(item => (<li key={item.id}>
{item.name}
</li>))
}
</ul>
</div>)
// compose the component and the GraphQL Query together
// using the `graphql` method from react-apollo.
export default graphql(getStarships)(List)
// our GraphQL Query, unchanged
export const getStarships = gql`
query getStarships {
starshipList {
items {
name
id
}
}
}
`
// the listing component
const List = (props) => (<div>
<ul>
{
// NOTE, we're not including the property "starshipList" here
// just the data, with ids and names
props.data.map( item => (<li key={item.id}>
{item.name}
</li>))
}
</ul>
</div>)
// we can use the tools in the Apollo Client to shape our component props
export default graphql(getStarships, {
props: ({data, ownProps}) => {
// data is the query result object
// ownProps is the props passed to the Component
const {
starshipPages,
loading
} = data
// compute new props, with only the data array, and the loading state
const newProps = {
loading,
data: starshipPages.items
}
// do not forget to include the originally received props (ownProps)!
return Object.assign({}, ownProps, newProps)
}
})(List)
// our updated Query, now expecting a $page variable
// type is Int
// default value is 1
export const getStarships = gql`
query getStarships($page: Int = 1) {
starshipList(page: $page) {
page
items {
name
id
}
}
}
`
// note that the data sctructure now contains the actual page number too
const List = (props) => (<div>
{
// do something meaningful during loading, this is just some text
props.loading ? 'LOADING' : ''
}
<ul>
{
props.data.map( item => (<li key={item.id}>
{item.name}
</li>))
}
</ul>
<button onClick={e => props.loadPage(props.page + 1) }>
Load Page {props.page + 1}
</button>
</div>)
export default graphql(getStarships, {
options: {
// this is needed to auto-update the 'loading' prop
notifyOnNetworkStatusChange: true,
// fill parameters for the query here
variables: {
// first query will use 1
page: 1
},
},
props: ({data, ownProps}) => {
const {
// grab the fetchMore method
fetchMore,
// actual data
starshipPages: { items, page },
// loading state indicator
loading
} = data
const newProps = {
// pass on loading state & data
loading,
page,
data: items,
// add a new function to the props,
// this will fetch the required page
loadPage: (nextPage) => {
// use fetchMore
return fetchMore({
variables: {
page: nextPage
},
updateQuery: (prev, { variables, fetchMoreResult }) => {
if (!fetchMoreResult) return prev;
// here you can concatenate the list
// with the already loaded and displayed ones (see `prev`)
// or just show the next page, like we do here
return Object.assign({}, fetchMoreResult, { variables })
}
})
}
}
// return the props
return Object.assign({}, ownProps, newProps)
}
})(List)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment