article thumbnail image
Published 2022. 9. 6. 21:33

https://nextjs.org/

 

Next.js by Vercel - The React Framework

Production grade React applications that scale. The world’s leading companies use Next.js by Vercel to build static and dynamic websites and web applications.

nextjs.org

 

npx create-next-app@latest

npx create-next-app@latest --typescript

npm run dev

 

Framework

기본적인 코드는 React와 상당히 유사할지도 모르지만 동작면에서는 상당히 큰 차이가 있다.

 

단순히 라이브러리처럼 어떤 기능을 호출하고 사용하는 것이 아닌 Nextjs는 코드를 규칙에 따라 작성하고 그 코드를 실행시켜야 작동한다 index파일은 page 폴더에서 자체적으로 home (“ / “)으로 라우팅시켜 보여주기 때문에 Home.js 등등이 아닌 index.js로 만들어야 처음 루트로 설정해줄 수 있게 된다

뿐만 아니라 pages내부에 있는 모든 폴더들은 각각의 파일명이 page의 실제 주소가 된다

 

Static Pre Rendering

react에서 client-side-rendering → 비어있는 div(빈 화면)를 갖고오고 나서 브라우저가 모든 reactjs(여기서 모든 코드는 js로 구성되어 있다)를 요청 → 받은 reactjs를 실행 →이 과정을 다 거치고 앱이 유저에게 보여짐.. 이 말은 연결이 느리다면 클라이언트에게는 빈 화면으로 보이면서 reactjs 코드를 가져오고 있다는 사실을 인지하지 못한다면 사용자에게는 큰 불편으로 다가온다(UX).

 

반면 nextjs를 쓰게 된다면 nextjs로 미리 생성 된 html코드가 존재하고 있어 클라이언트가 모든 데이터들을 볼 수는 없지만 html로구성되어 있는 페이지들은 확인할 수 있다

 

 

 

결론적으로 nextjs가 동작하는 방식은 유저가 웹사이트로 오면 초기 상태의 component로 미리 생성된 html 페이지를 보게 되고, 그 뒤에 reactjs코드를 받아와 채워지게 된다.

이것을 hydration이라고 하며 nextjs에서 SSR로 개발하여도 useState등을 사용할 수 있게 된다

 

 

Routing

https://nextjs.org/docs/api-reference/next/router

라우팅이 쉽다. 단순하게 pages 폴더의 파일명이 routing 주소로 활용된다

 

주의 : _app.js와 index.js같이 특수한 파일명은 라우팅 되지않을 수 있다.

 

ex) http://localhost:3000/About , http://localhost:3000/button = 대소문자 주의

 

 

Nextjs에서는 앱 내부에서 페이지를 네비게이트할 때 <a> 태그가 아닌 꼭 사용해야하는 component가 있다. 사용해야하는 이유는 기존 anchor태그와 마찬가지로 페이지가 새로고침 되어 다시 불러오기 때문에 상당히 느려질 수 있다

Router처럼 Link 로 지원하고 있다 사용법은 똑같다 href=""로 전달하면 된다.

 

Link는 오로지 href 때문에 존재하는 것이라서 href 를 제외한 나머지 스타일은 전부 Link안에 있는 <a> 태그에 넣는다 style, className …

import Link from "next/link"

export default function NavBar() {
    return (
        <nav>
            <Link href="/"><a>Home</a></Link>
            <Link href="/About"><a>about</a></Link>
            <Link href="/button">button</Link>
        </nav>
    );
}

 

useRouter() 라는 Next.js hook이 있는데 이것을 사용하게 되면 location에 대한 정보를 준다

useRouter 에서 주는 정보들을 사용

<Link href="/"><a style={{color : router.pathname === "/" ? "red" : "yellow"}}>Home</a></Link>
<Link href="/About"><a style={{color : router.pathname === "/About" ? "red" : "black"}}>about</a></Link>

 

CSS in Nextjs

  • 단순히 style을 추가

<a style={{color : "yellow"}}>Home</a>

  • .module.css 를 사용

이렇게 하게 되면 module로써 css를 추가하게 되기 때문에 단순히 className 을 추가시켜서 해결할 수 없다

 

import "./Navbar.css" (X)

import styles from "./Navbar.module.css"

 

<nav className="nav">(X)

<nav className={styles.nav}> 특정 module을 사용하는 것 처럼 이렇게 사용한다.

 

단순한 string 형식의 텍스트가 아닌 js object에 접근하는 property로 적는다

 

무작위로 네이밍하기 때문에 충돌이 발생하지 않는다는 장점이 있다. (중복해서 사용해도 문제 없다)

import Link from "next/link"
import {useRouter} from 'next/router';
import styles from "./Navbar.module.css"

export default function NavBar() {

    const router = useRouter();

    return (
        <nav>
            <Link href="/"><a className={router.pathname === "/" ? styles.active : ""}>Home</a></Link>
            <Link href="/About"><a className={router.pathname === "/About" ? styles.active : ""}>about</a></Link>
            <Link href="/button">button</Link>
        </nav>
    );
}
}

위에서 봤던 코드와 비슷한 코드임.

<Link href="/"><a className={`${styles.link} ${router.pathname === "/" ? styles.active : ""}`}>Home</a></Link>

 

 

두가지를 적용시키기 위해 이런 방식도 있다. 상태에 따라 css 적용..

  • styled jsx

Nextjs의 고유한 방식으로 이전에 했던 방법들과는 조금 다르다

import Link from "next/link"
import {useRouter} from 'next/router';
import styles from "./Navbar.module.css"

export default function NavBar() {

    const router = useRouter();

    return (
        <nav>
            <Link href="/"><a className={router.pathname === "/" ? "active" : null}>Home</a></Link>
            <Link href="/About"><a className={router.pathname === "/About" ? "active" : null}>about</a></Link>
            <Link href="/button"><a className={router.pathname === "/button" ? "active" : null}>button</a></Link>
            <style jsx>{`
                nav {
                    background-color:yellow;
                }
                a {
                    text-decoration:none
                }
                .active {
                    color: red;
                }
            `}</style>
        </nav>
    );
}
            <style jsx>{`
                nav {
                    background-color:yellow;
                }
                a {
                    text-decoration:none
                }
                .active {
                    color: red;
                }
            `}</style>

<style jsx>{``}

class 이름도 jsx가 된다

이 때 사용하는 스타일들은 같은 컴포넌트 안에 있는 스타일로만 제한된다. 쉽게 말하면 같은 className을 가지고 있는 HTML 태그가 다른 컴포넌트 안에 있다고 해도 각각 독립적으로 있기 때문에 서로 영향을 주지 않는다 (컴포넌트 내부로 한정한다) <a>태그가 다른 컴포넌트에 있다고 해도 <a> jsx로 스타일을 줬을 때 서로 영향을 주지 않음

  • 전역 CSS 적용

<style jsx global>

단순하게 global만 붙여도 되지만, 이때 Route되는 page를 고려해야 한다.

import {useState} from "react";
import NavBar from "../components/Navbar";

export default function Home() {
    return  (
        <>
            <div>
                <h1 className="active">Hello</h1>
            </div>
            <style jsx global>{`
                a {
                    color: white;
                }
            `}</style>
        </>
    );
}

예를 들어 page에 index.js에 global 스타일을 적용시켰다면 home주소가 http://localhost:3000/ 일때만 global로 적용시킨 css가 적용된다.

 

그렇기 때문에 Global CSS효과를 모든 파일(페이지, 컴포넌트)에 적용시키기 위해서는 _app.js를 만들어야한다.

 

_app.js파일은 단순히 css효과를 전역으로 적용시키는 것이 아니라 다른 역할을 갖고 있는데, 하나의 페이지가 실행되기 전에 먼저 동작하고 그 다음에서야 pages에 있는 js파일이 실행된다. 단순하게 middleware라고 생각해도 될거같다(특정 페이지에 진입하기 전 거치는 미들웨어 페이지) → 어떤 페이지가 실행될 때마다 먼저 실행 됨.

 

때문에 만약 page마다 공통된 component, 예를 들면 NavigationBar..가 있을 때 이 component를 넣어놓는다면 모든 페이지들에 NavigationBar 컴포넌트를 불러오지 않더라도 _app.js에서 불러지기 때문에 각 페이지에서 마다 호출할 필요가 없어진다. 그 다음 순서에 맞춰 불러오면 된다. <Component {...pageProps}/> 이 형식을 지켜야 불러올 수 있다. 또한 반드시 _app.js로 파일명을 만들어야 하고 내부에 있는 export default시키는 것은 이름에 신경 쓸 필요가 없다.

import NavBar from "../components/Navbar";
import "../../styles.css"

export default function CustomApp ({Component, pageProps}) {
    return (
        <>
            <NavBar/>
            <Component {...pageProps}/>
        </>
    )
    //이 페이지를 자동으로 부를 것이다. 각각에 잇는 컴포넌트를 받아와서
}

뿐만 아니라 _app.js 파일에서는 css를 모듈이 아닌 .css파일로 불러올 수 있게 됩니다.

_app.js 파일은 단순히 global css로 사용하는게 아니라 Layout으로 활용할 수 있도록 만들 수 있습니다.

//Layout.js

import NavBar from "./Navbar";

export default function Layout({children}) {
    return (
    <>
        <NavBar/>
        <div>{children}</div>
    </>
    )
}
// _app.js
import Layout from "../components/Layout"
import "../styles/globals.css"

export default function CustomApp ({Component, pageProps}) {
    return (
        <>
            <Layout>
                <Component {...pageProps}/>
            </Layout>
        </>
    )
    //이 페이지를 자동으로 부를 것이다. 각각에 잇는 컴포넌트를 받아와서
}

 

Next.js의 여러가지 기능

next/router , next/link , next/head ,next/Image …

 

router : 현재 페이지 정보를 Object로 보여줌

Link : anchor 태그 대신 Link를 사용(대신 CSS는 적용할 수 없기 때문에 안에 anchor태그를 씀)

head : HTML head의 역할을 그대로 함 <Head></Head>

 

https://nextjs.org/docs/api-reference/cli

 

CLI | Next.js

The Next.js CLI allows you to start, build, and export your application. Learn more about it here.

nextjs.org

 

 

단순 라이브러리를 받아 호출해서 사용하는게 아닌 규칙에 따라 내가 직접 코드를 작성해서 사용

  • redirect , rewrite

https://nextjs.org/docs/api-reference/next.config.js/introduction

next.confing.js에서 사용하게 되는데 환경 설정이라고 이해해도 된다.(사용자 지정 고급 구성)

const API_KEY  = process.env.API_KEY

module.exports = {
  reactStrictMode: true,
  async redirects() {
    return [
      {
        source:"/contact", //      "/contact/:path"  "/contact/:path*"
        destination:"<https://youtube.com>", //      "/contact/:path"  "/newcontact/:path*"
        permanent: false,  //검색엔진에 정보를 기록하는 역할도 함
      }
    ]
  },
  async rewrites() {
    return [
      {
        //rewrties 사용자를 redirect 시키긴 하지만 주소는 바뀌지 않는다
        source :"/api/movies",
        destination: `https://api.themoviedb.org/3/movie/popular?api_key=${API_KEY}`
      },
      {
        source : "/api/movies/:id",
        destination: `https://api.themoviedb.org/3/movie/:id?api_key=${API_KEY}`
      }
    ]
  }
}

redirect란 클라이언트가 어떤 페이지로 접속했을 때 다른 페이지로 연결시켜주는 것을 의미한다

source URL로 갔을 때 destination URL로 강제로 이동시켜 주고 사용자는 그것을 확인할 수 있다.

  async redirects() {
    return [
      {
        source:"/contact", //      "/contact/:path"  "/contact/:path*"
        destination:"<https://youtube.com>", //      "/contact/:path"  "/newcontact/:path*"
        permanent: false,  //검색엔진에 정보를 기록하는 역할도 함
      }
    ]
  },

 

검색엔진에도 영향을 주는데 permanent를 줄 경우 브라우저, 검색엔진이 정보를 기억하게 된다.

 

rewrite란 redirect와 비슷한 동작을 하지만, 사용자가 URL변화를 확인할 수 없다

destination에서는 기존 목적지를 입력하고 source에서는 사용자에게 보여지고 실제로 요청하는 destination URL을 다르게 쓴 것을 의미한다.

 

또한 서버쪽에서 일어나기 때문에 redirect와는 다르게 클라이언트는 URL의 변화를 알 수 없다

destination URL처럼 쓰는 것을 그저 source URL처럼 쓴 것 뿐이다.

 

API key를 숨기거나 하는 보안상의 이유 때문에 자주 사용된다

async rewrites() {
    return [
      {
        //rewrties 사용자를 redirect 시키긴 하지만 주소는 바뀌지 않는다
        source :"/api/movies",
        destination: `https://api.themoviedb.org/3/movie/popular?api_key=${API_KEY}`
      },
      {
        source : "/api/movies/:id",
        destination: `https://api.themoviedb.org/3/movie/:id?api_key=${API_KEY}`
      }
    ]
  }

API키를 찾을 수 있다(개발자도구 → 네트워크)

rewrite를 써서 바뀜

 

  • Server Side Rendering

https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props

 

Data Fetching: getServerSideProps | Next.js

Fetch data on each request with `getServerSideProps`.

nextjs.org

Data를 다 받아왔고 SEO는 이러한 것을 수집함

 

CSR은 자바스크립트가 로딩이 끝나면 그제서야 API로 데이터 요청을 보낸다. 하지만 SSR은 한번의 요청에 아예 렌더링 된 페이지로 불러와진다. 이말은 데이터 api 요청을 보내고나서 데이터 자체를 프론트에 넘겨준다.

그래서 CSR은 Loading.. text가 출력되기도 하지만 SSR은 그런거 없어도 데이터 자체가 이미 렌더링할 때 불러와졌기 때문에 필요없다.

 

SEO에 많은 영향을 준다.

 

  • 동적 라우팅

http://localhost:3000/movies/all 등등 http://localhost:3000/movies/…으로 이동하기 위해서 폴더로 만들어 줘도 된다 하지만 폴더 자체도 라우팅 경로가 되니 주의http://localhost:3000/movies/all

 

또 폴더안에 index.js가 들어가게 되면 폴더명 자체가 라우팅주소가 된다( 위 movies파일에 index.js 가 들어가면 http://localhost:3000/movies로 라우팅 된다. 마지막으로 정리하면 페이지가 하나면 폴더가 필요없다

 

하지만 중첩라우팅 하듯이 뒤로 쭉 이어져야 한다면 폴더를 만들고 index.js와 그 외 파일을 만들어야 한다

 

  • URL parameter가 필요할 때

[id].js [ ]안에 변수를 입력해서 pages 폴더에 만들게 되면 변수(id)가 필요한 동적 URL이라는 것을 알려줌

복사했습니다!