I am getting a strange behaviour where NextJs lets me include the 'use client' directive at the top of my file while still letting me declare the component with async, like below:
'use client';
import React, { useState } from 'react';
const TestComponent = async () => {
const [randomNumber, setRandomNumber] = useState(null);
return (
<div>
<div> {randomNumber} </div>
<button onClick={() => setRandomNumber(Math.random())}>Set state</button>
</div>
);
};
export default TestComponent;
I would have expected this to throw a runtime error and crash my application because I have mixed 'use client' with an async component, as is suggested here.
But all I get is a console warning and my component still runs fine. Weirdly, it acts kind of like a server component as the loading
component is shown whenever I run setRandomNumber
almost as if it was fetching data from a server component (I declare the loading component as a top-level component as is suggested by the nextJS docs). All of my console.logs are output in the client console (i.e. on the browser).
Is this some new functionality where your application doesn't break if you mix 'use client' with an async component?
My loading component:
const Loading = () => {
return <p>Loading...</p>;
};
export default Loading;
My project structure:
test-app/src/app
├── test
│ └── page.js # my TestComponent page
├── page.js # just the default NextJS index page
├── loading.js # my custom top-level loading page
└── layout.js # the default layout
Update
So I investigated this a bit more. I found that my top-level loading
component is preventing the usual: 'Hooks are not supported inside an async component' error from appearing (although I do get a console warning). Interestingly, when I remove my top level loading
component the error does show normally during runtime when I click the 'set state' button (i.e. the error takes over the entire page). But if I include a top-level loading
component in my project then the page will just show the 'loading' message as defined in the component, and the app will work just fine.
I tested this on a completely clean NextJs project with just the TestComponent
above and a top-level loading
component, and I still get the same behaviour. I am also able to build the project successfully and the app still runs ok (although again, I get a warning when the project builds).
Is this the expected behaviour? Perhaps this is just the way it is? It feels a bit confusing to throw an error under one set of circumstances but then it allows the project to run under other certain circumstances, e.g. if you include a loading
component.
TestComponent
is not exported and is likely not in the RSC build. YettestComponent
likely is but just as an undeclared object.