인프런 커뮤니티 질문&답변

밍끼님의 프로필 이미지
밍끼

작성한 질문수

Next + React Query로 SNS 서비스 만들기

안녕하세요 아직 수강중이긴한데 실무에서 작업중 궁금한게 있어서 질문드립니다!

해결된 질문

작성

·

1.6K

0

안녕하세요, 강의는 수강중이기도하고 아래에 비슷한 맥락의 질문이 있는데 제가 이해한게 맞나 궁금해서
질문 올립니다!

현재 next14 버전과 styled-component를 사용중이며 공식문서
https://nextjs.org/docs/app/building-your-application/styling/css-in-js#styled-components
내용 과 검색등을 통하여 적용하였습니다.

// libs/styledCompnents/Registry.tsx

'use client';

import { useServerInsertedHTML } from 'next/navigation';
import { ReactNode, useState } from 'react';
import { ServerStyleSheet, StyleSheetManager } from 'styled-components';

const Registry = ({ children }: { children: ReactNode }) => {
  const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet());

  useServerInsertedHTML(() => {
    const styles = styledComponentsStyleSheet.getStyleElement();
    styledComponentsStyleSheet.instance.clearTag();
    return <>{styles}</>;
  });

  if (typeof document !== 'undefined') {
    return <>{children}</>;
  }

  return (
    <StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
      {children}
    </StyleSheetManager>
  );
};

export default Registry;
//libs/styledComponets/Provider.tsx

'use client';

import { ThemeProvider } from 'styled-components';
import GlobalStyles from '@/styles/GlobalStyles';
import theme from '@/styles/theme';
import { PropsWithRequiredChildren } from '@/types/common';
import { StyledComponentsRegistry } from '.';

const Providers = (props: PropsWithRequiredChildren) => {
  return (
    <StyledComponentsRegistry>
      <ThemeProvider theme={theme}>
        <GlobalStyles />
        {props.children}
      </ThemeProvider>
    </StyledComponentsRegistry>
  );
};

export default Providers;

 

// layout.tsx

import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import AdminLayout from '@/layouts/AdminLayout/AdminLayout';
import { StyledComponentsProvider } from '@/libs/styledComponents';
import { MSWComponent } from '@/mocks/MSWComponent';

const inter = Inter({ subsets: ['latin'] });

export const metadata: Metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <MSWComponent>
          <StyledComponentsProvider>
            <AdminLayout>{children}</AdminLayout>
          </StyledComponentsProvider>
        </MSWComponent>
      </body>
    </html>
  );
}


현재 이렇게 사용중인데 AdminLayout에 'use client'를 사용하지않으면, 아래와 같은 에러가 나오고
'use client' 를 사용하면 에러 없이 렌더링이 정상적으로 됩니다.

```

Server Error

Error: createContext only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/context-in-server-component

This error happened while generating the page. Any console logs will be displayed in the terminal window.

Call Stack

o

node_modules/styled-components/dist/styled-components.esm.js (1:15911)

(rsc)/./node_modules/styled-components/dist/styled-components.esm.js

next/server/vendor-chunks/styled-components.js (30:1)

__webpack_require__

next/server/webpack-runtime.js (33:42)

eval

webpack-internal:///(rsc)/./src/components/atoms/Text/Text.style.ts (5:75)

(rsc)/./src/components/atoms/Text/Text.style.ts

next/server/app/page.js (569:1)

__webpack_require__

next/server/webpack-runtime.js (33:42)

eval

webpack-internal:///(rsc)/./src/components/atoms/Text/Text.tsx (7:69)

(rsc)/./src/components/atoms/Text/Text.tsx

next/server/app/page.js (580:1)

__webpack_require__

next/server/webpack-runtime.js (33:42)

eval

webpack-internal:///(rsc)/./src/components/atoms/Text/index.ts (5:63)

(rsc)/./src/components/atoms/Text/index.ts

next/server/app/page.js (591:1)

__webpack_require__

next/server/webpack-runtime.js (33:42)

eval

webpack-internal:///(rsc)/./src/layouts/AdminLayout/AdminLayout.tsx (10:80)

(rsc)/./src/layouts/AdminLayout/AdminLayout.tsx

next/server/app/page.js (745:1)

__webpack_require__

next/server/webpack-runtime.js (33:42)

eval

webpack-internal:///(rsc)/./src/app/layout.tsx (10:90)

(rsc)/./src/app/layout.tsx

next/server/app/page.js (503:1)

Function.__webpack_require__

next/server/webpack-runtime.js (33:42)

async eq

/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js (35:401280)

async tr

/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js (35:405046)

async tn

/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js (35:405596)

async tu

/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js (35:409938)

async

/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js (35:410457)

```

궁금한 점이 3가지가 있는데 검색만으로는 이해가 잘안되서 질문드립니다ㅠ


1. AdminLayout이 'use client'를 선언하지 않고 서버 컴포넌트로 사용을 하여도 StyledComponentsProvider 가 'use client' 이기 때문에 클라이언트 컴포넌트의 자식으로 AdminLayout을 사용하면 AdminLayout도 자동으로 클라이언트 컴포넌트로 변경되는걸까요? 아니면 자식 요소로 사용하는것은 상관없이 import 해오는 경우만 클라이언트 컴포넌트에서 서버 컴포넌트를 불러오면 서버 컴포넌트가 클라이언트 컴포넌트가 되는걸까요?

2. 컴포넌트의 자식이 부모의 컴포넌트의 상태를 따라간다면, 만약 최상위 부모 (Layout)가 클라이언트 컴포넌트라면 어차피 AdminLayout 이나 불러오는 NavMenu 들을 서버 컴포넌트로 사용 못하는게 맞나요?

3. 강의상 진행할때는 문제 없었습니다. 현재 위에 질문드린 에러는 styled-components 때문에 createContext 는 use client에서만 사용할수있다라는 에러인거같은데 AdminLayOut이나 다른 페이지에서도 useContext를 사용하려하면 'use client'를 작성하여도 같은 에러가 나옵니다. 현재 말씀드린 정보로만으로는 에러의 문제점을 찾을순 없을까요?

답변 1

0

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

  1. 클라이언트가 서버컴포넌트를 import하면 서버 컴포넌트가 클라이언트 컴포넌트가 됩니다. 서버컴포넌트가 클라이언트컴포넌트를 임포트하는건 아무 영향 없습니다.

  2. 네 그런데 서버컴포넌트를 import가 아니라 props로 전달하면 서버컴포넌트로 쓸 수 있습니다. children도 props라 서버컴포넌트를 전달 가능하고요. 레이아웃은 서버컴포넌트로 놔두는 게 좋습니다.

  3. 일단 서버 재시작 및 .next 삭제 해보시고 스타일드 컴포넌트를 쓴 곳을 전부 use client로 해보세요.

밍끼님의 프로필 이미지
밍끼
질문자

import React from 'react';
import Logo from '@/components/atoms/Logo';
import Text from '@/components/atoms/Text';
import SideBarBody from '@/components/molecules/SideBarBody';
import SideBarFooter from '@/components/molecules/SideBarFooter';
import SideBarHeader from '@/components/molecules/SideBarHeader';
import SideBar from '@/components/organisms/SideBar/SideBar';
import { PropsWithRequiredChildren } from '@/types/common';
import LogoutButton from '../components/LogoutButton/LogoutButton';
import NavWrap from '../components/NavWrap/NavWrap';
import SearchInput from '../components/SearchInput/SearchInput';
import * as S from './AdminLayout.style';

export interface AdminLayoutProps extends PropsWithRequiredChildren {}

const AdminLayout = ({ children }: AdminLayoutProps) => {
  return (
    <>
      <SideBar>
        <SideBarHeader>
          <Logo />
          <Text
            $color="var(--color-white)"
            $bold={500}
            $size={1.8}
            $spacing={[4.8, 0, 0, 0]}
          >
            유저네임
          </Text>
          <Text $color="#F4F4F8" $bold={400} $size={1.4}>
            부가정보
          </Text>
        </SideBarHeader>
        <SideBarBody>
          <NavWrap />
        </SideBarBody>
        <SideBarFooter>
          <LogoutButton />
        </SideBarFooter>
      </SideBar>
      <S.Main>
        <SearchInput />
        {children}
      </S.Main>
    </>
  );
};

export default AdminLayout;

아하 답변 감사합니다. 현재 이렇게 style.ts에서 styled-component 를 불러와서 S. 으로 사용하여 Layout에 이벤트나 훅이 들어가지 않는데도 'use client'를 사용해야 에러가 일어나지않았던거군요

밍끼님의 프로필 이미지
밍끼

작성한 질문수

질문하기