DEV Community

Cover image for Errors Received When Migrating Next.js 13 to New App Folder
Dennis Persson
Dennis Persson

Posted on • Originally published at perssondennis.com

Errors Received When Migrating Next.js 13 to New App Folder

Next.js is evolving. Fairly recently, Next.js has added a new powerful routing mechanism which is used but adding files to the a app folder instead of the old pages folder. With new routing and new features like Server Components, comes also new errors to detect. This article will present solutions to four errors which are likely to happen the first hour of trying out the new Next.js features.

In This Article

  1. Exporting Async Server Component When Fetching Data
  2. Server Components Are Not the Same as Client Components
  3. Using Client-Side Hooks in Server Components
  4. Infinite Loading With Next.js 13 Development Server
  5. Should You Use Next.js 13?

Exporting Async Server Component When Fetching Data

Error: 'MyComponent' cannot be used as a JSX component. Its return type 'Promise' is not a valid JSX element

Reason to error: You are using an old version of TypeScript

Solution: Bump TypeScript or suppress the error with @ts-expect-error

Note: This error is a TypeScript error. Next.js 13 is TypeScript-first. which means you have to opt-out of it if you don't want it

To fetch data in server components, Next.js recommends trying out their built-in fetch API which is based on an RFC. Their example code for that uses an async Page function.

The problem arise when trying to use an async component like that in another page component. Doing that, will result in a TypeScript error.

'MyComponent' cannot be used as a JSX component.
  Its return type 'Promise<Element>' is not a valid JSX element.
  Type 'Promise<Element>' is missing the following properties from type 'ReactElement<any, any>': type, props, key
Enter fullscreen mode Exit fullscreen mode

The error is thrown since the used TypeScript version doesn't recognize the async component. The issue has been solved recently in TypeScript version 5.1.3, but if you are bootstrapping templates or if you are checking out old git repositories you may have an outdated TypeScript version.

The solution is therefore to bump TypeScript version. If that for some reason cannot be done, you can suppress the warning with @ts-expect-error, which was the recommended solution from Next.js before it was fixed in TypeScript.

export default function Home() {
  return (
    <main>
      {/* @ts-expect-error Server Component */}
      <MyComponent />
    </main>
  )
}
Enter fullscreen mode Exit fullscreen mode

Server Components Are Not the Same as Client Components

Error: You're importing a component that needs useState. It only works in a Client Component

Reason to error: You are using client-side only functionality in a Server Component

Solution: Add 'use client' directive to convert the Server Component to a Client Component

The most fundamental part when upgrading to Next.js 13 is to understand Server Components and Client Components. Traditionally in React and Single Page Applications (SPA) overall, the application has been rendered on the client side, in contrast to even more traditional websites that were rendered on the server. In modern programming, rendering is shared between the client and the server.

Next.js 13 gives you the full power to granularly fine-tune where you want to render each of your component, either on client or server, dependent on your needs. If you don't actively state that a Client Component should be a Client Component, you will run into a ReactServerComponentsError error.

ReactServerComponentsError:

You're importing a component that needs useState. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.

-[/path/to/file/MyComponent.ts:1:1]
1 | import { useState } from 'react'
Enter fullscreen mode Exit fullscreen mode

The error above will show up when you have a component or hook which uses some client-side only functionality, but which isn't explicitly declared with a "use client" directive.

import { useState } from 'react'

const MyComponent = () => {
  const [value, setValue] = useState()

  // Some code...

  return <div>{value}</div>
}

export default MyComponent
Enter fullscreen mode Exit fullscreen mode

To fix the error, simply add the "use client" directive at the top of the file.

'use client'

import { useState } from 'react'

const MyComponent = () => {
  const [value, setValue] = useState()

  // Some code...

  return <div>{value}</div>
}

export default MyComponent
Enter fullscreen mode Exit fullscreen mode

Before you convert your component to a Client Component, take a minute to reflect over if you really need a Client Component or if you are better off with a Server Component. I think Next.js explains very well which one to use with a simple table.

Differences between Client and Server Components in Next.js
A good rule of thumb, only use a Client Component if you need browser functionality or keeping a state

In short, one can say, components and hooks which uses useState, useReducer and useEffect are client-side components/hooks.

Secondly, components which relies on user interactions via the DOM tree are client-side, which means that DOM elements which have attached listeners like onClick and onChange belongs to Client Components.

A third case is also when the component or hook relies on a web API such as Geolocation API. There exist a lot of Web APIs, and they are often meant to run in a browser.

Using Client-Side Hooks in Server Components

Error: Attempted to call the default export of /path/to/file/file.ts from the server but it's on the client

Reason to error: You are using client side functions in a Server Component

Solution: Convert the component to a Client Component or create a sub-client-component which uses the hook

In the previous header, we learned briefly what Server Components and Client Components, are and that we have to mark Client Components with the "use client" directive. That error was then resolved by using the directive, since Client Components can be used anywhere in Server Components. However, if the component you converted to a client component is a hook, you may see another error as well.

Let's say we have this hook:

'use client'

import { useState } from 'react'

const useSomeClientOnlyCode = () => {
  const [value, setValue] = useState()

  // Some code...

  return { value }
}

export default useSomeClientOnlyCode
Enter fullscreen mode Exit fullscreen mode

Then we use it in a Server Component as follow:

import useSomeClientOnlyCode from '@/hooks/useSomeClientOnlyCode'

const MyServerComponent = async () => {
  const { value } = useSomeClientOnlyCode()

  return(<div>{value}</div>)
}
Enter fullscreen mode Exit fullscreen mode

If we run this code, we will see an error like this:

Error: Attempted to call the default export of /path/to/file/useSomeClientOnlyCode.ts from the server but it's on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.
    at Component (./app/server-components/MyServerComponent.tsx:12:118)
    at stringify (<anonymous>)
Enter fullscreen mode Exit fullscreen mode

What is happening here, is that the hook contains client-side only code and is used in a Server Component. Whilst Next.js supports Client Components in Server Component, they don't support client functions or hooks to be used in Server Components.

Hooks are essentially just a part of a component, so if a hook uses client-side logic, then the whole component must be a client side Component as well.

The trivial way to solve this error is therefore to declare the component which uses the hook as a Client Component, by using the "use client" directive.

'use client'

import useSomeClientOnlyCode from '@/hooks/useSomeClientOnlyCode'

const MyServerComponent = async () => {
  const { value } = useSomeClientOnlyCode()

  return(<div>{value}</div>)
}
Enter fullscreen mode Exit fullscreen mode

If you don't want to convert your whole component to a Client Component you can always lift out the parts of the component which utilizes the hook into a child component, and then make the child component a Client Component.

const MyServerComponent = async () => {
  return(<div>
    <MyClientComponentWhichUsesTheHook />
    <div>Some other server rendered elements...</div>
  </div>)
}
Enter fullscreen mode Exit fullscreen mode

Infinite Loading With Next.js 13 Development Server

Error: Node.js development server does not work

Reason to error: Varies, in my case I had an async Client Component

Solution: In this case, remove the async keyword

Next.js 13 introduces a new app folder, which offers a new and improved way to perform routing. I have been using Next.js 13 a long time with the old pages folder without any issues with the development server or build, but as soon as I tried to use the new app folder I ran into severe problems. The development server wasn't working.

What happened in detail was that the web page never finished loading. Next.js hot reloading didn't work, and the page stopped responding. Even when I stopped the development server it continued to serve a non-working build on the port.

I read GitHub threads as Next.js dev server gets stuck after a while, requests just spin and browsed Stack Overflow for similar errors. Nothing could fix my problem. Changing ports didn't help, and neither did upgrading or downgrading versions of node or packages. Removing node_modules, .next folder and package-lock.json or swapping to Turbopack did nothing good.

It was really frustrating to troubleshoot when Next.js development server didn't work. And when I finally found the solution, the culprit wasn't more than five characters long. You recognize that feeling, don't you?

My mistake was a silly copy-paste mistake after having tested out to use fetch in a Server Component. Lesson learned there, look out so you don't have any Client Components with the async keyword. Only Server Components can be async in Next.js.

If you find any async Client Component in your code, remove the async keyword and start the development server again on another port with next dev -p 1234.

Should You Use Next.js 13?

If you already are using Next.js 12 and are thinking if you should migrate to version 13, I would say, do it. Next.js 13 is more or less backward compatible. You can bump to 13 and partly upgrade to use the new features according to your time and requirements. See their migration guide here.

If starting a new project or migrating an existing one to version 13, you should know that some of the features are still in beta. The app folder routing which is discussed in this article is production ready since version 13.4.

If you are not using Next.js at all, try it out. Remember that React itself is still just a library. Next.js is a complete framework based on React which have just made it all better.

Next.js and React meme
I'm here to extend you didn't sound as good...

Top comments (7)

Collapse
 
baenencalin profile image
Calin Baenen

Erors*

Collapse
 
perssondennis profile image
Dennis Persson

Don't forget the last R on the cup 😄

Collapse
 
baenencalin profile image
Calin Baenen

Eh. "Eror" is all that's shown onscreen. :þ

(I didn't even notice there at first — how did it get all the way over there?)

Thread Thread
 
perssondennis profile image
Dennis Persson

AI is fantastic nowadays. Can do anything for ya, on purpose or by mistake 😄

Thread Thread
 
baenencalin profile image
Calin Baenen

The image was generated using AI?

Thread Thread
 
perssondennis profile image
Dennis Persson

Yep, it's an AI one :) My articles are all manually crafted except from the header image which often is a mix between AI, open source images and poor photoshop skills 😄

Collapse
 
perssondennis profile image
Dennis Persson

Thanks for reading! Let me know if I should post more articles like this by writing a comment or reacting with some of the reactions ❤️🦄 🔥

If you want more memes, you can find those at my Instagram. Enjoy your day! :)