Next.js

Jeane·2021년 2월 16일
0

목차

  1. Intro
  2. Routing
  3. Head
  4. Layout
  5. Nav Component & Link
  6. Header
  7. Custom Document
  8. Data Fetching
  9. Nested Routing
  10. Export a Static Website
  11. API Routes
  12. Using the API Data
  13. Custom Meta Component

Intro

  • 공식 문서
  • Vercel에서 만든 리액트 프레임 워크
  • 기존의 리액트 앱과는 달리 첫 페이지는 서버에 의해 로드됨 (SEO와 퍼포먼스 관점에서 좋음)

특징

  • 페이지 라우팅이 편리
  • API Routes
  • TypeScript와 Sass를 별다른 설치없이 사용 가능
  • SSG
  • 배포가 쉬움

index.js

export default function Home() {
	return (
    	<div>
        	<h1></h1>
        </div>
 )
}

Routing

pages > about.js

const about = () => {
    return (
        <div>
            <h1>About</h1>
        </div>
    )
}

export default about

pages 폴더 안에 파일 생성 후 url에 /파일명을 붙여주면 라우팅 됨

  • next/head API
  • title이나 메타 태그 등을 커스텀

pages > index.js

import Head from 'next/head'

export default function Home() {
	return (
    	<div>
        	<Head>
            	<title></title>
                <meta name='keywords' content='...' />
            </Head>
        </div>

Layout

헤더, 푸터, 메뉴와 같이 매 페이지마다 보여야하는 것들은 Layout 컴포넌트를 만들어서 쓰면 편리

components > Layout.js

페이지를 레이아웃으로 감싸기 위해 children을 props로 전달

const Layout = ({ children }) => {
	return (
    	...
        {children}
        ...
    )
}

pages > _app.js

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

components > Nav.js

import Link from 'next/link'

const Nav = () => {
	return (
    	<nav>
        ...
			<Link href='/'>Home</Link>
        ...
        	<Link href='/about'>About</Link>
		...                

레이아웃에 import

components > Header.js

  • 헤더를 컴포넌트로 만들어 레이아웃에 import

Custom Document

pages > _document.js

  • 다큐먼트를 커스텀할 수 있음
  • 공식 문서에서 복사해옴
import Document, { Html, Head, Main, NextScript } from 'next/document'

  render() {
    return (
      <Html lang="en">
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

export default MyDocument

Data Fetching

Data fetching에 사용할 수 있는 세 가지의 메소드가 있음

  • getStaticProps() : 빌드할 때 데이터를 한번 가져옴
  • getServerSideProps() : 각 요청에 대해 데이터를 가져옴
  • getStaticPaths() : 지정한 모든 경로를 사전 렌더링

getStaticProps()

pages > index.js
Jsonplaceholder라는 API를 통해 가상 데이터를 이용해서 리스트 형태로 출력해볼 것임

export const getStaticProps = async () => {
	const res = await fetch('... url ...')
    	const articles = await res.json()
    
    return {
    	props: {
        	articles
        }
    }

}

이렇게 단순히 객체 형태로 props와 함께 리턴하면 됨

components > ArticleList.js
데이터가 출력될 리스트는 따로 컴포넌트를 분리하여 props를 통해 데이터 전달

const ArticleList = ({articles}) => {
	return (
    <div>
    	{articles.map((article) => (
            	<h3>{article.title}</h3>
        ))}
     </div>
   )
}

export default ArticleList

pages > index.js

import Head from 'next/head'
import ArticleList from '../components/ArticleList'

export default function Home({articles}) {
	return (
    	<div>
        	...
            <ArticleList articles={articles} />
        </div>

components > ArticleItem.js
리스트에 표시될 데이터를 조금 더 수정하여 컴포넌트를 생성했음

import Link from 'next/link'

const ArticleItem = ({article}) => {
    return (
        <Link href="/article/[id]" as={`/article/${article.id}`}>
            <a>
                <h3>{article.title} &rarr;</h3>
                <p>{article.body}</p>
            </a>
        </Link>
    )
}

export default ArticleItem

components > ArticleList.js

import ArticleItem from './ArticleItem'

const ArticleList = ({articles}) => {
	return (
    <div>
    	{articles.map((article) => (
        	<ArticleItem article={article} />
            ))}
     </div>
   )
}

export default ArticleList

ArticleItem에서 Link를 사용했기 때문에 이제 List에서 각 목록을 클릭하게 되면 url이 중첩된 루트처럼 나타날 것임

하지만 설정을 안해줬으므로 페이지는 404임 ㅋㅋ

Nested Routing

중첩 라우팅을 하는 건 너무나 간단하다
이렇게 우리가 설정할 url의 경로를 그대로 따라 폴더를 만들어주면 됨

pages > article > [id] > index.js

이 index.js가 우리 article의 싱글 페이지가 될 것

import {useRouter} from 'next/router'

	const article = () => {
    		const router = useRouter()
        	const {id} = router.query
        
        return <div> This is article {id} </div>
    }

이렇게 하면 각 id에 맞게 표시될 것임

getServerSideProps()

import {useRouter} from 'next/router'

	const article = ({article}) => {
    	//const router = useRouter()
        //const {id} = router.query
        
        return <div> This is article {article.id} </div>
    }

export const getServerSideProps = async (context) => {
	const res = await fetch(`...url...${context.params.id}`)
    
    const article = await res.json()
    
    return {
    	props: {
        	article
        }
    }
}

getStaticPaths()

getStaticProps와 짝으로 써야 함

export const getStaticProps = async (context) => {
	const res = await fetch(`...url...${context.params.id}`)
    
    const article = await res.json()
    
    return {
    	props: {
        	article
        }
    }
}

export const getStaticPaths = async () => {
	const res = await fetch(`...url...`)
    
    const articles = await res.json()
    
    const ids = articles.map(article => article.id)
    
    const paths = ids.map(id => ({params: {id: id.toString()}}))
    
    return {
    	paths,
        fallback: false
    }
    	
}

Export a Static Website

API Routes

위에서 jsonplaceholder를 통해 가상 데이터를 끌어와 사용했던 걸 우리가 정보를 직접 작성해서 API로 만들어 사용할 수 있음

기존에 있는 hello.js는 삭제하고 새롭게 생성
api > articles > idnex.js
데이터베이스 파일인 data.js를 최상위 루트에 가져왔음

import {articles} from '../../../data'

export default function handler(req, res){
	res.status(200).json(articles)
}

api > article > [id]

import { articles } from '../../../data'

export default function handler({ query: { id }}, res) {
	const filtered = articles.filter(article => article.id === id)
    
    if(filtered.length > 0) {
    	res.status(200).json(filtered[0])
    } else {
       	res.status(404).json({message: `Article with the id of ${id} is not found`})
    }
}

Using the API Data

config > index.js

const dev = process.env.NODE_ENV !== 'production'

export const server = dev ? 'http://localhost:3000' : 'https://whatever.com'

pages > index.js

import {server} from '../config'

	...
export const getStaticProps = async () => {
	const res = await fetch(`${server}/api/articles`)
    	const articles = await res.json()
            
        return {
  	    	props: {
   	           	articles,
                    },
                 }
}

//export const getStaticProps ...

pages > article > [id] > index.js
data fetching 부분 수정

Custom Meta Component

next/head api로 meta태그를 작성하는 방법도 있고 직접 컴포넌트를 만들어 커스텀할 수 있음
components > Meta.js

import Head from 'next/head'

const Meta = ({title, keywords, description}) => {
	return (
    		<Head>
            	<각종 meta 태그들 {title} {keywords} .../>
            </Head>
     )
}

Meta.defaultProps = {
	title: '',
    keywords: '',
    description: '',
}

defaultProps로 기본값 설정
그리고 Meta 컴포넌트를 Layout.js에 import해주면 됨

0개의 댓글