2차 공부/TIL

24.08.26 Next JS CSS

공대탈출 2024. 8. 26. 19:30
body {
    font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell,
        "Open Sans", "Helvetica Neue", sans-serif;
    background-color: black;
    color: white;
    font-size: 18px;
}

a {
    color: inherit;
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}

전역적으로 설정되길 원하는 css파일을 생성하고, 작성한다.

그리고 해당 css파일을 전역 layout파일에 import하면 모든 페이지에서 해당 css가 적용된다.

reset.css나 전역적으로 적용될 style을 이렇게 적용시키면 된다.


css-in-js 라이브러리를 사용하지 않고 모듈css를 사용해보자.

//navigation.module.css
.nav {
    background-color: red;
}
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import styles from "../styles/navigation.module.css";

export default function Navigation() {
    const path = usePathname();
    return (
        <nav className={styles.nav}>
            <ul>
                <li>
                    <Link href="/">Home</Link> {path === "/" ? "🔥" : ""}
                </li>
                <li>
                    <Link href="/about-us">About-us</Link> {path === "/about-us" ? "🔥" : ""}
                </li>
            </ul>
        </nav>
    );
}

module.css파일을 한 객체처럼 styles로 불러온다.

그리고 className속성에 객체의 값을 빼내듯이 styles.nav형식으로 지정해준다.

여기서 중요한 것은 module.css파일에서 스타일을 작성할 때에는 .을 꼭 붙여주어야 한다는 것이다.

 

뭐 어쨌든, module.css파일에서 만들어진 style을 적용시키면 이렇게 태그뒤에 랜덤값이 붙는다.

이것으로 각각의 요소를 분리하기 때문에 className이 겹쳐 버그가 일어날 가능성이 낮아진다.


NextJS의 generateMetadata()메서드를 사용하면 동적으로 metadata를 추가할 수 있다.

import { Suspense } from "react";
import MovieInfo, { getMovie } from "../../../../components/movie-info";
import MovieVideos from "../../../../components/movie-videos";

interface IParams {
    params: { id: string };
}

export async function generateMetadata({ params: { id } }: IParams) {
    const movie = await getMovie(id);
    return {
        title: movie.title,
    };
}

export default async function MovieDetail({ params: { id } }: IParams) {
    return (
        <div>
            <Suspense fallback={<h1>Loading Movie Info</h1>}>
                <MovieInfo id={id} />
            </Suspense>
            <Suspense fallback={<h1>Loading Movie Video</h1>}>
                <MovieVideos id={id} />
            </Suspense>
        </div>
    );
}
import Link from "next/link";
import { API_URL } from "../app/(home)/page";
import styles from "../styles/movie-info.module.css";

export async function getMovie(id: string) {
    // await new Promise((resolve) => setTimeout(resolve, 5000));
    const response = await fetch(`${API_URL}/${id}`);
    return response.json();
}

export default async function MovieInfo({ id }: { id: string }) {
    const movie = await getMovie(id);
    return (
        <div className={styles.container}>
            <img src={movie.poster_path} className={styles.poster} alt={movie.title} />
            <div className={styles.info}>
                <h1 className={styles.title}>{movie.title}</h1>
                <h3>⭐{movie.vote_average.toFixed(1)}</h3>
                <p>{movie.overview}</p>
                <a href={movie.homepage} target={"_blank"}>
                    Homepage &rarr;
                </a>
            </div>
        </div>
    );
}

이렇게 영화 상세페이지에서 영화제목을 title로 설정할수있다. 다만 여기서 의구심이 드는 것은 API요청을 두번해야한다는 것이다.

하지만 NextJS는 그것까지 염두에 두고, 같은 API요청은 캐싱된 데이터를 자동으로 보내준다. 따라서 metadata를 위한 getMovie함수는 캐싱된 데이터가들어가 두번 요청을 하지 않는 것이다.