Search code examples
javascriptreactjsnext.jsreact-bootstrap

Using react-bootstrap doesn't work, unsupported server component error


My problem is I keep getting a Unsupported Server Component Error while using react-bootstrap with typescript. I've given you the contents of my page.tsx file, my layout.tsx file, and the error itself

layout.tsx file

import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import './globals.css'
import React from 'react'
import 'bootstrap/dist/css/bootstrap.min.css'

const inter = Inter({ subsets: ['latin'] })

export const metadata: Metadata = {
  title: "Let's Assist - Volunteering for everyone",
  description: 'Generated by create next app',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <div className={inter.className}>{children}</div>
  )
}

page.tsx file

import React from 'react';
import Container from 'react-bootstrap/Container';
import Nav from 'react-bootstrap/Nav';
import Navbar from 'react-bootstrap/Navbar';
import NavDropdown from 'react-bootstrap/NavDropdown';


export default function Home() {
  return (
    <div>
      <Navbar expand="lg" className="bg-body-tertiary">
      <Container>
        <Navbar.Brand href="#home">React-Bootstrap</Navbar.Brand>
        <Navbar.Toggle aria-controls="basic-navbar-nav" />
        <Navbar.Collapse id="basic-navbar-nav">
          <Nav className="me-auto">
            <Nav.Link href="#home">Home</Nav.Link>
            <Nav.Link href="#link">Link</Nav.Link>
            <NavDropdown title="Dropdown" id="basic-nav-dropdown">
              <NavDropdown.Item href="#action/3.1">Action</NavDropdown.Item>
              <NavDropdown.Item href="#action/3.2">
                Another action
              </NavDropdown.Item>
              <NavDropdown.Item href="#action/3.3">Something</NavDropdown.Item>
              <NavDropdown.Divider />
              <NavDropdown.Item href="#action/3.4">
                Separated link
              </NavDropdown.Item>
            </NavDropdown>
          </Nav>
        </Navbar.Collapse>
      </Container>
    </Navbar>

      {/* Add your homepage content here */}
    </div>
  );
}

my error

❯ npm run dev

> [email protected] dev
> next dev

   ▲ Next.js 14.0.1
   - Local:        http://localhost:3000

 ✓ Ready in 2.7s
 ○ Compiling /page ...
 ✓ Compiled /page in 1679ms (782 modules)
Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Check your code at page.tsx:13.
Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Check your code at page.tsx:14.
Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Check your code at page.tsx:17.
Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Check your code at page.tsx:18.
Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Check your code at page.tsx:20.
Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Check your code at page.tsx:21.
Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Check your code at page.tsx:24.
Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Check your code at page.tsx:25.
Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Check your code at page.tsx:26.
Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Check your code at page.tsx:15.
 ⨯ Error: Unsupported Server Component type: undefined
    at stringify (<anonymous>)
 ⨯ Error: Unsupported Server Component type: undefined
    at stringify (<anonymous>)
 ⨯ Error: Unsupported Server Component type: undefined
    at stringify (<anonymous>)
digest: "723927334"
 ⨯ Error: Unsupported Server Component type: undefined
    at stringify (<anonymous>)

Let me give you some back story. I'm making a next-js app, and just to learn and stuff, I decided to use the default template (create-next-app template) and try bootstrap to make my life a lot easier. Now, doing this, the css portion of the bootstrap worked, but the js, kept giving an error! So, I ignored it, and tested out one of the features, which was dropdowns in navbars and it didn't work(im a new web dev, i do more backend stuff). I assumed, the problem was with the javascript and after some google searches, it seemed like I had to use something called react-bootstrap. I tried using that but I got this error, and I couldn't find out why anywhere. I've uploaded my main page.tsx file, and the error I'm getting below. If you know where I'm going wrong and what I can do that would be really helpful. Thanks!


Solution

  • Next.js uses Server-Side Rendering (SSR) by default, meaning the server pre-renders the content before the webpage is loaded, and send the results directly to the client browser. However, Bootstrap contains lots of client side javascript operated components that only works when rendered by the client. In Next.js, you can write "use client" on top of a component file to specify that it's supposed to be rendered by the client.

    With Next.js 13 or later using App Router, here's how you can bypass the issue.

    1. Keep the existing Bootstrap css import. import 'bootstrap/dist/css/bootstrap.min.css' and remove import of react and react-bootstrap frameworks from files that are server rendered.

    2. Create a new client rendered component file in src/components/BootstrapClient.tsx for importing Bootstrap.js after the webpage has loaded.

    "use client"
    
    import { useEffect } from 'react'
    
    function BootstrapClient() {
      useEffect(() => {
        require('bootstrap/dist/js/bootstrap.bundle.min.js')
      }, [])
    
      return null
    }
    
    export default BootstrapClient
    
    1. In your src/app/layout.tsx file, import and insert the BootstrapClient component.
    import BootstrapClient from '@/components/BootstrapClient'
    
    export default function RootLayout({ children }) {
      return (
        <html lang="en">
          <body className={inter.className}>
            {children}
            <BootstrapClient />
          </body>
        </html>
      )
    }
    
    1. Change the usages of react-bootstrap to bootstrap in src/app/page.tsx
    <nav className="navbar navbar-expand-lg bg-body-tertiary">
        <div className="container-fluid">
            <a className="navbar-brand" href="#">Navbar</a>
            <button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
            <span className="navbar-toggler-icon"></span>
            </button>
            <div className="collapse navbar-collapse" id="navbarSupportedContent">
            <ul className="navbar-nav me-auto mb-2 mb-lg-0">
                <li className="nav-item">
                <a className="nav-link active" aria-current="page" href="#">Home</a>
                </li>
                <li className="nav-item">
                <a className="nav-link" href="#">Link</a>
                </li>
                <li className="nav-item dropdown">
                <a className="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
                    Dropdown
                </a>
                <ul className="dropdown-menu">
                    <li><a className="dropdown-item" href="#">Action</a></li>
                    <li><a className="dropdown-item" href="#">Another action</a></li>
                    <li><hr className="dropdown-divider" /></li>
                    <li><a className="dropdown-item" href="#">Something else here</a></li>
                </ul>
                </li>
                <li className="nav-item">
                <a className="nav-link disabled" aria-disabled="true">Disabled</a>
                </li>
            </ul>
            <form className="d-flex" role="search">
                <input className="form-control me-2" type="search" placeholder="Search" aria-label="Search" />
                <button className="btn btn-outline-success" type="submit">Search</button>
            </form>
            </div>
        </div>
    </nav>
    

    Note: There's probably a way to get react-bootstrap to work with a client component wrapper, but I was encountering some issues with an "Unhandled Runtime Error": Cannot access Navbar.Brand on the server. You cannot dot into a client module from a server component. You can only pass the imported name through.

    Example:

    In src/components/BootstrapClient.tsx

    'use client'
    
    export * from 'react-bootstrap'
    

    In layout.tsx

    import { Container, Nav, Navbar, NavDropdown } from '@/components/BootstrapClient'