How to conditionally render a component in Next.js without caching CSS styles?

Viewed 341

I'm pretty new with Next.js and do not fully understand the cache functioning.

Given the following simplified example:

An index page that renders components Test1 or Test2, depending whether the current minute is even or odd:

import { Test2 } from '@src/components/test2'
import React from 'react'

const conditionallyChooseComponent = () => {
  const d = new Date()
  if (d.getMinutes() % 2 === 0) return <Test1 />
  else return <Test2 />
}

export default function Home() {
  return <div>{conditionallyChooseComponent()}</div>
}

And having the following components. Test1:


export const Test1 = () => {
  const d = new Date()

  return (
    <div className={`${utilStyles.redContainer}`}>
      <h1>It's {d.toISOString()} and I'm Test1 component. My background should be red</h1>
    </div>
  )
}

And Test2:


export const Test2 = () => {
  const d = new Date()

  return (
    <div className={`${utilStyles.blueContainer}`}>
      <h1>It's {d.toISOString()} and I'm Test2 component. My background should be blue</h1>
    </div>
  )
}

And this CSS:

.redContainer {
  background-color: red;
}

.blueContainer {
  background-color: blue;
}

The background color is being cached when the code is executed by building and serving from the transpiled code. When running with yarn dev it is working just fine.

Here is the unexpected result:

Screenshot with Test1 component being rendered with blue background

PS: I made this work with the workaround of using the getInitialProps to prevent Next.js from caching anything in that page but, for my real use case that option is not valid because I need the render condition to be calculated in the client side since it will depend on the local date of the browser.

2 Answers

To make that works, you will need to add some client-side code (via useEffect), so the React component updates every minute (or so). Funny enough, this is not as simple as it sounds, and even Dan Abramov has published a long post explaining why things such as setInterval may not work intuitively with React (specifically, with React Hooks).

Assuming you use the custom hook Dan explains in the article above, this should work:

export default function Home() {
  const [date, setDate] = useState(new Date());

  useInterval(() => {
    // this will update the component's date every second
    setDate(new Date()); 
  }, 1000);

  return <div>{date.getMinutes() % 2 === 0 ? <p>Test 1</p> : <p>Test 2</p>}</div>;
}

Observe that your code example only executes the conditionallyChooseComponent once, just when Next is trying to server-side rendering your page.

Related