자동 이미지 최적화 기능
- 크기최적화 : 각 기기에 맞는 크기의 이미지를 자동으로 제공
- 로컬 이미지 설정
import { Product } from "@/type/product";
import Image from "next/image";
const NewProductList = async () => {
const res = await fetch("http://localhost:4000/products", {
cache: "no-store",
});
const data: Product[] = await res.json();
const newData = data.filter((p) => p.isNew);
return (
<div className="flex gap-2 oveflow-auto w-full">
<div className="w-max flex gap-2">
{newData.map((product) => (
<div className="flex gap-2 w-[250px] border rounded-sm" key={product.id}>
<Image
className="rounded-sm object-scale-down"
width={80}
height={80}
src={product.images}
alt={product.title}
/>
<div className="flex flex-col justify-between">
<div>
<h2 className="text-md font-medium">{product.title}</h2>
<p className="mt-4 font-thin">{product.price.amount}$</p>
</div>
</div>
</div>
))}
</div>
</div>
);
};
export default NewProductList;
import Image from 'next/image'
export default function Page() {
return (
<Image
src="<network-image>"
alt="Picture of the author"
width={500}
height={500}
/>
)
}
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: false,
images: {
remotePatterns: [
{
protocol: "https",
hostname: "fakestoreapi.com",
pathname: "/**",
},
],
formats: ["image/avif", "image/webp"],
},
};
Next.js가 제공하는 메타 데이터를 정의하기 위한 두 가지 방법
1. Config 기반 메타데이터 : layout.js또는 page.js파일에서 정적 메타데이터 객체 또는 동적 generateMetadata함수를 내보낸다.
2. 파일 기반 메타데이터 : 라우트 세그먼트에 정적 또는 동적으로 생성된 특별한 파일을 추가한다. 두 옵션 모두에서 Next.js는 페이지에 대한 관련 head요소를 자동으로 생성한다.
// layout.tsx | page.tsx
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: '...',
description: '...',
}
export default function Page() {}
// app/products/[id]/page.tsx
import type { Metadata, ResolvingMetadata } from 'next'
type Props = {
params: { id: string }
searchParams: { [key: string]: string | string[] | undefined }
}
export async function generateMetadata(
{ params, searchParams }: Props,
): Promise<Metadata> {
// 경로 매개변수 읽기
const id = params.id
// 데이터 가져오기
const product = await fetch(`https://.../${id}`).then((res) => res.json())
return {
title: product.title,
}
}
export default function Page({ params, searchParams }: Props) {}
favicon.ico, apple-icon.jpg, icon.jpgopengraph-image.jpg 및 twitter-image.jpgrobots.txtsitemap.xmlNext.js에서는 public 폴더를 사용하여 정적 파일을 쉽게 제공할 수 있다. public 폴더 내의 파일은 기본 URL(/)을 기준으로 참조할 수 있다.
ex1) Logo.png
import Image from 'next/image'
import Logo from "/public/assets/logo.png";
<Image height={40} src={Logo} alt="logo"></Image>
next/font를 사용하면 폰트를 자동으로 최적화하고 외부 네트워크 요청을 제거하여 개인정보 보호와 성능을 향상시킬 수 있음next/font/google에서 사용할 폰트를 가져와 함수로 사용
import { Inter } from 'next/font/google'
const inter = Inter({
subsets: ['latin'],
display: 'swap',
})
export default function RootLayout({ children }) {
return (
<html lang="en" className={inter.className}>
<body>{children}</body>
</html>
)
}
import { Inter, Roboto_Mono } from 'next/font/google'
export const inter = Inter({
subsets: ['latin'],
display: 'swap',
})
export const roboto_mono = Roboto_Mono({
subsets: ['latin'],
display: 'swap',
})
import { inter } from './fonts'
export default function Layout({ children }) {
return (
<html lang="en" className={inter.className}>
<body>
<div>{children}</div>
</body>
</html>
)
}
import localFont from 'next/font/local'
// Font files can be colocated inside of `app`
const myFont = localFont({
src: './my-font.woff2',
display: 'swap',
})
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en" className={myFont.className}>
<body>{children}</body>
</html>
)
}
사용법
import Script from 'next/script'
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
<Script src="https://example.com/script.js" />
</html>
)
}
스크립트 로딩 전략을 세부적으로 조정할 수 있다:
beforeInteractive: Next.js 코드 및 페이지 하이드레이션 전에 스크립트 로드afterInteractive: (기본값) 페이지 하이드레이션 후 스크립트 로드lazyOnload: 브라우저 유휴 시간에 스크립트 로드worker: (실험적) 웹 워커에서 스크립트 로드api>apiTest를 만든 후 하위에 route.ts파일 생성
export async function GET(request: Request) {
console.log("GET /api/test");
}
export async function POST(request: Request) {
console.log("POST /api/test");
}
export async function PUT(request: Request) {
console.log("PUT /api/test");
}
export async function DELETE(request: Request) {
console.log("DELETE /api/test");
}
export async function PATCH(request: Request) {
console.log("PATCH /api/test");
}
Thunder Client로 테스트
POST / http://localhost:3000/api/test
"use server";
import { Product } from "@/type/product";
import { BASE_URL } from "@/constants/api";
export async function getProducts() {
const res = await fetch(`${BASE_URL}/products`, {
cache: "no-store",
});
const data: Product[] = await res.json();
return { data };
}
ex) cart같은 곳 값 넣을 때
'use server';
import { revalidatePath } from 'next/cache';
import { redirect } from 'next/navigation';
export async function addItemToCart(formData: FormData) {
const { itemId, quantity } = formData.get('itemId'), formData.get('quantity');
const cart = await fetch({...});
revalidatePath('/cart');
redirect('/cart');
}
Next.js는 대부분의 영역에서 fetch함수를 기반으로 캐싱을 한다.
Next.js의 fetch API를 기반으로 Next.js에서 확장한 새로운 fetch API이기 떄문이다.
server-actions.ts 설정
// server-action.ts
export async function rePath() {
revalidatePath("/");
}
export async function reTag() {
revalidateTag("products");
}
import { Product } from "@/type/product";
import Image from "next/image";
type Props = {
params: {
id: string;
};
};
const ProductModal = async ({ params }: Props) => {
const id = parseInt(params.id, 10);
const res = await fetch(`http:localhost:4000/products/${id}`, {
cache: "no-store",
});
const data: Product = await res.json();
return (
<div className="fixed rounded-md text-black bg-white/90 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[300px] h-[300px]">
<div className="flex flex-col p-5 gap-2 items-center">
<Image
src={data.images}
alt={data.title}
width={100}
height={100}
className="w-[100px] h-[100px] object-cover"
></Image>
<div className="text-lg font-bold ">{data.title}</div>
<div className="line-clamp-3">{data.description}</div>
<button className="bg-gray-800 text-white px-4 py-2 rounded-md">
View Detail
</button>
</div>
</div>
);
};
export default ProductModal;