728x90
반응형

리액트에서의 스타일 적용법은 다음 링크로 확인할 수 있다.

 

https://typo.tistory.com/entry/Reactjs-%EC%9E%85%EB%AC%B8-CSS-SASS-SCSS?category=891266 

 

React.js | 입문 | CSS, SASS, SCSS

ReactJS에 CSS를 추가하는 방법은 크게 세가지가 있다. 먼저 css, sass, scss의 차이점 부터 알아보자. HTML 1 2 3 이러한 코드가 주어졌을 때 CSS .list { width: 100px; float: left; } li { color: red; backgr..

typo.tistory.com

 

 

NextJS CSS는 다음 링크로 자세히 볼 수 있다.

 

https://nextjs.org/docs/basic-features/built-in-css-support#adding-a-global-stylesheet

 

Basic Features: Built-in CSS Support | Next.js

Next.js supports including CSS files as Global CSS or CSS Modules, using `styled-jsx` for CSS-in-JS, or any other CSS-in-JS solution! Learn more here.

nextjs.org


 

Global CSS

bootstrap 같은 전역 css는 pages/_app.js 에 추가해서 사용할 수 있다.

pages/_app.js

// pages/_app.js
import 'bootstrap/dist/css/bootstrap.css'

export default function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

 

 

Component CSS

특정 Component에서 쓰이는 css는 컴포넌트와 이름이 같은 css 파일을 만들어서 import 할 수 있다.

 

예를들어 Components/Button 폴더 안에 index.js, Button.module.css 파일이 있다고 가정할 때 아래와 같이 사용할 수 있다.

 

Components/Button/Button.module.css

/*
You do not need to worry about .error {} colliding with any other `.css` or
`.module.css` files!
*/
.error {
  color: white;
  background-color: red;
}

 

Components/Button/index.js

import styles from './Button.module.css'

export function Button() {
  return (
    <button
      type="button"
      // Note how the "error" class is accessed as a property on the imported
      // `styles` object.
      className={styles.error}
    >
      Destroy
    </button>
  )
}

 

css 파일은 어느 곳에서나 가져올 수 있습니다.

 

SASS in NextJS

SASS를 이용해 scss 파일을 사용하고자 할 때는 먼저 사용할 모듈을 설치하자.

$ npm install sass

 

그다음 next.config.js 파일을 수정해야 한다.

next.config.js

const path = require('path')

module.exports = {
  sassOptions: {
    includePaths: [path.join(__dirname, 'styles')],
  },
}

 

 

React에서와 같이 변수를 사용할 수도 있으며 export로 변수를 밖으로 내보낼 수도 있다.

variables.module.scss

/* variables.module.scss */
$primary-color: #64FF00

:export {
  primaryColor: $primary-color
}

 

pages/_app.js

// pages/_app.js
import variables from '../styles/variables.module.css'

export default function MyApp({ Component, pageProps }) {
  return (
    <Layout color={variables.primaryColor}>
      <Component {...pageProps} />
    </Layout>
  )
}

 

 

참조

https://medium.com/sebride/next-js-with-module-sass-a8fe3976147

 

Next.js with module sass

제가 가장 선호하는 css는 module sass 방식입니다. 고전적인 css 방식에 익숙하신 분들은 어색한 개념일 수 있는데요. 차근차근 설명해보도록 하겠습니다.

medium.com

 

728x90
반응형

'Front-End > Next.js' 카테고리의 다른 글

Next.js | Json in Json 상태 관리  (0) 2022.01.04
Next.js | 기본기능 | userAgent 정보 확인하기  (0) 2021.11.03
Next.js | next-redux-wrapper  (0) 2021.10.15
Next.js | 기본기능 | 환경 변수  (0) 2021.10.13
Next.js | API 경로  (0) 2021.10.13
728x90
반응형

NextJS에서 상태를 관리하기 수월하게 해주는 redux를 TypeScript와 함께 사용해보자.

이 포스트는 counter에 대한 state를 다루는 포스트이다.

 

사전 준비

create-next-app으로 프로젝트를 생성한다.

 

$ npx create-next-app nextredux --typescript

 

웹으로 설치가 잘 되었는지 확인한다.

$ npm run dev

 

 

필요한 npm 패키지를 설치한다.

$ npm i react-redux redux next-redux-wrapper
$ npm i redux-devtools-extension redux-logger --dev-save

 

store 폴더와 하위에 index.ts파일을 생성해준다.

 

 

/store/index.ts

import { createStore, applyMiddleware, compose } from "redux";
import { createWrapper } from "next-redux-wrapper";
import { createLogger } from "redux-logger";
import { composeWithDevTools } from "redux-devtools-extension";
import rootReducer from "reducer/index";

const configureStore = () => {
	const logger = createLogger();
	const enhancer = compose(composeWithDevTools(applyMiddleware(logger)));
	const store = createStore(rootReducer, enhancer);
	return store;
};

const wrapper = createWrapper(configureStore, { debug: true });

export default wrapper;

아직 reducer 폴더를 만들지 않았기 때문에 오류가 뜬다. 천천히 해보자.

 

 

만든 store를 _app.tsx 파일에 wrapper 적용을 하자.

 

_app.tsx

import { AppProps } from "next/app";
import { NextPage } from "next";
import wrapper from "../store"; //좀전에 만든 store.ts 파일

const MyApp: NextPage<AppProps> = ({ Component, pageProps }: AppProps) => {
	return (
		<>
			<Component {...pageProps} />
		</>
	);
};

export default wrapper.withRedux(MyApp);

 

 

interfaces폴더를 아래와 같이 생성한다.

 

index.ts파일을 수정한다.

/store/interfaces/index.ts

export * from "./counter/counter.interfaces";
export * from "./counter/counterAct.interfaces";

 

 

RootState.ts파일을 수정한다.

/store/interfaces/RootState.ts

import { CounterState } from "./index";

export interface RootStateInterface {
	counter: CounterState;
}

 

 

counter.interfaces.ts 파일을 수정한다.

/store/interfaces/counter/counter.interfaces.ts

export interface CounterState {
	count: number;
}

 

 

counterAct.interfaces.ts 파일을 수정한다.

/store/interfaces/counter/counterAct.interfaces.ts

export enum actionTypesCounter {
	COUNTER_INCREMENT = "COUNTER_INCREMENT", // 숫자 + 1
	COUNTER_DECREMENT = "COUNTER_DECREMENT",  // 숫자 - 1
	COUNTER_RESET = "COUNTER_RESET", // 초기화 
}

export type ActionsCounter = CounterIncrement | CounterDecrement | CounterReset;

export interface CounterIncrement {
	type: actionTypesCounter.COUNTER_INCREMENT;
}

export interface CounterDecrement {
	type: actionTypesCounter.COUNTER_DECREMENT;
}

export interface CounterReset {
	type: actionTypesCounter.COUNTER_RESET;
}

 

interfaces는 완성되었다. 이번엔 reducer를 만들어보자.

 

 

index.ts 파일을 수정한다.

/store/reducer/index.ts

import { combineReducers, Reducer, AnyAction } from "redux";
import { RootStateInterface } from "../interfaces/RootState";
import counter from "./counter";

const rootReducer: Reducer<
	RootStateInterface,
	AnyAction
> = combineReducers<RootStateInterface>({
	counter,
});

export default rootReducer;
export type RootState = ReturnType<typeof rootReducer>;

 

 

counter.ts 파일을 수정한다

/store/reducer/counter.ts

import { HYDRATE } from "next-redux-wrapper";
import {
	CounterState,
	actionTypesCounter,
	ActionsCounter,
} from "../interfaces";

export const initialState: CounterState = {
	count: 0,
};

interface HydratePayload {
	counter: CounterState;
}

const counter = (
	state = initialState,
	action: ActionsCounter | { type: typeof HYDRATE; payload: HydratePayload },
): CounterState => {
	switch (action.type) {
		case HYDRATE:
			return { ...state, ...action.payload.counter };
		case actionTypesCounter.COUNTER_INCREMENT:
			return {
				...state,
				...{ count: state.count + 1 },
			};

		case actionTypesCounter.COUNTER_DECREMENT:
			return {
				...state,
				...{ count: state.count - 1 },
			};

		case actionTypesCounter.COUNTER_RESET:
			return {
				...state,
				...{ count: initialState.count },
			};

		default:
			return state;
	}
};
export default counter;

 

 

그다음 pages/counter/index.tsx 파일을 만든다.

 

pages/counter/index.tsx

import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { RootStateInterface } from "../../store/interfaces/RootState";
import { CounterState } from "../../store/interfaces";
import { actionTypesCounter } from "../../store/interfaces/counter/counterAct.interfaces";

const Counter = () => {
	const { count } = useSelector(
		(state: RootStateInterface): CounterState => state.counter,
	);
	const dispatch = useDispatch();
	const handleClick = (num: number) => {
		if (num === 1) {
			dispatch({type : actionTypesCounter.COUNTER_INCREMENT});
		} else if (num === 0) {
			dispatch({type : actionTypesCounter.COUNTER_DECREMENT});
		} else if (num === 2) {
			dispatch({type : actionTypesCounter.COUNTER_RESET});
		}
	};
	return (
		<div>
			<div>현재값:{count}</div>
			<div>
				<button onClick={() => handleClick(1)}>+</button>
				<button onClick={() => handleClick(0)}>-</button>
				<button onClick={() => handleClick(2)}>reset</button>
			</div>
		</div>
	);
};

export default Counter;

 

실행해본다.

 

 

정상적으로 카운트state가 버튼 클릭에따라 바뀌는 것을 확인할 수 있다.

 

액션을 만들어서 State를 다루는 방법은 Nest - Next 카테고리에서 확인할 수 있다.

728x90
반응형
728x90
반응형

예시

https://github.com/vercel/next.js/tree/canary/examples/environment-variables

 

GitHub - vercel/next.js: The React Framework

The React Framework. Contribute to vercel/next.js development by creating an account on GitHub.

github.com

 

우리는 기본적으로 .env.local 파일을 생성해서 환경 변수를 설정할 수 있다.

 

.env.local

DB_HOST=localhost
DB_USER=myuser
DB_PASS=mypassword

 

선언한 환경 변수들을 서버사이드 측에서 다음과같이 쓸 수 있다.

// pages/index.js
export async function getStaticProps() {
  const db = await myDB.connect({
    host: process.env.DB_HOST,
    username: process.env.DB_USER,
    password: process.env.DB_PASS,
  })
  // ...
}

 

 

Next 브라우저에서의 환경 변수

Next 브라우저에서는 'NEXT_PUBLIC_' 접두사를 붙여야한다. 예를들어

 

.env.local

NEXT_PUBLIC_ANALYTICS_ID=abcdefghijk

 

 

이렇게 선언한 환경 변수를 브라우저에서 다음과 같이 쓸 수 있다.

 

// pages/index.js
import setupAnalyticsService from '../lib/my-analytics-service'

// NEXT_PUBLIC_ANALYTICS_ID can be used here as it's prefixed by NEXT_PUBLIC_
setupAnalyticsService(process.env.NEXT_PUBLIC_ANALYTICS_ID)

function HomePage() {
  return <h1>Hello World</h1>
}

export default HomePage
728x90
반응형

'Front-End > Next.js' 카테고리의 다른 글

Next.js | 기본기능 | Built-In CSS Support(SCSS)  (0) 2021.11.02
Next.js | next-redux-wrapper  (0) 2021.10.15
Next.js | API 경로  (0) 2021.10.13
Next.js | 라우터 | Imperatively  (0) 2021.10.13
Next.js | 라우터 | Dynamic Routes  (0) 2021.10.13
728x90
반응형

API 경로는 Next.js로 API를 빌드하기 위한 솔루션을 제공한다.

 

폴더 내의 모든 파일 'pages/api'에 매핑 '/api/*' 하고 API 대신의 엔드 포인트로 처리된다.

서버측 전용 번들이며 클라이언트 측 번들 크기를 늘리지 않는다.

 

예를 들어 다음 API 경로 'pages/api/user.js' 는 'json'상태 코드가 다음과 같은 응답을 반환한다.

 

pages/api/user.js

export default function handler(req, res) {
  res.status(200).json({ name: 'John Doe' })
}

 

API에서 다른 HTTP 메소드를 처리하기 위해 'req.method' 다음과 같이 요청 핸들러에서 사용할 수 있다.

 

pages/api/user.js

export default function handler(req, res) {
  if (req.method === 'POST') {
    // Process a POST request
  } else {
    // Handle any other HTTP method
  }
}

 

 

728x90
반응형

'Front-End > Next.js' 카테고리의 다른 글

Next.js | next-redux-wrapper  (0) 2021.10.15
Next.js | 기본기능 | 환경 변수  (0) 2021.10.13
Next.js | 라우터 | Imperatively  (0) 2021.10.13
Next.js | 라우터 | Dynamic Routes  (0) 2021.10.13
Next.js | 라우터 | 소개  (0) 2021.10.13
728x90
반응형

useRouter을 사용하여 절대경로로 페이지를 이동시킬 수 있다.

 

import { useRouter } from 'next/router'

export default function ReadMore() {
  const router = useRouter()

  return (
    <button onClick={() => router.push('/about')}>
      Click here to read more
    </button>
  )
}

 

728x90
반응형

'Front-End > Next.js' 카테고리의 다른 글

Next.js | 기본기능 | 환경 변수  (0) 2021.10.13
Next.js | API 경로  (0) 2021.10.13
Next.js | 라우터 | Dynamic Routes  (0) 2021.10.13
Next.js | 라우터 | 소개  (0) 2021.10.13
Next.js | 기본기능 | Built-In CSS Support  (0) 2021.10.13
728x90
반응형

 

Next.js에서 페이지에 대괄호를 추가하여 동적경로를 생성할 수 있다.

 

pages/post/[pid].js

import { useRouter } from 'next/router'

const Post = () => {
  const router = useRouter()
  const { pid } = router.query

  return <p>Post: {pid}</p>
}

export default Post

원하는 경로 'post/1', '/post/abc'등이 일치된다. 

 

 

Optional catch all routes

선택적으로 모든 경로를 잡을 수 있다. 이중괄호 ('[[...slug]]') 에 포함하여 선택 사항으로 만들 수 있다.

예를 들어 pages/post/[[..slug]].js  이렇게 만들면

'/post', '/post/a', 'post/a/b' 이런식으로 불러올 수 있다. 다음과 같이 나타난다.

{ } // GET `/post` (empty object)
{ "slug": ["a"] } // `GET /post/a` (single-element array)
{ "slug": ["a", "b"] } // `GET /post/a/b` (multi-element array)

 

728x90
반응형
728x90
반응형

→라우팅

Next.js에는 페이지 개념을 기반으로 구축된 파일 시스템 기반의 라우터가 있다.

파일이 pages 디렉토리에 추가되면 자동으로 경로로 사용이 가능하다.

 

 

index 경로

라우터는 이름이 지정된 파일 'index'을 디렉터리의 루트로 자동 라우팅한다.

  • 'pages/index.js' → '/'
  • 'pages/blog/index.js' → '/blog'

 

중첩 경로

라우터는 중첩 파일을 지원한다. 

  • 'pages/blog/first-post.js' → '/blog/first-post
  • 'pages/dashboard/settings/username.js' → '/dashboard/settings/username'

 

동적 경로 세그먼트

동적 세그먼트를 일치시키기 위해 대괄호 구문을 사용할 수 있다.

  • pages/blog/[slug].js→ /blog/:slug( /blog/hello-world)
  • pages/[username]/settings.js→ /:username/settings( /foo/settings)
  • pages/post/[...all].js→ /post/*( /post/2020/id/title)

 

페이지 간 연결

Next.js 라우터를 사용하여 SPA와 유사하게 페이지 간에 클라이언트 측 경로 전환을 수행할 수 있다.

import Link from 'next/link'

function Home() {
  return (
    <ul>
      <li>
        <Link href="/">
          <a>Home</a>
        </Link>
      </li>
      <li>
        <Link href="/about">
          <a>About Us</a>
        </Link>
      </li>
      <li>
        <Link href="/blog/hello-world">
          <a>Blog Post</a>
        </Link>
      </li>
    </ul>
  )
}

export default Home

 

 

여러가지 링크가 있는 곳에서 href 는 알려진 페이지에 대한 경로를 매핑한다.

  • /  pages/index.js
  • /about  pages/about.js
  • /blog/hello-world  pages/blog/[slug].js

 

동적 경로에 연결

${}를 이용하여 동적 경로를 매핑할 수 있다.

import Link from 'next/link'

function Posts({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>
          <Link href={`/blog/${encodeURIComponent(post.slug)}`}>
            <a>{post.title}</a>
          </Link>
        </li>
      ))}
    </ul>
  )
}

export default Posts
728x90
반응형
728x90
반응형

Adding a Global Stylesheet

만약 application에 stylesheet을 추가하려면 pages/_app.js에 CSS 파일을 import해라.

예를들어

 

/styles.css

body {
  font-family: 'SF Pro Text', 'SF Pro Icons', 'Helvetica Neue', 'Helvetica',
    'Arial', sans-serif;
  padding: 20px 20px 60px;
  max-width: 680px;
  margin: 0 auto;
}

 

그다음 pages/_app.js에서 import한다.

 

pages/_app.js

import '../styles.css'

// This default export is required in a new `pages/_app.js` file.
export default function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

 

 

 

Adding Component-Level CSS

Next.js는 [name].module.css 파일명 형식의 CSS Modules도 지원한다.

 

예를 들어 Button 컴포넌트를 생각해보자.

 

먼저 components/Button.module.css 를 생성한다.

/*
You do not need to worry about .error {} colliding with any other `.css` or
`.module.css` files!
*/
.error {
  color: white;
  background-color: red;
}

 

그다음 components/Button.js를 생성하고 CSS 파일을 import한다.

import styles from './Button.module.css'

export function Button() {
  return (
    <button
      type="button"
      // Note how the "error" class is accessed as a property on the imported
      // `styles` object.
      className={styles.error}
    >
      Destroy
    </button>
  )
}

 

오직 .module.css라는 확장명을 사용한 파일에만 적용된다. 이런 css 파일들은 application이 빨리 실행되도록 해주는데 app이  paint되기에 최소한 양의 CSS만 로드되도록 해주기 때문이다.

 

 

Sass Support

Next.js는 .scss나 .sass 모두 import할 수 있게 해준다. 그러기 위해선 먼저 설치해야한다.

$ npm install sass

 

Note: Sass는 2개의 syntax를 지원한다. .scss는 SCSS 문법을 사용하길 요구한다. 반면에 .sass는 들여쓰는 SASS문법을 사용하길 요구한다.만약 특별히 사용에 대한 기준이 없다면, .scss를 사용해라. 이건 CSS의 상위집합개념이고 SASS에서 사용하는 어떤 들여쓰기 문법도 요구하지 않는다.

 

CSS in JS

CSS-in-JS 또한 사용가능하다. 아래 예가 있다.

function HiThere() {
  return <p style={{ color: 'red' }}>hi there</p>
}

export default HiThere

 

728x90
반응형
728x90
반응형

getServerSideProps

만약 getServerSideProps 라 불리는 async 함수를 export한다면 Next.js는 getServerSideProps에 의해 리턴된 data를 사용하면서 이 페이지를 매 요청시마다 pre-rendering 할 것이다.

 

export async function getServerSideProps(context) {
  return {
    props: {}, // will be passed to the page component as props
  }
}

 

context 파라미터는 다음 속성들을 포함하는 객체이다.

params 만약 동적 라우트를 사용하는 페이지라면 params는 라우트 파라미터들을 포함한다. 만약 페이지명이 [id].js라면 params{id : ...}와 같은 형태가 될 것이다.
req HTTP IncommingMessage object
res HTTP response object
query An object representing the query string
preview previewtrue라면 이 페이지는 preview모드, false면 아닌 것이다.
previewData setPreviewData에 의해 세팅된 preview data이다
resolvedUrl client transition을 위해 _next/data 접두어가 생략된 요청 url의 정규화 버전
locale active locale을 포함
locales 모든 지원 locales를 포함
defaultLocale 디폴트로 설정된 locale

 

getServerSideProps가 리턴하는 객체는 아래항목들이 포함한다.

  • props - 페이지 컴포넌트에 의해 리턴되는 props는 필수객체이다.
  • notFound - 페이지가 404 상태와 404 페이지로 리턴되도록 허용하는 옵셔널한 boolean 값이다.
  • redirect: 옵셔널한 값으로 내외부 자원으로 redirecting 해주는 값이다. 반드시 {destination: string, permanent: boolean} 형태여야 한다.

 

export async function getServerSideProps(context) {
  const res = await fetch(`https://.../data`)
  const data = await res.json()

  if (!data) {
    return {
      redirect: {
        destination: '/',
        permanent: false,
      },
    }
  }

  return {
    props: {}, // will be passed to the page component as props
  }
}

 

 

언제 getServerSideProps를 써야할까?

getServerSideProps는 pre-render되는 페이지의 필요한 데이터가 요청시에 가져와야하는 경우에만 사용해라. 서버가 반드시 모든 요청에 대한 결과를 계산해야만 하기 때문에  getStaticProps보단 느리다.

 

만약 데이터가 pre-render 될 필요가 없다면, client-side에서 데이터를 가져오는 것을 고려해봐라.

 

  • 동적 라우트에서 정적인 데이터를 필요로 할 때 : getStaticProps
  • 동적 라우트에서 정적인 데이터를 필요로 하며, 정적인 페이지를 생성할 때 : getStaticPaths with getStaticProps
  • pre-render되는 페이지에 필요한 데이터를 요청시에 가져와야 하는경우 : getServerSideProps
  • pre-render가 필요없고 데이터를 가져와야하는 경우 : Axios

 

TypeScript : Use GerServerSideProps

타입스크립트를 사용할 때에는 next에서 GetServerSideProps를 사용할 수 있다.

 

import { GetServerSideProps } from 'next'

export const getServerSideProps: GetServerSideProps = async (context) => {
  // ...
}

 

 

Technical details

Only runs on server-side

getServerSideProps는 서버에서만 동작하고 브라우저에서 동작하지 않는다. 사용할 때

  • getServerSideProps는 요청시에만 실행된다.
  • 만약 이 페이지가 next/Linknext/router를 통해 요청된다면 Next.js는 API요청을 서버에 보낸다. 그리고 getServerSideProps를 실행한다. 그리고 getServerSideProps의 실행결과로 만들어진 JSON을 리턴한다. 

 

또한 getServerSIdePropspages에서만 요청된다.

 

 

SWR

리액트에서 쓰이는 useAsync같은 Hook이다. 클라이언트사이드에서 데이터를 가져올 때 이것이 매우 유용하다.

 

import useSWR from 'swr'

const fetcher = (url) => fetch(url).then((res) => res.json())

function Profile() {
  const { data, error } = useSWR('/api/user', fetcher)

  if (error) return <div>failed to load</div>
  if (!data) return <div>loading...</div>
  return <div>hello {data.name}!</div>
}

 

 

728x90
반응형
728x90
반응형

getStaticPaths(Static Generation)

만약 dynamic routes를 가지고 있는 페이지가 있고, 그 페이지가 getStaticProps를 사용한다면 그 페이지는 빌드시에 HTML pre-render될때 어떤 경로의 리스트의 페이지들인지 정의할 필요가 있다.

 

dynamic routes를 사용하는 어떤 페이지에서  getStaticProps라 불리는 async 함수를 export한다면, Next.js는 

getStaticProps에 의해 정의된 모든 paths들을 정적으로 pre-render 할 것이다.

 

export async function getStaticPaths() {
  return {
    paths: [
      { params: { ... } } // See the "paths" section below
    ],
    fallback: true or false // See the "fallback" section below
  };
}

 

 

The paths key(required)

path키는 pre-render되야하는 경로들을 정의한 것이다. pages/posts/[id].js 라는 이름의 dynamic routes를 사용하는 페이지가 있다고 가정해보자.  getStaticPaths를 해당 페이지에서 export하고 paths를 다음과 같이 리턴한다.

 

return {
  paths: [
    { params: { id: '1' } },
    { params: { id: '2' } }
  ],
  fallback: ...
}

 

그럼 Next.js는 posts/1, posts/2 를 빌드시에 정적으로 생성하고, pages/posts/[id].js의 페이지 컴포넌트로서 사용된다.

 

  • 만약 페이지 명이 pages/posts/[postId]/[commentId] 라면 params는 반드시 postId와 commentId를 포함해야한다.
  • 만약 pages/[...slug] 라고 한다면 params는 반드시 slug를 배열로 포함해야한다.

 

The fallbackkey (required)

getStaticPaths에 의해 리턴되는 객체는 반드시 boolean속성의 fallback 키를 포함해야한다.

 

fallback: false

 

만약 fallbackfalse이면 getStaticPaths에 의해 전달받지 못한 path들은 모두 404 페이지로 호출된다.

새 페이지가 자주 추가되지 않는다면 이방식은 유용하다. 만약 데이터 소스에 항목을 더 추가하고 새 페이지를 렌더링해야하는 경우엔 빌드를 다시 실행해야 한다.

 

아래 페이지를 예로 들어보자. getStaticPath에 의해 CMS로 부터 블로그 포스트리스트는 반환된다. 그리고 각 페이지들은 getStaticProps 에 의해 CMS로부터 각 포스트 데이터가 반환된다.

// pages/posts/[id].js

function Post({ post }) {
  // Render post...
}

// This function gets called at build time
export async function getStaticPaths() {
  // Call an external API endpoint to get posts
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // Get the paths we want to pre-render based on posts
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))

  // We'll pre-render only these paths at build time.
  // { fallback: false } means other routes should 404.
  return { paths, fallback: false }
}

// This also gets called at build time
export async function getStaticProps({ params }) {
  // params contains the post `id`.
  // If the route is like /posts/1, then params.id is 1
  const res = await fetch(`https://.../posts/${params.id}`)
  const post = await res.json()

  // Pass post data to the page via props
  return { props: { post } }
}

export default Post

 

만약 fallback이 true이면 getStaticProps의 행동이 변한다.

 

  • getStaticPaths로 부터 리턴된 경로들은 getStaticProps에 의해 빌드시에 HTML로 render된다.
  • 빌드시에 생성되지 않은 경로들은 404페이지로 로드되지 않는다. 대신 첫번째요청시에 "fallback"버전을 제공한다.
fallback: true는 next next 사용시 지원되지 않는다.

 

Fallback Pages: 로딩페이지 같은 역할

"fallback" 버전의 페이지는

  • 페이지의 props는 비워진다.
  • 라우터사용시 fallback이 렌더되면 router.isFallbacktrue값이 되는데 이로인해 fallback이 렌더링 되었다는 것을 확인할 수 있다.
// pages/posts/[id].js
import { useRouter } from 'next/router'

function Post({ post }) {
  const router = useRouter()

  // If the page is not yet generated, this will be displayed
  // initially until getStaticProps() finishes running
  if (router.isFallback) {
    return <div>Loading...</div>
  }

  // Render post...
}

// This function gets called at build time
export async function getStaticPaths() {
  return {
    // Only `/posts/1` and `/posts/2` are generated at build time
    paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
    // Enable statically generating additional pages
    // For example: `/posts/3`
    fallback: true,
  }
}

// This also gets called at build time
export async function getStaticProps({ params }) {
  // params contains the post `id`.
  // If the route is like /posts/1, then params.id is 1
  const res = await fetch(`https://.../posts/${params.id}`)
  const post = await res.json()

  // Pass post data to the page via props
  return {
    props: { post },
    // Re-generate the post at most once per second
    // if a request comes in
    revalidate: 1,
  }
}

export default Post

 

 

When is fallback : true Useful?

fallback: true 는 app이 매우 많은 양의 정적페이지를 가지고 있을때 유용하다. 어떤 사람들이 아직 생성되지 않은 페이지들을 요청할 수 있다. 그때 그 유저는 로딩창을 볼 수 있을것이다. 다만 생성된 페이지들을 업데이트 하지 않는다.

업데이트하려면 ISR을 fallback true와 같이 쓰도록 하자.

 

fallback : 'blocking'

 

만약 fallback이 blocking이라면 getStaticPath에 의해 리턴되지 않은 새로운 페이지들은 HTML이 생성될 때 까지

기다릴 것이다. 원래는 데이터 받고 HTML이 생성되지만 그 반대로 작동한다.

  • getStaticPaths로 부터 반환된 경로들은 getStaticProps에 의해 빌드시 HTML로 render된다.
  • 빌드시에 생성되지 않은 경로들이 404페이지로 가지 않는다. 
  • loading/fallback 상태가 없고 그냥 요청된 페이지가 바로 로드된다.
fallback : 'blocking'은 next export 사용시 지원되지 않는다.

 

When should I use getStaticPaths?

동적 라우트를 사용해서 페이지를 정적으로  pre-rendering한다면 ( pages/[id].js ) 반드시 getStaticPaths를 써야한다.

 

 

TypeScript: Use GetStaticPaths

타입스크립트에서는 next에서 GetStaticPaths를 import 할 수 있다.

 

import { GetStaticPaths } from 'next'

export const getStaticPaths: GetStaticPaths = async () => {
  // ...
}

 

 

Technical details

  • getStaticProps를 동적 라우트 파라미터와 함께 사용한다면 getStaticPaths는 무조건 써야한다. getStaticPathsgetServerSideProps와 절대 같이 사용할 수 없다.
  • getStaticPaths는 서버사이드에서 빌드시에만 실행된다.
  • getStaticPathspage에서만 exported 될 수 있다. page가 아닌곳에선 export 할 수 없다.
  • 개발환경에서는 getStaticPaths는 매 요청시에 호출된다.
728x90
반응형

+ Recent posts