Errors Received When Migrating Next.js 13 to New App Folder
Tags: react, nextjs, javascript, webdev
Published: 2023-06-18 14:46:19

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](#exporting-async-server-component-when-fetching-data)
1. [Server Components Are Not the Same as Client Components](#server-components-are-not-the-same-as-client-components)
1. [Using Client-Side Hooks in Server Components](#using-clientside-hooks-in-server-components)
1. [Infinite Loading With Next.js 13 Development Server](#infinite-loading-with-nextjs-13-development-server)
1. [Should You Use Next.js 13?](#should-you-use-nextjs-13)

## Exporting Async Server Component When Fetching Data

_**Error**: 'MyComponent' cannot be used as a JSX component. Its return type 'Promise<Element>' 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](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching) which is based on an RFC. Their [example code](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching) 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

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](https://github.com/vercel/next.js/issues/42292), 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.

```react
export default function Home() {
  return (
    <main>
      {/* @ts-expect-error Server Component */}
      <MyComponent />
    </main>
  )
}
```

{% embed https://dev.to/perssondennis/how-to-make-a-hero-image-in-nextjs-4lpf %}

## 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'

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.

```react
import { useState } from 'react'

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

  // Some code...

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

export default MyComponent
```

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

```react
'use client'

import { useState } from 'react'

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

  // Some code...

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

export default MyComponent
```

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](https://nextjs.org/docs/getting-started/react-essentials#when-to-use-server-and-client-components) with a simple table.

![Differences between Client and Server Components in Next.js](https://www.perssondennis.com/images/articles/errors-received-when-migrating-nextjs-13-to-new-app-folder/nextjs-client-vs-server-components.webp)
_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](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API). There exist [a lot of Web APIs](https://developer.mozilla.org/en-US/docs/Web/API), and they are often meant to run in a browser.

{% embed https://dev.to/perssondennis/react-anti-patterns-and-best-practices-dos-and-donts-3c2g %}

## 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:

```react
'use client'

import { useState } from 'react'

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

  // Some code...

  return { value }
}

export default useSomeClientOnlyCode
```

Then we use it in a Server Component as follow:

```react
import useSomeClientOnlyCode from '@/hooks/useSomeClientOnlyCode'

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

  return(<div>{value}</div>)
}
```

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>)

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.

```react
'use client'

import useSomeClientOnlyCode from '@/hooks/useSomeClientOnlyCode'

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

  return(<div>{value}</div>)
}
```

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.

```react
const MyServerComponent = async () => {
  return(<div>
    <MyClientComponentWhichUsesTheHook />
    <div>Some other server rendered elements...</div>
  </div>)
}
```

## 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](https://github.com/vercel/next.js/issues/10061) and browsed [Stack Overflow](https://stackoverflow.com/questions/61033562/hot-module-reload-is-not-working-on-my-nextjs-app) 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](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching). 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](https://nextjs.org/docs/app/building-your-application/upgrading/app-router-migration).

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](https://www.perssondennis.com/images/articles/errors-received-when-migrating-nextjs-13-to-new-app-folder/nextjs-react-replacement.webp)
_I'm here to extend you didn't sound as good..._

{% embed https://dev.to/perssondennis %}