Posts

Dynamically import class with no SSR in Next.js

In this tutorial, I will show you how to dynamically import class with no SSR in Next.js.

Probably you already have seen this Next.js documentation regarding dynamically importing component with no SSR. But the problem with this is that it can only be used on React components, but what if we need to dynamically import a non-React component class?

This guide will show you how. I will use FullCalendar plugin called FullCalendar interaction as this has a class that I need to dynamically import to make it work. (READ: How to use FullCalendar in Next.js)

Step 1: Initialize a Next.js project

Initialize a Next.js project by running the following commands in the terminal.

mkdir import-class-nextjs
cd import-class-nextjs
touch package.json

Paste the following inside package.json that we have created.

{
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  }
}

Install the necessary Next.js packages by running the following command in the terminal.

npm install --save next react react-dom

Let’s create an index or landing page for our project using the following commands.

mkdir pages
touch pages/index.js

Page the following inside pages/index.js that we have created.

export default function Home() {
  return <div>Welcome to Next.js!</div>
}

This is just a simple component for our landing page which just returns a single div component.

Step 2: Dynamically import class with no SSR

Install the package that you need. In this example, we are going to use FullCalendar interaction plugin.

npm install --save @fullcalendar/core @fullcalendar/interaction

If you tried to import this the usual way (import interactionPlugin from '@fullcalendar/interaction') you will get an error Element is not defined as Element is non-existent on the server side rendering.

The solution is to make sure that the window is already defined when you import the package.

Since Next.js is a React framework we can take advantage of using componentDidMount if you are using class components or useEffect when using functional components.

The importing of package can be written as follows.

import { useEffect } from 'react'



export default function Home() {

  useEffect(() => {
    dynamicallyImportPackage()
  }, [])

  let dynamicallyImportPackage = async () => {
    const FullCalendarInteraction = await import('@fullcalendar/interaction')

    // you can now use the package in here
  }

  return <div>Welcome to Next.js!</div>
}

That’s it, we have now successfully imported a non-React component class with no SSR in Next.js.

How to use FullCalendar in Next.js

In this tutorial, we would be learning on how to use FullCalendar in Next.js.

You might have been able to come here because you have encountered an error Element is not defined when you are trying to use FullCalendar in Next.js project.

Before we proceed with the solution, I will just point out the cause of that error.

Next.js renders the page on the server side. Since it was on the server side, window is not available as it is only available on the client side. If the window is not available, then the element is also not available.

Now that we understand the problem, let’s proceed with the solution.

Step 1: Initialize a Next.js project

Let’s start with initializing our Next.js project by running the following commands in the terminal.

mkdir nextjs-fullcalendar
cd nextjs-fullcalendar
touch package.json

In the package.json that we have created, paste the following.

{
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  }
}

In the terminal, install Next.js by running the following command.

npm install --save next react react-dom

Now, let’s create our landing page. Run the following commands in the terminal.

mkdir pages
touch pages/index.js

In the file pages/index.js, paste the following.

export default function Home() {
  return <div>Welcome to Next.js!</div>
}

We just created a Home component that simply shows a short message on our landing page.

Step 2: Setup Next.js CSS support

Since FullCalendar has custom CSS, we must setup our Next.js project to support CSS.

In the terminal run the following.

npm install --save node-sass @zeit/next-sass @zeit/next-css
touch next.config.js

In the file next.config.js, paste the following.

const withSass = require('@zeit/next-sass')
module.exports = withSass()

Step 3: Install FullCalendar

Now, let’s install FullCalendar to our project. Run the following command in the terminal.

npm install --save @fullcalendar/core @fullcalendar/react @fullcalendar/daygrid @fullcalendar/timegrid

Let’s create an SCSS file for the FullCalendar CSS by running the following commands in the terminal.

mkdir styles
touch styles/calendar.scss

In the file styles/calendar.scss, paste the following.

@import '[email protected]/core/main.css';
@import '[email protected]/daygrid/main.css';
@import '[email protected]/timegrid/main.css';

Step 4: Create your own no SSR FullCalendar component

Let’s start by creating a directory for our components. Run the following commands in the terminal.

mkdir components
touch components/fullcalendar.js

In the file components/fullcalendar.js, paste the following.

import dynamic from 'next/dynamic'
import { useEffect, useState } from 'react'

import '../styles/calendar.scss'

let CalendarComponent



export default function FullCalendar(props) {

  const [calendarLoaded, setCalendarLoaded] = useState(false)

  useEffect(() => {
    CalendarComponent = dynamic({
      modules: () => ({
        calendar: import('@fullcalendar/react'),
        dayGridPlugin: import('@fullcalendar/daygrid'),
        timeGridPlugin: import('@fullcalendar/timegrid')
      }),
      render: (props, { calendar: Calendar, ...plugins }) => (
        <Calendar {...props} plugins={Object.values(plugins)} ref={props.myRef} />
      ),
      ssr: false
    })

    setCalendarLoaded(true)
  })

  let showCalendar = (props) => {
    if ( !calendarLoaded ) return <div>Loading ...</div>

    return (
      <CalendarComponent {...props} />
    )
  }

  return (
    <div>
      {showCalendar(props)}
    </div>
  )

}

The problem that we have is that Next.js renders our page in the server. In the docs, there is a way to dynamically import packages with no ssr.

We simply imported the FullCalendar component dynamically using Next.js’s dynamic function with an attribute ssr: false to make sure that it is not rendered on the server.

We also imported it in React’s useEffect() hook just to be sure that the window is already defined.

Step 5: Use our own FullCalendar component

In the file pages/index.js, paste the following.

import FullCalendar from '../components/fullcalendar'



export default function Home() {
  return (
    <div>
      <FullCalendar defaultView='dayGridMonth' />
      <FullCalendar defaultView='timeGridWeek' />
    </div>
  )
}

Now if you run npm run dev in the terminal and navigate to http://localhost:3000 in your browser, you should be able to see the two (2) calendars, one in month view and one in week view rendered properly without any errors.

TL;DR

Install FullCalendar using the following command.

npm install --save @fullcalendar/core @fullcalendar/react @fullcalendar/daygrid @fullcalendar/timegrid

Import the CSS in your styles.

@import '[email protected]/core/main.css';
@import '[email protected]/daygrid/main.css';
@import '[email protected]/timegrid/main.css';

Dynamically import FullCalendar with no SSR and use the component in your project.

import dynamic from 'next/dynamic'
import { useEffect, useState } from 'react'

import '../styles/calendar.scss'

let FullCalendar



export default function Home(props) {

  const [calendarLoaded, setCalendarLoaded] = useState(false)

  useEffect(() => {
    FullCalendar = dynamic({
      modules: () => ({
        calendar: import('@fullcalendar/react'),
        dayGridPlugin: import('@fullcalendar/daygrid'),
        timeGridPlugin: import('@fullcalendar/timegrid')
      }),
      render: (props, { calendar: Calendar, ...plugins }) => (
        <Calendar {...props} plugins={Object.values(plugins)} ref={props.myRef} />
      ),
      ssr: false
    })

    setCalendarLoaded(true)
  })

  let showCalendar = (props) => {
    if ( !calendarLoaded ) return <div>Loading ...</div>

    return (
      <FullCalendar {...props} />
    )
  }

  return (
    <div>
      {showCalendar(props)}
    </div>
  )

}

That’s it, we have learned on how to use FullCalendar in Next.js project.

Reference: Using fullcalendar with Next.js