Search code examples
javascriptcachingnext.jscontentfulswr

Can I use 'useSWR' with the contentful-client to create pagination?


I'm trying to create pagination with nextjs and the useSWR hook.

This is how I've currently done it, and it appears to be working... however I read in the docs that the key passed as the first parameter should be a unique string (usually a URL). I'm just passing the index to fetch the correct data. Will my approach mess up the caching? I'm not sure if I'm doing this correctly?

index.js

import React, { useState } from 'react'
import Page from '../components/page'

export default function IndexPage( ) {
  const [pageIndex, setPageIndex] = useState(0)

  return (
    <div>
      <Page index={pageIndex} />
      <button onClick={() => setPageIndex(pageIndex - 1)}>Previous</button>
      <button onClick={() => setPageIndex(pageIndex + 1)}>Next</button>
    </div>
  )
}

And in my page.js

import useSWR from 'swr'
import { fetcher } from '../client/fetcher'

function Page({ index }) {
  const { data } = useSWR(index, fetcher)
  console.table(data)

  return <div>nothing here, just testing</div>

}

export default Page

And finally the fetcher.js

import client from './contentful-client'

export async function fetcher(pageIndex = 1, limit = 3) {
  const data = await client.getEntries({
    content_type: 'posts',
    skip: pageIndex * limit,
    order: '-fields.publishDate',
    limit,
  })

  if (data) {
    return data
  }
  console.log('Something went wrong fetching data')
}


Solution

  • You may want to move the Contentful data fetching logic to the server as to not expose credentials and logic to the browser. This could be done using Next.js API routes.

    // pages/api/posts.js
    
    import client from '<path-to>/contentful-client' // Replace with appropriate path to file
    
    export default async function handler(req, res) {
        const { pageIndex = 1, limit = 3 } = req.query
        const data = await client.getEntries({
            content_type: 'posts',
            skip: pageIndex * limit,
            order: '-fields.publishDate',
            limit,
        })
    
        res.json(data)
    }
    

    You could then refactor the code in your page to make a request against the newly created API route, passing the route URL as the key to useSWR.

    import useSWR from 'swr'
    
    const fetcher = (url) => fetch(url).then(res => res.json())
    
    function Page({ index }) {
        const { data } = useSWR(`/api/posts?pageIndex=${index}`, fetcher)
        console.table(data)
    
        return <div>nothing here, just testing</div>
    }
    
    export default Page