I see 'use client' used too often in our own code base, and it seems to be a matter of confusion elsewhere too: devs don’t understand 'use client' or don’t want to get into it. Let me give a quick explanation of why you should not use it everywhere and hopefully, by the end of this post, you’ll have at least understood what it is not for.
'use client' indicates that a client module can be called within server modules. No more no less. That means 'use client' modules have some restrictions, because they can sit at the server-client boundary:
When a server evaluated module imports values from a
'use client'module, the values must either be a React component or supported serializable prop values to be passed to a Client Component. Any other use case will throw an exception.
(Source: React reference)
The thing is: most types are serializable, so you don’t generally see an issue with putting 'use client' everywhere. But one commonly used type is not: plain simple functions. It should make intuitive sense: a reference to a function is meaningless at the server-client boundary (unless it is a server action).
In practice: if your reactive client component exposes events to its parents, like onSubmit and onCancel in the component below, that means we expect the parents to be client component themselves.
export default function LineItemForm({
account,
onSubmit,
onCancel,
}: {
account: string;
onSubmit?: (data: LineItemData) => void;
onCancel?: () => void;
}) {How could it be otherwise? The function onSubmit or onCancel could never cross the client-server boundary. Thus, you can remember now:
When an exported client component has properties that are not serializable, like functions, its module should not start with
'use client'.
Now, you may be thinking: “But adding 'use client' does not hurt anything, right?” Ever taken painkillers when you don’t need it? It’s the same reasoning: it does not harm, but at the critical moment where you need to feel pain, you’re suddenly numb to it.
Without 'use client' at the top of that component, the compiler will not let you call that client component from a server component. But with an incorrect 'use client' the compiler will just obey and assume you’ve made sure the properties are serializable without checking, and misusing that component in server components could result in runtime errors.
Unfortunately, I cannot find any linter that lints this. There is however a dynamic warning provided by the typescript-language-server: Props must be serializable for components in the "use client" entry file. Adding a linter for this would be an interesting project.