v13 변경사항에 대해 알아보자.
*app/ 디렉토리 구조는 beta버전이기 때문에 실제 프로덕션 레벨에서는 권장되지 않는다.
기존에는 pages 디렉토리 안에 파일을 생성하여 Automating Routing을 실행했지만, 13버전부터는 app/이라는 새로운 디렉토리가 등장하였다.
파일 시스템 기반에서 디렉터리 기반 라우팅 시스템으로 전환하였다.
현재는 pages와 app 디렉토리가 공존하는 베타 버전으로 제공된다.
app 디렉토리 안에는 layout.js
, page.js
, head.js
파일이 존재한다.
*dev server를 돌리면 자동적으로 head.js와 layout.js를 생성해준다.
-page.js : 고유한 ui를 정의하는데 사용(index.js같은 느낌)
-layout.js : 여러 경로에서 공유되는 ui를 정의하는데 사용(nav, footer 컴포넌트)
// page.js
const Home = () => {
return <div>Homepage</div>;
};
export default Home;
// layout.js
import "styles/globals.css";
import Header from "./Header";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html>
<body>
<Header />
{children}
</body>
</html>
);
}
react에서 데이터를 불러올 때 최초 렌더링 시 빈 배열의 형태를 가지며 그 이후 useEffect를 통해 값이 채워지게 된다. 그 다음 렌더링을 통해 그 렌더링된 값이 보여지는데 이 과정에서 화면에 깜빡임이 생길 수 있다.
이를 방지하기 위해 next-js에서는 사전 렌더링(pre-rendering)을 위한 data fetching을 할 수 있는 기능으로 getStaticProps와 getServerSideProps가 있다.
빌드 시에 한 번
만 호출되고, 바로 static file로 빌드된다.
SSG (Static Site Generation) 수정될 일이 없는 경우에 사용하기 좋다.
getServerSideProps는 getStaticProps와 다르게 page가 요청이 들어올 때마다 호출되며, 그 때마다 사전 렌더링을 진행한다.
요청 시마다 다시 호출되므로 자주 바뀌게 될 동적 데이터가 들어갈 때 더 사용하기 좋다.
13부터는 getServerSideProps, getStaticProps 대신에 use
를 사용해야 한다.
import { use } from 'react'
const getData = async () => {
const res = await fetch("www.example.com/movies/1");
const data = await res.json();
return data;
};
const page = () => {
const movie = use(getData());
return <div>{movie.title}<div>;
};
// getStaticProps
const getStaticProps = async () => {
const res = await fetch("www.example.com/movies/1", {
cache: "force-cache",
});
const data = await res.json();
return data;
};
// getServerSideProps
const getServerSideProps = async () => {
const res = await fetch("www.example.com/movies/1", {
cache: "no-store",
});
const data = await res.json();
return data;
};
Image
컴포넌트를 통해서 이미지 파일을 넣을 수 있는데 자동으로 최적화된다. *layout Shift: 이미지 사이즈가 정해져있지 않은 경우, 이미지를 기다리는 동안 기존의 레이아웃이 밀려나는 현상
import Image from 'next/image';
export default function Page() {
return (
// 1) Local Images
<Image
src={profilePic}
alt="profile"
// width={500} automatically provided
// height={500} automatically provided
// blurDataURL="data:..." automatically provided
// placeholder="blur" // Optional blur-up while loading
/>
// 2) Remote Images
<Image
src="https://s3.amazonaws.com/my-bucket/profile.png"
alt="profile"
width={500}
height={500}
/>
);
}
-> Remote image
를 사용하기 위해서는 width와 height 값을 지정해줘야 한다.
// app/layout.tsx
import { Inter } from '@next/font/google';
const inter = Inter({ subsets: ['latin'] })
export default function RootLayout({ children }: {
children: React.ReactNode;
}) {
return (
<html lang="en" className={roboto.className}>
<body>{children}</body>
</html>
);
}
다양한 weight와 styles 사용 시 배열을 사용
const roboto = Roboto({
weight: ['400', '700'],
style: ['normal', 'italic'],
subsets: ['latin'],
});
local font 역시 같은 방법으로 사용가능
import localFont from '@next/font/local';
const myFont = localFont({ src: './my-font.woff2' });
export default function RootLayout({ children }: {
children: React.ReactNode;
}) {
return (
<html lang="en" className={myFont.className}>
<body>{children}</body>
</html>
);
}
<a>
태그를 사용하지 않아도 된다.// before
<Link href="/about">
<a onclick={()=>console.log('clicked')}>About</a>
</Link>
// after
<Link href="/about" onclick={()=>console.log('clicked')}>
About
</Link>