Next.js 튜토리얼을 접하며 중구난방으로 적은 내용입니다.
Next에서 기본적으로 라우팅을 하는 법은 pages/ 디렉토리에 파일을 생성하는 것이다. 그 파일 이름을 기준으로 고정 url을 갖는다. (e.g. pages/events -> url이 events, pages/index -> url이 /)
기본적으로 Link
컴포넌트를 사용해서 클라이언트 사이드 route transition을 한다. 이 때 동적 url을 생성할 수 있는데, pages/p/1, pages/p/2 처럼 하고 싶을 때에는, pages/p/[id].js 를 생성한다. 그 다음 라우트 컴포넌트에서 <Link href='/p/[id]'/>
이렇게 설정하고, 부모 페이지에서 props로 id를 넘겨주면 된다.
(조금 덜 깔끔한 방법도 있다. 브라켓을 사용하지 않고 그냥 링크 컴포넌트에서 <Link href={/p/${props.id}
/> 라고 사용해도 된다.)
여기서 href는 pages 디렉토리 내의 path를 나타내고, as는 브라우저 상의 url을 나타낸다.
아래는 블로그라는 페이지(/blog
)에서 포스트 링크 리스트를 나열하고, 각 포스트 링크를 클릭하면 post 페이지로 이동하는 코드이다.
import Layout from '../comp/Layout'
import Link from 'next/link'
// 포스트 링크 컴포넌트는
// 부모 페이지로부터 전달받은 props로 동적 라우팅을 한다.
// href에 [] 내부의 id는 blog 페이지로부터 전달 받은
// 쿼리 패러미터이다.
const PostLink = props => (
<li>
<Link href="/p/[id]" as={`/p/${props.id}`}>
<a>{props.id}</a>
</Link>
</li>
)
export default function Blog() {
return (
<Layout>
<h1>Blog</h1>
<ul>
<PostLink id="hello-next" />
<PostLink id="learn-next" />
</ul>
</Layout>
)
}
import { useRouter } from 'next/router'
import Layout from '../../comp/Layout'
// post 페이지
// 라우트 객체에서 쿼리를 가져와 보여준다.
export default function post() {
const router = useRouter()
return (
<Layout>
<h1>{router.query.id}</h1>
</Layout>
)
}
useRouter 훅(useRouter는 리액트 훅이다)은 Next.js의 라우트 객체를 리턴한다. 라우트 객체를 통해 쿼리 패러미터, pathname 등에 접근할 수 있으며 push 등 메서드를 사용할 수 있다.
useRouter 말고 withRouter HOC를 사용할 수도 있다. withRouter는 어떤 컴포넌트에서든 라우터 객체에 접근할 수 있도록 한다. 사용방법은 사용하고자 하는 컴포넌트를 감싸서 export하고, props로 router객체를 받아서 사용하면 된다.
import { withRouter } from 'next/router'
function Page({ router }) {
return <p>{router.pathname}</p>
}
export default withRouter(Page)
components, comp 등 컴포넌트를 넣어놓는 디렉토리를 생성하여 거기에서 만든 컴포넌트는 page를 구성하는 요소로 여기저기에 갖다 쓸 수 있다. 즉 nextjs에서는 pages에 해당 url에 매핑되는 뷰를 만들고, 그 뷰를 만들 때 comp 에서 컴포넌트를 갖다가 구성한다.
각 페이지에 필요한 data를 fetch해서 준비해야 하는 경우 getInitialProps
API를 사용한다.
getInitialProps
: Standard API to fetch data for pages(Async Function). Through this, can fetch data from remote data source and pass it as props to page.
getInitialProps
는 페이지에서 디폴트 export 하는 컴포넌트에만 적용 가능하다.
import Layout from '../components/MyLayout.js'
import Link from 'next/link'
import fetch from 'isomorphic-unfetch'
const Index = props => (
<Layout>
<h1>Batman TV Shows</h1>
<ul>
{props.shows.map(show => (
<li key={show.id}>
<Link href="/p/[id]" as={`/p/${show.id}`}>
<a>{show.name}</a>
</Link>
</li>
))}
</ul>
</Layout>
)
Index.getInitialProps = async function() {
console.log('init prop function is called')
const res = await fetch('https://api.tvmaze.com/search/shows?q=batman')
const data = await res.json()
console.log(`show data fetched. count: ${data.length}`)
return {
shows: data.map(entry => entry.show),
}
}
export default Index
import { useRouter } from 'next/router'
import Layout from '../../components/MyLayout.js'
const Post = props => {
return (
<Layout>
<h1>{props.show.name}</h1>
</Layout>
)
}
export default Post
Post.getInitialProps = async function(context) {
const { id } = context.query
const res = await fetch(`https://api.tvmaze.com/shows/${id}`)
const show = await res.json()
console.log(`Fetched show: ${show.name}`)
return { show }
}