Next.js로 정적 웹사이트 만들기 - 4. Routing 사용하기

2019.05.24(6달 전)

지난 글에서 index.jspost.js를 생성했었고 Routing을 사용하지 않고 URL로 직접 접근해서 화면을 확인했었다. 이번 글에서는 Next.jsRouting을 사용하여 페이지 전환을 해보려고한다.

Next.js githubRouting에 대한 설명이 잘 나와있다.

Next.js에서 Routepages디렉토리 경로에 작성한 파일명으로 생성된다. 그렇기 때문에, 파일명도 신경써서 잘 만들어야한다.

about.js 파일 생성

Routing 경로를 더 추가하기 위해 pages디렉토리에 about.js파일을 추가하고 다음과 같이 작성한다.

export default (props) => {
    return (
        <div>About</div>
    );
}

about.js까지 생성하였다면 총 3개의 Routing이 생기게 되었다.

그런 다음, 공통의 레이아웃이 작성된 _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>를 추가해준다.

여기까지 작성되었다면 다음과 같은 화면이 보일 것이다.

first-routing

한 번씩 눌러본다.

first-routing-click

post.js에 Router 추가

다음으로, <button>엘리먼트 onClick을 이용해서 Routing을 해보는데, 이때 Next.jsRouter를 사용해본다.

먼저, <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('/')를 추가한다.

여기까지 작성되었다면 다음처럼 동작한다.

first-router-click

마찬가지로 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.jsabout.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에 다음처럼 보이게 된다.

first-query-string

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

화면을 확인해본다.

first-query-string-from

as 속성으로 URL Params 숨기기

URL Params가 URL에 보이는 것이 맘이 편하지 않다면 Next.js에서는 숨길 수 있는 방법이 있다.

as속성을 이용하는 것인데, <Link href="/?history=post" as="/">로 사용하거나 Router.push("/?history=post", '/')로 사용할 수 있다.

post.jsabout.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>
    );
}

다시 화면을 확인해본다.

first-routing-as

아까와는 다르게 URL에 Query String이 붙지 않고 history가 전달된 것을 확인할 수 있다.

하지만 이 방법에서 문제점을 찾으라고 한다면, 새로고침을 했을 때 전달받은 router 오브젝트에 query가 비어있으므로 From the문구가 보이지 않게 된다.

withRouter 사용

다음으로 withRouter를 사용해볼 것인데, 이 녀석은 RouterHOC로써 컴포넌트에서 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>
    );
}

작성한 후에 화면을 확인한다.

first-router-history

index.js에서 <History>router를 props으로 전달하지 않지만 <History>컴포넌트에서 HOCwithRotuer를 사용했기 때문에 props로 router오브젝트를 전달받은 것을 볼 수 있다.

first-router-history-log

Next.js로 정적 웹사이트 만들기 목차

react
nextjs
website
Sung Gyun Oh
Sung Gyun Oh
Hello world!