Next.js에 대해 알아보자 #2
포스팅 미리 보기
- metadata로 웹사이트 title 바꾸는 법
- dummyjson을 활용해보기
- 신기술 suspense 사용해보기(feat. 동적라우팅)
- next에서 로딩 화면 간편하게 만들기
아래의 설명보다 좀 더 자세한 설명을 원한다면 공식문서를 참고하는 것이 좋다!

metadata로 웹사이트 title 바꾸는 법
본격적인 내용에 들어가기에 앞서 아주 간단하게 몸풀기하고 들어가도록 하겠다. 몸풀기로 준비한 것은 metadata라는 것으로 웹사이트 title을 바꾸는 법이다.
//layout.tsx
//정적인 페이지 사용시 쓸 수 있는 코드
export const metadata = {
title: 'Thank you next!',
description: '넥스트야 고마워',
}
나는 layouy.tsx안에 metadata를 만들었다. 여기서 title은 코드에서도 바로 보이듯이 title : '적고싶은 글 내용', 을 적음 된다.
아래에 있는 description은 빌드 후 개발자 모드를 켜서 보면 head 속에 생기게 된다
공식문서에는 metadata의 다양한 사용법에 대해 알려주고 있으니 참고해보길 바란다.
dummyjson을 활용해보기
현재 나의 파일구조는 위와 같다.
간단하게 많은 데이터가 있는 json을 사용해보기 위해 dummyjson을 활용해보았다.
//dummyapi 불러오는 코드
//물품 목록 불러오는 div 컴포넌트
//useEffect와 useState 할용
//api output 그대로 띄움
"use client";
import { useState, useEffect } from "react";
interface Product {
id: number;
title: string;
description: string;
map(element: (product) => JSX.Element): any;
}
export default function client() {
const [product, setProduct] = useState<Product>();
// const [isLoading, setIsLoad] = useState<boolean>(true);
useEffect(() => {
fetch("https://dummyjson.com/products")
.then((res) => res.json())
.then((data) => setProduct(data.products));
},[]);
console.log(product);
return(
<div>
{product && product.map((item)=>{
//참일때만 map돌리게
return(
<div key={item.id}>
<h1>{item.title}</h1>
<p>{item.description}</p>
</div>
)
})}
</div>
);
}
위 코드는 client > page.tsx에 있는 코드이다.
간단하게 말하자면 dummy api를 불러와 전부 보여주는 코드라고 볼 수 있다.
결과화면은 아래와 같다.
그 다음에는 아래와 같은 텍스트가 뜨는 화면을 만들어보도록 하겠다.
나는 Next.js 13 이상에서 지원하는 비동기 서버 컴포넌트를 사용해보고 싶었다. 따라서 아래의 코드를 짜게되었다.
async function getItems(id:string) {
await new Promise((res) => setTimeout(res,3000))
const response = await fetch(`https://dummyjson.com/products/${id}`)//템플릿 리터럴로 주소에 id 넣기
const json = await response.json()
return json
}
export default async function GetItem({id}: {id:string}){
const item = await getItems(id)
return <h2>{JSON.stringify(item.title)}</h2>
}
components > Get-Item.tsx파일이고, 위의 파일을 보면 눈에 뜨는 건 promise와 setTimeout을 사용하여 인위적으로 3초간 지연시키고 데이터를 가져오게 만들었다. 그리고 GetItem 서버 컴포넌트에는 전 버전의 Next.js에서 사용하던 getServerSideProps나 getStaticProps 같은 특별한 함수 없이도 서버 사이드에서 데이터를 가져올 수 있게 await을 직접 사용하였다.
async function getNextItem(id:string) {
await new Promise((res) => setTimeout(res,5000))
const nextId:number = parseInt(id,10) + 1
const response = await fetch(`https://dummyjson.com/products/${nextId.toString()}`);
return response.json()
}
export default async function GetNextItem({id}: {id:string}){
const item = await getNextItem(id)
return <h4>{JSON.stringify(item.title)}</h4>
}
components>Get-Next-Item.tsx파일이고, 이 파일도 위의 Get-Item.tsx과 비슷하게 인위적으로 5초 지연시키고, await을 사용하여 서버 사이드에서 데이터를 가져오는데 다른 점은 다음 아이템을 가져와야하기에 문자열 id를 숫자로 변환시키고 +1을 해 Get-Item에서 불러온 아이템의 다음 아이템을 가져오게된다.
신기술 suspense 사용해보기(feat. 동적 라우팅)
컴포넌트를 다 만들었으니 이제는 사용해볼 시간이다.
import { Suspense } from "react"
import GetItem from "../../components/Get-Item";
import GetNextItem from "../../components/Get-Next-Item";
export default async function Items({ params }: { params: { id: string } }) {
//params는 Next.js의 동적 라우팅 시스템에서 URL 파라미터를 나타내는 객체
//params 객체를 prop으로 받음
return (
<div>
<h1>강원의 상점</h1>
<Suspense fallback={<div>Loading 1</div>}>
<GetItem id={params.id}/>{/* 이게 로딩될 때 까지 Loading 1이 뜸, suspense안 GetItem 같은 건 무조건 컴포넌트화 해서 써야함 */}
</Suspense>
<Suspense fallback={<div>Loading2</div>}>
<GetNextItem id={params.id}/>
</Suspense>
</div>
);
}
items>[id] 파일인데, id를 감싼 대괄호는 무엇일까?
바로 동적 라우팅이다. 이렇게 대괄호로 감싸준다면, 해당 부분이 URL의 변수 부분이 될 것임을 Next.js에 알려준다. 예를 들어, /items/1, /items/abc, /items/product-name같은 것들이 이 동적 라우팅과 매칭이 되는 것이다.
다시 코드로 넘어가면 눈에 띄는게 있다. 바로 <Suspense>라는 것인데. <suspense>는 자식 요소가 로드되기 전까지 화면에 대체 UI를 보여줍니다. 라고 공식문서에 설명이 되어있다. suspense는 리액트에서 React 18 (2022년 3월 출시)에서 Suspense의 서버 사이드 렌더링 지원이 추가된 기능이다.
나도 위 파일에서 suspense를 사용해보았다.
<div>
<h1>강원의 상점</h1>
<Suspense fallback={<div>Loading 1</div>}>
<GetItem id={params.id}/>{/* 이게 로딩될 때 까지 Loading 1이 뜸, suspense안 GetItem 같은 건 무조건 컴포넌트화 해서 써야함 */}
</Suspense>
<Suspense fallback={<div>Loading2</div>}>
<GetNextItem id={params.id}/>
</Suspense>
</div>
우리는 위에서 components 폴더 안 setTiemOut으로 강제 지연시키는 비동기 서버 컴포넌트인 Get-Next-Item.tsx, Get-Item.tsx를 만들었다. 따라서 <Suspense>를 쓸 수 있게 되었다.
위의 코드를 보면 fallback이라는 것이 있는데. <GetItem> children에 필요한 모든 코드와 데이터가 로드될 때까지 Loading 1 fallback을 보여준다.
위처럼 사용되는 것을 볼 수 있다.
suspense를 사용하기 위해서는 유의사항이 있는데 위의 주석에도 있듯 suspense안 GetItem 같은 children은 무조건 컴포넌트화 해서 써야한다. 이제서야 내가 왜 components 폴더 안 setTiemOut으로 강제 지연시키는 비동기 서버 컴포넌트인 Get-Next-Item.tsx, Get-Item.tsx를 만들었는지 알 수 있을 것이다. (다 큰 그림!)
마지막으로는 리스트 형식으로 item들의 id를 보여주고, 그걸 클릭하면 아까 <Suspense>를 사용한 곳으로 넘어갈 수 있도록 만들었다.
코드는 아래와 같다.(Navigation은 필요없어서 주석처리했다.)
import { Suspense } from "react"
import GetItem from "../../components/Get-Item";
import GetNextItem from "../../components/Get-Next-Item";
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
export default async function Items({ params }: { params: { id: string } }) {
await delay(2000);
return (
<div>
<h1>강원의 상점</h1>
<Suspense fallback={<div>Loading 1</div>}>
<GetItem id={params.id}/>{/* 이게 로딩될 때 까지 Loading 1이 뜸, suspense안 GetItem 같은 건 무조건 컴포넌트화 해서 써야함 */}
</Suspense>
<Suspense fallback={<div>Loading2</div>}>
<GetNextItem id={params.id}/>
</Suspense>
</div>
);
}
next에서 로딩 화면 간편하게 만들기
그리고 delay함수는 원래는 없었으나 next에서 loading을 간편하게 할 수 있는 것을 보여주기 위해 넣어봤다. 위의 list에서 아이템을 클릭하면 아래와 같이 로딩화면이 뜨고 불러와진다.
코드는 아주 간단하게 items>[id}안 loading.tsx를 만들면 로딩되는 시간동안 이 파일 안 요소가 보여지게 된다. 코드는 아래와 같다
export default function Loading(){
return <h2>Loading............</h2>
}
이번 포스팅은 여기서 마무리하도록 하겠다.
