NextJS에는 일부 보호된 파일명이 있다.
이 파일명들은 app/폴더(부 폴더 포함) 내부에서 생성될 때만 보호된다.
app/폴더 외부에서 생성될 경우 이 파일명들을 특별한 방식으로 처리하지 않는다.
다음 목록은 NextJS에서 보호된 파일명들이다.
page.js => 신규 페이지 생성 (예: app/about/page.js은 /about page을 생성)
layout.js => 형제 및 중첩 페이지를 감싸는 신규 레이아웃 생성
not-found.js => ‘Not Found’ 오류에 대한 폴백 페이지(형제 또는 중첩 페이지 또는 레이아웃에서 전달된)
error.js => 기타 오류에 대한 폴백 페이지(형제 또는 중첩 페이지 또는 레이아웃에서 전달된)
loading.js => 형제 또는 중첩 페이지(또는 레이아웃)가 데이터를 가져오는 동안 표시되는 폴백 페이지
route.js => API 경로 생성(즉, JSX 코드가 아닌 데이터를 반환하는 페이지, 예: JSON 형식)
보호된 파일명 공식 문서 : https://nextjs.org/docs/app/api-reference/file-conventions
이름.module.css 파일을 만들고
main-header.js파일에서 import main-header.module.css 파일을 가져와서
import classes from './main-header.module.css'
<header className={classes.header}> ...
<nav className={classes.nav}> ...
이렇게 사용하면 된다
Next.js에서 이미지를 사용할때는 Image라는 태그를 next/image에서 import해와서 사용하는 것이 좋다.
이미지 컴포넌트가 페이지를 로드할때 불필요한 깜빡임이나 새로고침이 일어나지 않게 하려면,
가능한 빨리 로딩 될 필요가 있다.
import Image from 'next/image'
...
<Image src={logoImg} alt = "A plate with food on it" priority/>
우선적으로 로딩되게 하는 priority 속성을 주면 해결된다.
fill 속성을 사용하면 부모 요소에 꽉차도록 이미지가 적용된다
(주의: fill은 부모요소가 포지셔닝 된것만 적용됨)
<Image src="/image.jpg" fill/>
object-fit: cover 속성을 사용해서 브라우저를 줄이거나 늘렸을 때 이미지 비율이 깨지지 않게 막을 수 있다
<Image src="/image.jpg" style={{ objectFit: "cover" }} fill />
Next.js는 기본적으로 서버 사이드 랜더링으로 돌아가지만,
몇몇 페이지같은 경우 클라이언트 사이드 랜더링으로 짜야 할 필요가 있다 ex> 5초마다 바뀌는 그림
클라이언트 컴포넌트를 작성하려면 간단하게 'use client'를 파일 맨 위에 추가하면 된다.
이런식으로 쓰면 된다.
import { usePathname } from 'next/navigation'
...
export default function Header() {
const path = usePathname();
...
<Link href="/meals" className={ path.startsWith('/meals')
? classes.active : undefined}>Browse Meals</Link>
<Link href="/community" className={ path === '/community'
? classes.active : undefined}>Foodies Community</Link>
usePathname() 훅을 이용해서 현재 경로를 탐지하고,
현재 어떤 페이지에 있는지 Nav바가 보여주게 하이라이트 할 수 있다.
그러나 클라이언트 컴포넌트는 최대한 아랫단계의 트리에 작성하는 것이 좋다.
따라서 nav-link.js 파일을 만들고,
'use client';
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import classes from './nav-link.module.css'
export default function NavLink({href,children}) {
const path = usePathname();
return (
<Link href={href} className={path.startsWith(href)
? `${classes.link} ${classes.active}`
: classes.link}>
{children}
</Link>
)
}
메인 헤더에서 클라이언트 컴포넌트를 import 해서 사용하는 것이 좋다.
특정 부분을 제외한 나머지 부분을 서버에서 계속 랜더링되게 할 수 있다.
...
import classes from './main-header.module.css'
import NavLink from './nav-link'
export default function Header() {
return (
<>
...
<nav className={classes.nav}>
<ul>
<li>
<NavLink href="/meals">Browse Meals</NavLink>
</li>
<li>
<NavLink href="/community">Foodies Community</NavLink>
</li>
</ul>
</nav>
</header>
</>)
}
npm install better-sqlite3
로컬에서 세팅없이 바로 데이터베이스 이용할 수 있게 함
깔고 initdb.js 파일 루트 디렉토리에 놓고, 루트 디렉토리에서
node initdb.js 실행하면 meals.db가 생성됨
loading 은 페이지와 연관된 다른 페이지들에 로딩페이지를 보여주는 파일명이다.
현재 page들과 하위 page들이 로딩중일때 이 컴포넌트가 실행된다
// lib>meals.js
import sql from 'better-sqlite3'
const db = sql('meals.db');
export async function getMeals() {
await new Promise((resolve)=> setTimeout(resolve,2000));
return db.prepare('SELECT * FROM meals').all();
}
//meals>page.js
// 이런식으로 async, await으로 가져와서 사용 가능
async function Meals() {
const meals = await getMeals();
return <MealsGrid meals={meals} />
}
Suspense는 리액트에서 제공하는 컴포넌트로,
일부 데이터가 불러와질때까지 로딩 상태를 처리하고 대체 컨텐츠를 표시한다.
데이터를 불러오는 Meals Function이 있을떄 이것을 suspense로 감싸줘서, fallback 함수를 표시해서 사용할 수 있다.
import { Suspense } from 'react';
<Suspense fallback={<p className={classes.loading}>Fetching meals...</p>}>
<Meals />
</Suspense>
이제 Next.js는 새로고침없이 , 랜더링 할 수있는 콘텐츠로 부분적으로 랜더링한 후에
로딩된 컨텐츠를 스트리밍하여 랜더링 한다. 더 나은 사용자 경험을 제공할 수 있는 것이다.