4

I have a server component InitView;

const InitView = () => {
    useEffect(() => { });
    return (
        <>
            <Hero/>
            <span className="text-xl font-normal text-gray-100">Now, how do you want to play?</span>
            <GameModeMenu/>
        </>
    );
}

export default InitView;

Also I have one more server component View;

interface ViewProps {
    children?: React.ReactNode;
}

const View = ({children}:ViewProps) => {
    return (
        <main className="home w-screen h-screen flex flex-col gap-10 justify-start items-center bg-neutral-900 px-8 py-10">
            {children}
        </main>
    );
}

export default View;

And here is my page.tsx

export default function Page() {
  return (
    <View>
        <InitView/>
    </View>
  )
}

When I tried to import the InitView inside the View component with pass-child method it throws an error;

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

I'm completely okay with this error since I'm trying to use an effect inside a server component. However here is the thing , if I change my codes to this;

Page.tsx

export default function Page() {
  return (
    <View/>
  )
}

View.tsx

"use client";

const View = () => {
    return (
        <main className="home w-screen h-screen flex flex-col gap-10 justify-start items-center bg-neutral-900 px-8 py-10">
            <InitView/>
        </main>
    );
}

export default View;

The error is gone now. To clarify;

I can use an effect inside my InitView component without any "use client" markings since I directly imported it in View(marked as client) component.

I'm assuming every directly imported (server or client) components inside client components, will be client components, as the previous error says none of its parents are marked with "use client", so they're Server Components by default.

Have you guys any ideas? Am I wrong or correct?

P.S. The documentation says I can not import server components inside client components but as clearly can be seen, I can. I'm highly confused.

utkuonursahin
  • 249
  • 4
  • 10

3 Answers3

6

As per my understanding, we can't import Server Components inside Client Components only when the Server Components contain any server only code (for instance, a database calling or using component level async/await ).

In your case InitView don't have any server-specific code, so importing it inside a Client Component, may infer it to Client Component.

You can find it on Next.js' beta docs - Link

Sachin Som
  • 1,005
  • 3
  • 8
  • Thanks for your answer. I made the InitView async and fetched some JSON data in it. Situation went as you guessed. I could not imported it inside View component directly. I had to pass it as child of the View like . They should really emphasize this subtle confusion in their docs. – utkuonursahin Mar 24 '23 at 12:29
3

All the component's are Server Components by default, if you don't mention the

*'use client';*

marker on the top of the component. In order to use reacts client side hooks you need to mention the marker on the top for Next.js to know if it is client or server-side component.

0

useEffect() is a client-side function. As in, it executes on the browser. So if you use that in your component, that component, or its parent component, has to have the "use client" directive on it. Now, combine that with the fact, that all components are by default server components.

In your case initview, view, and page are all server components. So, when you bring page->view->initview together, there is useEffect function in initview, but no component in the chain with "use client". Therefore, you get that error.

As soon as you put "use client" in view, one of the components in the chain has the "use client" directive, the error goes away. However, by marking the view components with "use client" directive, view becomes a client component and then we cannot import the initview component into it, because by default initview is a server components. Server components can be passed into the client component as children as you noted above or as server actions.

dude0307
  • 31
  • 2