Next.js로 정적 웹사이트 만들기 - 4. Routing 사용하기
지난 글에서 index.js
와 post.js
를 생성했었고 Routing
을 사용하지 않고 URL로 직접 접근해서 화면을 확인했었다. 이번 글에서는 Next.js
의 Routing
을 사용하여 페이지 전환을 해보려고한다.
Next.js github에
Routing
에 대한 설명이 잘 나와있다.
Next.js
에서Route
는pages
디렉토리 경로에 작성한 파일명으로 생성된다. 그렇기 때문에, 파일명도 신경써서 잘 만들어야한다.
about.js 파일 생성
Routing 경로를 더 추가하기 위해 pages
디렉토리에 about.js
파일을 추가하고 다음과 같이 작성한다.
export default (props) => {
return (
<div>About</div>
);
}
about.js
까지 생성하였다면 총 3개의 Routing이 생기게 되었다.
_app.js에 Link 컴포넌트 추가
그런 다음, 공통의 레이아웃이 작성된 _app.js
에서 <header>
엘리먼트 안에 <Link>
컴포넌트를 추가하여 생성한 Routing
연결해본다.
import React from 'react';
import App, { Container } from 'next/app';
import Head from 'next/head';
import Link from 'next/link';
const styles = {
layout: {
display: 'flex',
width: '100%',
height: '100%',
flexDirection: 'column',
},
header: {
height: 60,
},
main: {
flex: 1,
},
footer: {
height: 60,
},
divider: {
margin: '0 8px',
},
}
export default class RootApp extends App {
render() {
const { Component, ...other } = this.props;
return (
<Container>
<Head>
<title>Static Website</title>
</Head>
<div style={styles.layout}>
<header style={styles.header}>
<Link href="/"><a>Home</a></Link>
<span style={styles.divider}>|</span>
<Link href="/post"><a>Post</a></Link>
<span style={styles.divider}>|</span>
<Link href="/about"><a>About</a></Link>
</header>
<main style={styles.main}>
<Component {...other} />
</main>
<footer style={styles.footer}>Footer</footer>
</div>
</Container>
);
}
}
import Link from 'next/link'
로 모듈을 import 해주고 <Link>
컴포넌트에 href
Props 값으로 pages
디렉토리에서 생성한 파일명을 작성해준다. 마지막으로 <Link>
안에는 <a>
를 추가해준다.
여기까지 작성되었다면 다음과 같은 화면이 보일 것이다.
한 번씩 눌러본다.
post.js에 Router 추가
다음으로, <button>
엘리먼트 onClick
을 이용해서 Routing
을 해보는데, 이때 Next.js
의 Router
를 사용해본다.
먼저, <Link>
와 Router
의 큰 차이점은 클라이언트 사이드로 렌더링 하냐 안하냐에 있다.
Router.push
를 사용하면 클라이언트 사이드로 렌더링을 한다.
import Router from 'next/router';
export default (props) => {
return (
<div>
First post page
<div>
<button onClick={() => Router.push('/')}>Home</button>
</div>
</div>
);
}
post.js
에서 import Router from 'next/router'
로 모듈을 import 해주고 <button>
을 추가한 다음 onClick
속성에 Router.push('/')
를 추가한다.
여기까지 작성되었다면 다음처럼 동작한다.
마찬가지로 about.js
에도 추가해준다.
import Router from 'next/router';
export default (props) => {
return (
<div>
About
<div>
<button onClick={() => Router.push('/')}>Home</button>
</div>
</div>
);
}
URL Params(Query String) 전달
다음으로 Routing
을 할 때, URL로 Parameter를 전달하여 각 페이지에서 전달받은 Parameter를 화면에 처리할 수 있도록 해본다.
Home
버튼을 클릭 했을 때, 어떤 페이지에서Home
으로 돌아왔는지 확인해보는 예제를 작성한다.
post.js
에서 했던 것처럼 about.js
에도 <button>
엘리먼트를 추가하고 onClick
속성에 Router.push
를 추가한다.
그러고 나서 post.js
와 about.js
에 작성된 Router.push('/')
를 각각 Router.push('/?history=post')
와 Router.push('/?history=about')
로 변경해준다.
post.js
import Router from 'next/router';
export default (props) => {
return (
<div>
First post page
<div>
<button onClick={() => Router.push('/?history=post')}>Home</button>
</div>
</div>
);
}
about.js
import Router from 'next/router';
export default (props) => {
return (
<div>
About
<div>
<button onClick={() => Router.push('/?history=about')}>Home</button>
</div>
</div>
);
}
이렇게 작성된 페이지에서 Home
버튼을 클릭하여 Home
경로로 가게 됐을 경우, URL에는 Query String이 붙게 되었고, index.js
에 전달되는 props에 console.log(props)
로 로그를 확인해보면 Develop Console
에 다음처럼 보이게 된다.
props에 router
오브젝트가 전달되는데, router
오브젝트 안에서 전달된 query
를 확인할 수 있다.
이것을 활용해서 index.js
에서 어떤 페이지로부터 넘어왔는지 확인해본다.
index.js
const styles = {
from: {
color: 'red',
},
};
export default (props) => {
const { router } = props;
return (
<div>
Home
{
router.query.history ? (
<div style={styles.from}>
From the {router.query.history}
</div>
) : null
}
</div>
);
}
화면을 확인해본다.
as 속성으로 URL Params 숨기기
URL Params
가 URL에 보이는 것이 맘이 편하지 않다면 Next.js
에서는 숨길 수 있는 방법이 있다.
as
속성을 이용하는 것인데, <Link href="/?history=post" as="/">
로 사용하거나 Router.push("/?history=post", '/')
로 사용할 수 있다.
post.js
와 about.js
에 가서 다음과 같이 바꿔준다.
post.js
import Router from 'next/router';
export default (props) => {
return (
<div>
First post page
<div>
<button onClick={() => Router.push('/?history=post', '/')}>Home</button>
</div>
</div>
);
}
about.js
import Router from 'next/router';
export default (props) => {
return (
<div>
About
<div>
<button onClick={() => Router.push('/?history=about', '/')}>Home</button>
</div>
</div>
);
}
다시 화면을 확인해본다.
아까와는 다르게 URL에 Query String
이 붙지 않고 history
가 전달된 것을 확인할 수 있다.
하지만 이 방법에서 문제점을 찾으라고 한다면, 새로고침을 했을 때 전달받은
router
오브젝트에query
가 비어있으므로From the
문구가 보이지 않게 된다.
withRouter 사용
다음으로 withRouter
를 사용해볼 것인데, 이 녀석은 Router
의 HOC
로써 컴포넌트에서 router
props를 전달받을 수 있도록 해준다.
History
예제를 위해서 root 경로에 components
디렉토리를 만들고 하위에 History.js
파일을 생성한다.
그런 다음, History.js
에는 다음과 같이 작성한다.
History.js
import React, { Component } from 'react';
import { withRouter } from 'next/router';
const styles = {
history: {
color: 'red',
},
};
class History extends Component {
render() {
const { router } = this.props;
return router.query.history ? (
<div style={styles.history}>
{router.query.history}
</div>
) : null;
}
}
export default withRouter(History);
import { withRouter } from 'next/router'
로 모듈을 import 시키고 withRouter(History)
로 Component를 감싸게 되면 props로 router를 전달받을 수 있게 된다.
index.js
는 다음과 같이 변경한다.
index.js
import History from '../components/History';
export default (props) => {
return (
<div>
Home
<History />
</div>
);
}
작성한 후에 화면을 확인한다.
index.js
에서 <History>
로 router
를 props으로 전달하지 않지만 <History>
컴포넌트에서 HOC
로 withRotuer
를 사용했기 때문에 props로 router
오브젝트를 전달받은 것을 볼 수 있다.