Next.js

Next.js는 React 기반의 웹 프레임워크로, 서버 사이드 렌더링과 정적 페이지 생성을 지원하여 성능을
향상시키고, 개발자들이 간편하게 웹 애플리케이션을 구축할 수 있도록 도와줍니다.

시작하기

npx create-next-app@latest

 

위에 명령어를 입력하면 이러한 문구가 보이실 것입니다. 

이때 자기가 원하는 기능에 맞춰 No / Yes 를 누르시면 됩니다.

파란색으로 칠한 건 제가 원하는 기능에 맞춰 고른 부분이라 신경쓰지 않으셔도 됩니다.

What is your project named? my-app
Would you like to use TypeScript? No / Yes
Would you like to use ESLint? No / Yes
Would you like to use Tailwind CSS? No / Yes
Would you like to use `src/` directory? No / Yes
Would you like to use App Router? (recommended) No / Yes
Would you like to use Turbopack for `next dev`?  No / Yes
Would you like to customize the default import alias (@/*)? No / Yes
What import alias would you like configured? @/*

 

여기까지 하셨다면 밑에 사진처럼 다양한 폴더가 생성되는 것을 보실 수 있습니다. 

npm run dev

터미널에 위에 처럼 npm run dev를 하시면 next 가 실행되는 것을 볼 수 있습니다.

이제부터 next 를 공부하거나 시작하실 수 있습니다!!

 

 

 

 

 

 

경로 설정하기

React 에서는 react-router-dom을 이용해서 URL을 조작하거나 해당 파일을 URL에 연결하여 경로를 설정했습니다.

하지만 Next.js 에서는 폴더명만 신경 써 주면 Next.js 에서 알아서 경로를 설정해 줍니다. 

하지만 신경써 주어야 할 부분은 app 폴더명 안에 만들어 주어야 합니다.

만약 sales 폴더 안에 page.tsx 말고 pages.tsx, home.tsx 같은 파일이 있다면 sales 경로로 갔을 때 다른 파일을 렌더링 할까요??

결론은 아닙니다. Next.js 는 page.tsx 만을 찾아서 렌더링 해줍니다.

 

중첩 페이지

만약 Navbar Component 를 모든 페이지에 적용하고 싶다면 어떻게 해야 할까요??

페이지 하나하나에 해당 Component 를 집어넣기에는 중첩 코드가 발생하고 불필요한 비용이 발생합니다.

이때 도움을 주는 기능은 layout 입니다. layout.tsx라는 파일을 사용하면 중첩 페이지를 적용하실 수 있습니다.

Page 폴더 안에 layout.tsx 를 설정하고 하위 폴더에 page.tsx를 만들어 두면 자동적으로 layout.tsx 에서 설정한 {children} 안에 해당 페이지가 들어가게 됩니다. 아래 코드를 자세히 보시면 이해가 빠르실 것입니다.

import React from 'react';

interface RootLayoutProps {
  children: React.ReactNode;
}

const RootLayout: React.FC<RootLayoutProps> = ({ children }) => {
  return (
    <div>
     {children}     <---- 이 부분에 하위 폴더 page.tsx 가 들어갑니다.
    </div>
  );
};

export default RootLayout;

 

Metadata

주어진 데이터의 의미, 구조, 형식, 처리 방법 등을 설명합니다. 웹 개발에서 메타데이터는 웹 페이지의 정보를 설명하고 검색 엔진이나 소셜 미디어 플랫폼이 페이지를 이해하고 적절하게 표시할 수 있도록 도와줍니다.

export const metadata = {
  title: 'Next.js',
  description: 'Generated by Next.js',
}

 

metadata를 설정할 때 주의할 점은 page, layout 파일에만 메타 데이터를 적용시킬 수 있습니다.

또한 "use client" 를 사용하는 페이지에서는 metadata를 사용하실 수 없습니다. "use client"는 뒤에 배우게 됩니다.

 

Next.js에는 향상된 SEO 및 웹 공유성을 위해 애플리케이션 메타데이터(ex: HTML head 엘리먼트 내의 meta 및 link 태그)를

정의하는 데 사용할 수 있는 메타데이터 API가 있습니다.

import { Metadata } from "next"

export const metadata:Metadata = {
  title: {
    template: "%s | Next Movies",
    default: "Loading..."
  },
  description: 'Generated by Next.js',
}

// 다른곳에서 
export const metadata:Metadata = {
  title: "not found"
}

 

폴더명 그룹화 하기

폴더명으로 쉽게 개발하고 폴더를 그룹화하면 어떻게 해야 할까요?? 밑에 사진처럼 해주시면 됩니다.

이러한 방법은 가독성 측면에서 매우 좋다고 생각합니다. 

즉 localhost3030 으로 들어가게 된다면 (Home)/page.tsx를 볼 수 있게 되며, localhost3030/shop으로 들어가게 된다면

(Shop)/shop/page.tsx를 볼 수 있게 됩니다. 가독성 측면에서 매우 좋죠??

 

params

http://localhost:3000/movies/123?country=kr&hobby=soccer 

라는 주소가 있을 때 123?country=kr&hobby=soccer 이라는 정보를 어떻게 가져올 수 있을까요??

 

next.js 에서는 파라미터에서 기본적으로 props라는 기능을 지원해 줍니다. 

props를 이용해서 params 정보를 가져올 수 있는 것이죠. 여기서 [id]라는 폴더명이 중요합니다. [id]에 자동적으로 내가 설정한 

주소의 상세 정보(123) 을 적용시켜 이용할 수 있습니다. 이걸 이용해서 동적으로 여러 데이터를 가져올 수 도 있겠죠.

 

데이터를 가져오는 방법

React 에서 데이터를 가져오는 다양한 방법이 있지만 대부분 사용하는 방법은 tanstack-query 를 사용하는 방법입니다.

그냥 데이터를 가져올 수 있지만 해당 라이브러리를 사용하면 데이터를 캐싱하고 보관하는 기능도 지원해 주기 때문에 많이들 사용합니다.

하지만 next.js 에서는 해당 라이브러리를 사용하지 않고도 데이터를 자동으로 캐싱해서 보관하는 기능을 지원해 줍니다.

import React from 'react';

export const metadata = {
  title: "Home"
}

const URL = "https://nomad-movies.nomadcoders.workers.dev/movies";

async function getMovies() {
  const response = await fetch(URL);
  const data = await response.json();
  return data
}

const HomePage = async () => {

  const movies = await getMovies()

  return (
    <div>
      {JSON.stringify(movies)}
    </div>
  )
}

export default HomePage

 

주의해야 할 점은 함수 컴포넌트 자체에 async 를 사용하여 promise 를 적용시켜 주어야 합니다.

만약 해당 getMovies 함수가 오래 걸려서 데이터를 불러오고 있는 중이라면 어떤 화면을 보여주어야 할까요?? 

next.js 에서는 loading 이라는 파일 형식을 지원해 줍니다.

간단하게 데이터를 불러오는 파일이 들어 있는 폴더에 loading.tsx 라는 파일을 만들기만 해주면 자동적으로 next.js 는 

데이터를 불러오면서 loading.tsx 에 만들어 둔 내용들을 임시로 보여줍니다.

이 기능을 활용하면 사용자 경험을 향상시킬 수 있으며, 로딩 중임을 명확히 전달하여 사용자가 페이지가 멈춘 것이 아니라 데이터를 기다리고 있음을 알 수 있습니다.

Suspense

데이터들을 여러개 가져오고 보여주는 페이지가 있다고 생각해 봅시다.

만약 3개의 데이터를 보여주는 페이지라면 서버에 3개의 데이터를 요청할 것입니다.

이때 한개의 데이터만 먼저 가져오고 나머지 데이터들을 가져오고 있는 중이라면 나머지 데이터가 오기 전까지 화면에는 먼저 온 데이터가 보여지지 않을 수 있습니다. 

이때 사용할 수 있는 기능은 Suspense 라는 기능입니다.

서버에서 데이터를 가져오고 먼저 온 데이터를 차례차례 순서대로 먼저 보여주고 싶다면 Suspense 를 사용하면 됩니다.

 

// MovieVideos

import React from 'react';
import { URL } from '../app/(Home)/page';

const getVideos = async (id:string) => {
  const response = await fetch(`${URL}/${id}/videos`);
  return response.json();
}

const MovieVideos = async ({id}: {id: string}) => {
  const videos = await getVideos(id);
  return (
    <h6>{JSON.stringify(videos)}</h6>
  )
}

export default MovieVideos
import React, { Suspense } from 'react';
import { URL } from '../../../(Home)/page';
import MovieVideos from '../../../../components/movie-videos';
import MovieInfo from '../../../../components/movie-info';


const Movies = async ({params: {id}}: {params: {id: string}}) => {
  return (
    <div>
      <Suspense fallback={<h1>Loading...</h1>}>
        <MovieInfo id={id}/>
      </Suspense>
      <Suspense fallback={<h1>Loading...</h1>}>
        <MovieVideos id={id}/>
      </Suspense>
    </div>
  )
}

export default Movies

 

여기서 fallback={} 은 데이터를 가져오고 있을 때 임시적으로 보여주는 요소 입니다.

 

use client

클라이언트 측에서만 동작해야 하는 상태 관리 로직과 부수 효과 (예: useState, useEffect 등)는 서버 사이드 렌더링 기반인 Next.js 에서 실행될 수 없습니다. 하지만 "use client"를 사용하여 이러한 로직이 클라이언트 측에서만 실행되도록 보장할 수 있습니다

또한 window, document, localStorage와 같은 브라우저 전용 API는 서버 환경에서는 존재하지 않으므로,

이를 사용하는 코드는 반드시 클라이언트 측에서 실행되어야 합니다.

 

즉 쉽게 이야기 하자면 client 측에서 관리해야 하는 코드가 있을 경우 사용합니다.

예를 들어 useEffect, useState, Ref 등 과 같은 Hooks 들을 사용할 때 해당 파일 맨 위에 "use client" 라고 써야 합니다.

고맙게도 개발을 하다 use client 를 사용해 하면 next.js 에서 친절하게 오류로 실수를 알려줍니다

// 클라이언트 전용 컴포넌트
'use client';

import { useState, useEffect } from 'react';

function ClientComponent() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    // 클라이언트 측에서만 실행될 부수 효과
    console.log('Component mounted');
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increase</button>
    </div>
  );
}

export default ClientComponent;

'Next' 카테고리의 다른 글

[Next.js] 이미지 최적화  (4) 2024.09.22
[Next.js] 배포시 console 지우기  (1) 2024.09.20
Next.js MetaData 심화  (0) 2024.07.30
Next.js - 경로  (1) 2024.05.21