Challenges

Live Reloading for a Production Next.js app

Showing a Notification

Reloading the page gets the job done, but it'll be nice if we show a notification like this:

Next.js Live Reload notification
Next.js Live Reload notification

Let's try to implement it.

Update the lib/use-live-reload.js with the following content.

import useSWR from 'swr'
import {useRouter} from 'next/router'
import { useEffect, useState } from 'react'

async function textFetcher(path) {
    const res = await fetch(path)
    return res.text()
}

export default function useLiveReload() {
    const [needToReload, setNeedToReload] = useState(false)
    const router = useRouter()
    const [prevData, setPrevData] = useState(null)
    const {data} = useSWR(router.asPath, textFetcher, {
        refreshInterval: 1000,
    })

    useEffect(() => {
        if (needToReload || !data) {
            return
        }

        if (prevData && prevData !== data) {
            setNeedToReload(true)
            return
        }

        setPrevData(data)
    })

    return {
        needToReload
    }
}

In this version, we return a field called needToReload instead of reloading the page. In the following component, we use that field to render a notification.

Add the following content to components/LiveReloadBanner.js:

import useLiveReload from "../lib/use-live-reload"

export default function LiveReloadBanner() {
    const { needToReload } = useLiveReload()
    
    if (needToReload) {
        return (
            <div>
                There's a new version of this page.
                <button onClick={() => location.reload()}>Reload Now</button>
                <style jsx>{`
                    div {
                        position: fixed;
                        top: 0;
                        left: 0;
                        right: 0;
                        padding: 10px;
                        background-color: #F48FB1;
                        text-align: center;
                    }
                    div button {
                        margin-left: 10px;
                    }          
                `}</style>
            </div>
        )
    }

    return null
}

Then we can use the above React component inside our pages/index.js page. To do that, remove the existing React hook and use the LiveReloadBanner component. This is how it looks like with this change.

Again, let's do the same experiment:

  • Kill the already running app
  • Run your app with yarn build && yarn start
  • Visit http://localhost:3005 using a new browser tab
  • Then open the data/content.md file
  • Change the content
  • Check the content of http://localhost:3005 for 5 seconds
  • Reload the page twice
Q: How do you describe the result?
authenticating...