DEV Community

Cover image for How to properly use third-party libraries with React Server Components
Martin PAUCOT
Martin PAUCOT

Posted on • Edited on • Originally published at martin-paucot.fr

How to properly use third-party libraries with React Server Components

With the new Next.JS 13 App Router, arrived React Server Components. When following the best practices of this new version, we have to think server first but it can be easy to get tangled in server and client components when working with third-party libraries.

What is a React Server Component

A React Server Component is rendered server-side. The generated HTML is then sent to the browser to hydrate the updated part of your app.

PHP Developers will recognize this pattern!

There are a lot of benefits of using React Server Components:

  • Drastically decrease the amount of Javascript sent to the browser
  • React Server Components can be entirely cached
  • Ability to fetch data directly from your component

The problem with React Server Components

If you try to use React Hooks (useState, useEffects, etc) or simply listen to an event (onClick, onChange). You will receive an error similar to this one:

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.
Enter fullscreen mode Exit fullscreen mode

This is completely normal as the server is not able to listen to events happening in the browse.

To fix the issue you have to add 'use client'; on top of your file to tell Next.JS that everything inside the file is "client-side".

But watchout! Do not add 'use client'; everywhere as if it was a patch. The idea is to keep most of your components server side.

The problem with UI Libraries

You just installed your favorite UI library, and start using it:

// src/app/page.tsx
import { Button } from "@chakra-ui/react";

export default async function Page() {
  const post = await fetchPost();
  return <Button>{post.title}</Button>;
}
Enter fullscreen mode Exit fullscreen mode

You received the same error You're importing a component that needs useState but you do not want to change your page into a Client Component as you need to fetch data.

So you decide to create a "component-in-the-middle" that will tell Next.JS that the Button imported from @chakra-ui/react is a Client Component:

// src/app/Button.tsx
"use client";
import { Button as ChakraButton } from "@chakra-ui/react";

export default function Button({ children }: { children?: React.ReactNode }) {
  return <ChakraButton>{children}</ChakraButton>;
}
Enter fullscreen mode Exit fullscreen mode
// src/app/page.tsx
import Button from "./Button";

export default async function Page() {
  const post = await fetchPost();
  return <Button>{post.title}</Button>;
}
Enter fullscreen mode Exit fullscreen mode

It works! But for this case we only forwarded the children, we want every props. Let's do it with a much simpler solution:

// src/app/Button.tsx
"use client";
import { Button as ChakraButton } from "@chakra-ui/react";

const Button = ChakraButton;

export default Button;
Enter fullscreen mode Exit fullscreen mode

But it means that we have to do the same thing for every single component that we use, is there any better solution?

"use client";
export * from "@chakra-ui/react";
Enter fullscreen mode Exit fullscreen mode
import { Button } from "./ChakraUI";

export default function Page() {
  const post = await fetchPost();
  return <Button>{post.title}</Button>;
}
Enter fullscreen mode Exit fullscreen mode

What about "dot notation" like framer-motion

Unfortunately there is no magic solution currently.
You have to export each component:

"use client";

import { motion } from "framer-motion";

export const MotionDiv = motion.div;
export const MotionSpan = motion.span;
Enter fullscreen mode Exit fullscreen mode

Conclusion

Properly using React Server Component can drastically increase your app performances but it is tricky to keep a good component tree without getting tangled between server and client.

Currently most of the libraries does not yet export using 'use client'; directive so you still have to add it ourself.

Top comments (0)