TIL100. Next.JS 13 새로운 특징들

조연정·2022년 12월 12일
1

v13 변경사항에 대해 알아보자.

app/ Directory

*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>
  );
}

Data Fetching

react에서 데이터를 불러올 때 최초 렌더링 시 빈 배열의 형태를 가지며 그 이후 useEffect를 통해 값이 채워지게 된다. 그 다음 렌더링을 통해 그 렌더링된 값이 보여지는데 이 과정에서 화면에 깜빡임이 생길 수 있다.
이를 방지하기 위해 next-js에서는 사전 렌더링(pre-rendering)을 위한 data fetching을 할 수 있는 기능으로 getStaticProps와 getServerSideProps가 있다.

getStaticProps

빌드 시에 한 번만 호출되고, 바로 static file로 빌드된다.
SSG (Static Site Generation) 수정될 일이 없는 경우에 사용하기 좋다.

getServerSideProps

getServerSideProps는 getStaticProps와 다르게 page가 요청이 들어올 때마다 호출되며, 그 때마다 사전 렌더링을 진행한다.
요청 시마다 다시 호출되므로 자주 바뀌게 될 동적 데이터가 들어갈 때 더 사용하기 좋다.

use

13부터는 getServerSideProps, getStaticProps 대신에 use를 사용해야 한다.

  • fetch 구문의 URL 뒤에 { cache: '' } 를 넣어줄 수 있는데, 안에 무엇이 들어가냐에 따라 기존의 getServerSideProps, getStaticProps와 유사한 기능을 쓸 수 있다.
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/Link/Font)

next/Image

  • Image컴포넌트를 통해서 이미지 파일을 넣을 수 있는데 자동으로 최적화된다.
  • 이미지가 로딩중일 때, 자동적으로 width와 height를 설정해서 *layout shift를 방지해준다.
  • 페이지 내에서 실제로 필요할 때까지 리소스의 로딩을 미루는 'lazy loading'기법으로 로딩 시간을 단축하여 웹 성능을 향상시킨다.(with optional blur-up)

*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 값을 지정해줘야 한다.

next/font

  • font 역시 자동으로 layout Shift가 방지된다.
  • ⭐️구글 폰트가 내장되어 브라우저에서 구글 폰트 요청을 별도로 하지 않아도 사용할 수 있다.

google font

// 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

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>
  );
}
  • Link Component 안에 더이상 <a> 태그를 사용하지 않아도 된다.
  • Link 태그에도 props나 함수를 사용할 수 있다.
// before
<Link href="/about">
  <a onclick={()=>console.log('clicked')}>About</a>
</Link>

// after
<Link href="/about" onclick={()=>console.log('clicked')}>
  About
</Link>
profile
Lv.1🌷

0개의 댓글