리액트로 웹 애플리케이션을 빌드하기 위해서 고려해야 할 중요한 점들
framework
로는 이런 문제들을 해결할 수 없다. 그러나 이러한 프레임워크들은 올바른 추출?추상화의 수준이 있어야 한다. 그렇지 않으면 이것들은 쓸모 없을 것이다. 또한 수준급의 개발자 경험
이 있어야 한다.
Next.js는 위에 문제들 모두에 해결책을 제시한다.
이 튜토리얼을 통해 어떻게 Next.js를 시작할 지 배울 수 있다.
먼저 개발환경을 준비하자.
Next.js app을 생성하기 위해서 우선 터미널을 열고 cd
치면서 이 프로젝트를 생성하고 싶은 폴더 내로 들어간다.
우선 블로그 만드는 예제로 보자.
npm init next-app nextjs-blog --example "주소"
이제 새 디렉토리를 생성해서 cd 로 들어가자.
cd 디렉토리 이름
이제.
npm run dev
이것은 당신의 Next.js의 개발서버를 시작하는 것이다. localhost3000 을 들어가면
라는게 뜰 것이다.
이제 스타터 페이지를 수정해보자.
pages/index.js
를 당신의 text editor로 열어라.파일을 저장하는대로 브라우저는 자동적으로 reload되고 업데이트 될 것이다.
Next.js 개발 서버는 Hot Reloading 의 특징을 가진다. 당신이 파일에서 무엇인가를 고치면 자동적으로 반영되어 브라우저에 변화가 생긴다.
자 이제 첫 번째 레슨이 끝났다.
다음은 더 많은 페이지를 만들고 페이지 사이를 이어주는 작업이다.
지금까지는 우리가 생성한 Next.js app은 오직 한 페이지를 가지고 있다. 일반적으로 웹사이트들과 웹 어플리케이션은 많은 다른 페이지들을 가질 수 있다.
이제 우리의 어플리케이션에 어떻게 더 많은 페이지를 더할 수 있을 지 탐구해보자.
Link
컴포넌트를 어떻게 사용하는가npm init next-app nextjs-blog --example "https://github.com/vercel/next-learn-starter/tree/master/navigate-between-pages-starter"
터미널에서 원하는 폴더 안에서 이걸 쳐주면 해당하는 폴더가 생긴다.
cd nextjs-blog를 해준다.
시작은 npm run dev
Next.js에서 page는 pages 라는 디렉토리에서 내보낸 리액트 구성요소이다.
페이지들은 파일 이름을 기준으로 경로와 연결된다.
pages 내에 posts라는 폴더를 만들고 first-post.js라는 파일을 만들어서
export default function FirstPost() {
return(
<h1>First Post</h1>
)
}
를 적고 localhost:3000/posts/first-post 로 들어가면
빈 화면에 이렇게 뜨는것을 볼 수 있다.
컴포넌트는 어떤 이름도 가질 수 있지만 내보낼 때 default
로 내보내야 한다.
pages 폴더 내에 JS 파일 손쉽게 생성하고 url path가 어떻게 되는지 보았다. 어떤면에서는 이것은 html 또는 php파일을 사용하여 웹 사이트를 구축하는 것과 유사하다. html를 작성하는 대신 jsx를 작성하고 React Components를 사용한다.
페이지들을 연결할 때 우리는 대부분 html의<a>
태그를 사용했다.
Next.js에서는 우리는 <Link>
를 사용할 것이다. 이 태그는 <a>
태그를 감싸는 형태이고 이 태그는 응용 프로그램의 다른 페이지로 클라이언트 쪽 탐색을 수행할 수 있다.
첫번째로 pages/index.js
에 Link 를 import해야 한다.
import Link from 'next/Link
그리고 h1 태그를 사용해준 뒤 그 밖에 Link 태그를 넣어준다.
원래 a태그 쓰면
<a href="">hallo</a>
Link 쓰면
<Link href=""><a>hallo</a></Link>
이렇게 href위치가 되어야 한다.
이제 우리가 전에 만들었던 first-post.js를 연결해주자.
<Link href="/posts/first-post"><a>this page!</a></Link>
import Link from 'next/link'
export default function FirstPost() {
return(
<>
<h1>First Post</h1>
<h2>
<Link href="/">
<a>back to home</a>
</Link>
</h2>
</>
)
}
아예 다른 페이지로 이동하는거라면 Link 말고 a태그만 이용하자.
그리고 만약 className
같은 속성이 필요하다면 a태그에 넣자. Link태그 말고!
Next.js는 기본적으로 CSS와 SASS를 지원하고 있다.
이 튜토리얼에서는 CSS를 쓰게된다.
이번 단원에서는 Next.js가 이미지와 같은 정적 assets와 title 태그와 같은 페이지 메타 데이터를 처리하는 방법에 대해서 설명한다.
<head>
안에 있는 것을 어떻게 customize할 것인가.pages/_app.js
에 어떻게 global CSS를 넣을 것인가먼저, Next.js가 이미지 같은 정적인 assets를 어떻게 handle하는지 얘기해보자.
Next.js는 이런 정적인 파일들을 제일 상위 레벨에 있는 public
디렉토리 밑에서 받을 수 있다. public
안에 있는 파일들은 pages
와 같이 어플리케이션의 root에서부터 참조될 수 있다.
만약 당신이 당신의 어플리케이션에서 pages/index.js
를 연다면 <footer>
부분을 살펴보아라. 우리는 이렇게 넣을 것이다.
<img src="/vercer.svg" alt="Vercel Logo" className="logo">
logo 이미지는 public
디렉토리 안에 있다.
그 public
는 또한 robots.txt
, Google Site Verification 또는 그 어떤 정적인 assets도 유용하게 사용할 수 있다.
만약 우리가 <title>
HTML 태그와 같은 페이지의 metadata를 수정하고 싶다면 어떻게 해야 할까?
<title>
은 <head>
태그의 부분인데 이제 우리는 Next.js페이지에서 어떻게 <head>
태그를 수정할 수 있는지 알아볼 것이다.
<Head>
<title>Create Next App</title>
<link rel="icon" href="/favicon.ico" />
</Head>
방금 위에서 <head>
가 아닌 <Head>
를 썼다. 이 <Head>
는 Next.js 안에 내장된 React Component로 <head>
를 수정하게 허락해준다.
Head 는 'next/head'모듈로 import 해 올 수 있다.
만약 http://localhost:3000/posts/first-post 의 title을 바꾸고 싶다면
import Head from 'next/head'
export default function FirstPost() {
return(
<>
<Head>
<title>First Post</title>
</Head>
</>
)
}
이렇게 하면 된다.
pages/index.js
를 보면
<style jsx>{`
...
`}</style>
라고 되어있는 styled-jsx
라는 라이브러리를 볼 수 있다. 이 라이브러리는 "CSS-in-JS"라이브러리로 React component안에 CSS를 쓸 수 있다. 그리고 CSS 스타일들은 해당 component안에 scoped될 것이다.(다른 컴포넌트에 영향을 주지 않을 것이다.)
Next.js에 styled-jsx가 내장되어있다. 그러나 styled-components나 다른 라이브러리를 사용할 수 있기도 하다.
먼저, 모든 페이지에서 공통적인 layout 구성요소를 만들어보자.
components
라고 불리는 상위 디렉토리를 생성하자layout.js
라고 불리는 파일을 생성하자.function Layout({children}) {
return <div>{children}</div>
}
export default Layout
그리고 나서 pages/posts/first-post.js
안에 Layout을 import해서 가장 바깥쪽에 두르자.
import Head from 'next/head'
import Link from 'next/link'
import Layout from '../../components/layout'
export default function FirstPost() {
return (
<Layout>
<Head>
<title>First Post</title>
</Head>
<h1>First Post</h1>
<h2>
<Link href="/">
<a>Back to home</a>
</Link>
</h2>
</Layout>
)
}
자 이제 Layout을 위한 스타일을 할 것이다. 그러기 위해서, 우리는 CSS Modules를 사용할것이다.
layout.module.css
라는 파일을 components디렉토리 안에 만들자
.container {
max-width: 36rem;
padding: 0 1rem;
margin: 3rem auto 6rem;
}
CSS Modules를 사용하기 위해서 CSS 파일의 이름은
.module.css
가 되어야 한다.
이 Layout
을 사용하기 위해서는
styles
를 import 해준다.styles.<class-name>
을 className처럼 쓴다.container
이고 우리는 styles.container
를 사용할 것이다.import styles from './layout.module.css'
export default function Layout({ children }) {
return <div className={styles.container}>{children}</div>
}
만약 모든 페이지에 어떤 CSS를 로드하고 싶다면 pages
밑에 _app.js
라는 파일을 만들어서 이렇게 적어야 한다.
export default function App({ Component, pageProps}) {
return <Componnent {...pageProps} />
}
이 App
컴포넌트는 모든 다른 페이지들 사이에 공통적으로 있을 상위 레벨의 컴포넌트이다. App
컴포넌트는 또한 페이지 사이에서 state를 유지시키고 싶을 때 사용할 수 있다.
_app.js
를 더했다면 develpment server를 다시 시작해줘야 한다.Ctrl + c
를 눌러 server 를 멈추고
npm run dev
Nest.js에서 _app.js
에서 import하면 가능하지만 아무데서나 global CSS를 import 할 수는 없다.
_app.js
가 아닌 다른 곳에서 import 하게 되면 모든 요소들에게 영향을 끼친다.
그러면 어떻게 해아할까.
styles
디렉토리를 생성하고 그 안에 global.css
라는 파일을 만든다.html,
body {
padding: 0;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu,
Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
line-height: 1.6;
font-size: 18px;
}
* {
box-sizing: border-box;
}
a {
color: #0070f3;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
img {
max-width: 100%;
display: block;
를 써서 _app.js
에 import 해준다.
import '../styles/global.css'
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />
}
만약 안된다면
_app.js
를 더했을 때 development server를 재시작 해줬는지 다시 확인해라.
*.mocule.css
를 써서 어떤 컴포넌트에도 import해서 사용할 수 있다.pages/_app.js
안에 css 파일을 import 해준다.먼저, 우리는 마지막 디자인을 위해서 프로필 사진을 더해줄 것이다.
public
디렉토리 안에 images
디렉토리 생성.components/layout.module.css
업데이트.container {
max-width: 36rem;
padding: 0 1rem;
margin: 3rem auto 6rem;
}
.header {
display: flex;
flex-direction: column;
align-items: center;
}
.headerImage {
width: 6rem;
height: 6rem;
}
.headerHomeImage {
width: 8rem;
height: 8rem;
}
.backToHome {
margin: 3rem 0 0;
}
styles/utils.module.css
생성.heading2Xl {
font-size: 2.5rem;
line-height: 1.2;
font-weight: 800;
letter-spacing: -0.05rem;
margin: 1rem 0;
}
.headingXl {
font-size: 2rem;
line-height: 1.3;
font-weight: 800;
letter-spacing: -0.05rem;
margin: 1rem 0;
}
.headingLg {
font-size: 1.5rem;
line-height: 1.4;
margin: 1rem 0;
}
.headingMd {
font-size: 1.2rem;
line-height: 1.5;
}
.borderCircle {
border-radius: 9999px;
}
.colorInherit {
color: inherit;
}
.padding1px {
padding-top: 1px;
}
.list {
list-style: none;
padding: 0;
margin: 0;
}
.listItem {
margin: 0 0 1.25rem;
}
.lightText {
color: #999;
}
components/layout.js
업데이트import Head from 'next/head'
import styles from './layout.module.css'
import utilStyles from '../styles/utils.module.css'
import Link from 'next/link'
const name = 'Your Name'
export const siteTitle = 'Next.js Sample Website'
export default function Layout({ children, home }) {
return (
<div className={styles.container}>
<Head>
<link rel="icon" href="/favicon.ico" />
<meta
name="description"
content="Learn how to build a personal website using Next.js"
/>
<meta
property="og:image"
content={`https://og-image.now.sh/${encodeURI(
siteTitle
)}.png?theme=light&md=0&fontSize=75px&images=https%3A%2F%2Fassets.vercel.com%2Fimage%2Fupload%2Ffront%2Fassets%2Fdesign%2Fnextjs-black-logo.svg`}
/>
<meta name="og:title" content={siteTitle} />
<meta name="twitter:card" content="summary_large_image" />
</Head>
<header className={styles.header}>
{home ? (
<>
<img
src="/images/profile.jpg"
className={`${styles.headerHomeImage} ${utilStyles.borderCircle}`}
alt={name}
/>
<h1 className={utilStyles.heading2Xl}>{name}</h1>
</>
) : (
<>
<Link href="/">
<a>
<img
src="/images/profile.jpg"
className={`${styles.headerImage} ${utilStyles.borderCircle}`}
alt={name}
/>
</a>
</Link>
<h2 className={utilStyles.headingLg}>
<Link href="/">
<a className={utilStyles.colorInherit}>{name}</a>
</Link>
</h2>
</>
)}
</header>
<main>{children}</main>
{!home && (
<div className={styles.backToHome}>
<Link href="/">
<a>← Back to home</a>
</Link>
</div>
)}
</div>
)
}
pages/index.js
업데이트import Head from 'next/head'
import Layout, { siteTitle } from '../components/layout'
import utilStyles from '../styles/utils.module.css'
export default function Home() {
return (
<Layout home>
<Head>
<title>{siteTitle}</title>
</Head>
<section className={utilStyles.headingMd}>
<p>[Your Self Introduction]</p>
<p>
(This is a sample website - you’ll be building a site like this on{' '}
<a href="https://nextjs.org/learn">our Next.js tutorial</a>.)
</p>
</section>
</Layout>
)
}
까지 4단계를 거치면
완성.
이제 data fetching lesson으로 가자.