프로그래밍/Next

[Next] CSS Modules / Styled JSX / Custom App

라다디 2022. 7. 8. 03:17

1. CSS Modules

넥스트 어플리케이션에 CSS를 추가하는 방법 중 하나는 modules를 사용하는 것이다. 

 

NavBar.module.css

.nav {
  text-decoration: none;
}

이름은 상관 없고 중요한 건 .module.css이다.

css를 작성하고 이 파일을 사용하고 싶은 곳에 자바스크립트 오브젝트로서 import를 시키면 된다. 

import styles from "./NavBar.module.css"

모듈이기 때문에 className="nav"가 아니라 className={styles.nav}처럼 작성해줘야 한다.

이게 작동하는 이유는 .module.css 패턴을 사용했기 때문이다.

이 패턴은 css 모듈이라고 불리는데 이건 개발자로 하여금 평범한 css를 사용할 수 있도록 해준다. 

 

그리고 클래스 이름을 추가해줄 때, 클래스 이름을 텍스트로서 적지 않고 자바스크립트 오브젝트에서의 프로퍼티 형식으로 적는다.

실상 이 클래스의 이름을 살펴본다면 NavBar_nav_무작위 텍스트이다. 

클래스 이름이 무작위이기 때문에 충돌이 나지 않는다는 점이 이 접근 방식의 장점이다. 

즉, 다른 컴포넌트에서도 nav라는 클래스 이름을 사용할 수 있는 것이다.

 

두 가지 스타일을 적용하고 싶다면 아래와 같이 작성할 수 있다.

// 방법 1
className={`${styles.link} ${
router.pathname === "/" ? styles.active : ""
}`}

// 방법 2
className={[
styles.link,
router.pathname === "/about" ? styles.active : "",
].join(" ")}

css 모듈 방식은 두 개의 파일을 가져야 하고 클래스 이름을 기억해야 한다는 단점이 있다. 

 

2. Styled JSX 

NextJS 어플리케이션에서 스타일을 추가하는 또 다른 방법은 NextJS 고유의 방법인 styled jsx를 사용하는 것이다. 

 

style 태그(HTML 태그)를 열고 jsx prop을 넣어주면 된다.

<style jsx>{`
    nav {
      background-color: tomato;
    }
    a {
      text-decoration: none;
    }
`}</style>

styled jsx를 사용하면 위와 같은 클래스 이름을 지니게 된다.

 

모듈들이 독립되어 있어 부모 컴포넌트가 그 클래스 이름을 사용하고 있을지라도 상관이 없다.

스타일들은 오직 styled jsx가 사용된 컴포넌트 내부로 범위가 한정된다. 

 

3. Custom App

Global Styles를 추가하는 한 가지 방법으로는 styled jsx에 와서 global이라는 prop을 추가하는 방법이 있다. 

하지만 styled jsx가 있는 페이지에만 적용이 된다. 

 

모든 페이지들에 전역적으로 스타일링을 하고 싶다면 모든 페이지의 청사진을 커스텀할 수 있는 장소인 App Component에 대해 알아야 한다.

App Component는 기본으로 프레임워크에 포함되어 있는 NextJS가 모든 페이지를 렌더링할 수 있게 하는 컴포넌트이다.

 

App Component를 커스터마이즈 하기 위해서는 _app.js라는 파일을 만들어야 한다. 

NextJS는 먼저 App을 본 뒤 페이지의 내용물을 렌더링한다.  

NextJS가 index를 렌더링하기 전에 _app.js를 먼저 확인할거고, 그 다음에 index.js의 내용물을 _app.js에 기반해서 렌더링하는 것이다. 

_app.js는 어떻게 페이지가 있어야 하는지, 어떤 컴포넌트가 어떤 페이지에 있어야만 하는지 알려주는 청사진이다. 

 

NextJS는 _app.js를 불러올거고, App 함수를 두 prop과 함께 부른다. 

export default function App({Component, pageProps})
 

 

만약 About 페이지를 렌더링하길 원한다면 NextJS는 about.js 파일로 가서 컴포넌트를 가져다가 Component Prop에 전달한다. 

export default function App({About, pageProps})
 
그리고 나서 페이지(About)와 함께 추가로 작성한 것들을 리턴한다. 
export default function App({ Component, pageProps }) {
  return (
    <div>
      <Component {...pageProps} />
      <span>Hello</span>
    </div>
  );
}
export default function App({ About, pageProps }) {
  return (
    <div>
      <About {...pageProps} />
      <span>Hello</span>
    </div>
  );
}

 

여러 페이지에서 중복되는 코드를 _app.js에 넣을 수 있다. 

import NavBar from "../components/NavBar";

export default function App({ Component, pageProps }) {
  return (
    <>
      <NavBar />
      <Component {...pageProps} />
    </>
  );
}

이렇게 작성한다면 index 페이지에도, about 페이지에도 NavBar가 필요 없다.

왜냐하면 이제 모든 페이지는 여기에 NavBar 밑에 렌더링 될 것이기 때문이다. 

 

원한다면 Global Styles를 추가해줄 수 있다. 

import NavBar from "../components/NavBar";

export default function App({ Component, pageProps }) {
  return (
    <>
      <NavBar />
      <Component {...pageProps} />
      <style jsx global>{`
        a {
          color: white;
        }
      `}</style>
    </>
  );
}

 

NextJS로 앱을 만들 때는 global css파일을 import할 수 없다.

만일 index.js에 global css 파일을 import하려고 하면 Custom App 이외의 파일들에서는 임포트할 수 없다는 에러가 발생한다.

페이지나 컴포넌트 내에 css를 import하고 싶다면 반드시 module이어야만 한다. 

하지만 _app.js는 global css파일을 import할 수 있다.

 

※ 타입스크립트 사용시 _app.js

더보기
import { AppProps } from 'next/dist/shared/lib/router/router'

export default function App({ Component, pageProps }: AppProps) {
    return < Component {...pageProps} />
}

 

정리

NextJS는 App 컴포넌트를 사용하여 page를 초기화하는데 이를 재정의하고 페이지 초기화를 제어할 수 있다.

기본 App을 재정의하려면 pages/_app.js 파일을 만든다.

 

파일명.module.css 파일 형태를 제외한 모든 나머지 css파일들은 _app.js에서만 import해와서 사용해야 한다.

(global css간의 충돌을 피하기 위함)

 

Recap 

CSR (클라이언트 사이드 렌더링)

브라우저가 리액트 코드를 다운받고 모든걸 그려줘야 하기 때문에 하얀 화면이 보여질 수 있다.

NextJS 어플리케이션에서는 페이지가 사용자가 가기 전에 미리 만들어진다.
컴포넌트의 초기 상태는 자동적으로 HTML로 렌더링된 상태가 된다.

ReHydration = Hydration
NextJS가 백엔드 상에서 리액트를 돌려 HTML 페이지를 사전 생성한다.
사용자가 웹 사이트에 들어갈 때 하얀 화면이나 로딩 단계 없이 이 HTML 페이지를 본다.
모든 자바스크립트가 다 다운로드 된 뒤에는 리액트가 다시 주도권을 가져서 모든 게 일반적인 리액트처럼 동작한다.
그래서 useState같은 평범한 리액트의 모든 것을 사용할 수 있는 것이다.

NextJS를 다룰 때는 하나의 큰 어플리케이션이 아니라 각각의 나뉘어진 페이지를 생각해야 한다.

 

Custom App 컴포넌트는 NextJS에 의해 페이지를 렌더링할 때마다 사용된다. 

About 페이지를 렌더링해야 할 때마다 About 컴포넌트를 가지고 _app.js 내의 App함수(함수명 상관x)를 호출한다.

그리고 NextJS는 그 렌더링하기를 원하는 페이지를 Component Prop에 넣어주고 그리는 작업을 한다. 

이건 모두 자동적으로 일어나는 일이다. 

커스텀을 원하는 게 아니라면 _app.js 파일을 직접 만들 필요가 없다.

 


📌 아래 강의의 내용을 정리한 글입니다.