- [노마드코더] NextJS 시작하기 #1
- [노마드코더] NextJS 시작하기 #2
- [노마드코더] NextJS 시작하기 #3
- [노마드코더] NextJS 시작하기 #4
- [노마드코더] NextJS 시작하기 #5
전의 글에 이어서 계속해서 강의내용을 정리하려고 한다.
Routing
우선 components 폴더를 생성해서 안에 새로운 파일을 작성해준다.
<components/NavBar.js>
export default function NavBar() {
return (
<nav>
<a href="/">HOME</a>
<a href="/about">About</a>
</nav>
);
}
그리고 전에 만들었던 index.js와 about.js의 내용을 약간 수정해준다.
<pages/index.js>
import NavBar from "../components/NavBar";
export default function Home() {
return (
<div>
<NavBar />
<h1>Hello </h1>
</div>
);
}
<pages/about.js>
import NavBar from "../components/NavBar";
export default function about() {
return (
<div>
<NavBar />
<h1>About us</h1>
</div>
);
}
=>이렇게 하면 NavBar.js에서 페이지를 이동할때 a태그를 사용하지 마라는 에러가 뜬다.
(나는 안뜬다...밑줄이 있어야하는데 나는 없음ㅠ) 안뜨는 이유를 찾았다! 만약 메시지가 뜨지 않는다면 플러그인에서 ESLint를 설치하기 바람.
이런 에러가 뜨는 이유는 NextJS에 페이지를 이동할 때 사용해야만 하는 특정 컴포넌트가 존재하기 때문이다.
React에서 React Router Link를 사용해야만 할 때와 이유가 동일하다.
만약 a태그를 사용한 채로 페이지를 이동하게 되면 전체 어플리케이션이 새로고침 된다. 이것은 클라이언트 사이드 네비게이션이 없다는 의미이다. 즉, 다른 페이지로 이동하기 위해서 전체 페이지를 새로고침 한다는 의미다.
실제로 a태그를 사용한 부분을 클릭하고 파비콘을 보면 새로고침 되는 모습을 볼 수 있다. 또한 약간의 딜레이도 느낄 수 있다.
경고문을 읽어보면 a태그 말고, next/link를 import해서 Link태그를 사용하라고 친절하게 알려주고 있다.
Link태그는 클라이언트 사이드 네비게이션을 제공해준다.
사용 방법은 다음과 같다.
기존의
<a href="/">HOME</a>
을 Link를 사용해서 변경하려면
<Link href="/">
<a>HOME</a>
</Link>
이런식으로 바깥에 Link로 감싸주고, href 속성을 Link로 옮겨준다.
그리고 다시 링크가 걸려있는 부분을 클릭해보면 파비콘도 그대로고 확실히 속도면에서 빠르게 이동하는 것을 느낄 수 있다.
a태그를 지워도 작동은 한다. 하지만 Link태그에는 클래스명이나 파라미터를 넘길 수 없기 때문에 여러가지 속성들을 적용하고 싶다면 a태그에 적용을 해줘야한다. Link태그에는 오직 href 속성만을 사용한다.
Next에서는 useRouter라는 hook를 사용하면 location정보를 알 수 있다.
import Link from "next/link";
import { useRouter } from "next/router";
export default function NavBar() {
const router = useRouter();
console.log(router);
return (
<nav>
<Link href="/">
<a>HOME</a>
</Link>
<Link href="/about">
<a>About</a>
</Link>
</nav>
);
}
NavBar.js 파일인데 useRouter를 사용하고, router정보를 콘솔에 찍어봤다.
그러면
다음과 같이 경로에 대한 여러가지 정보를 얻을 수 있다.
여기서 현재 페이지 정보를 가지고 있는 pathname을 사용해서 style을 적용해줄 수 있다.
import Link from "next/link";
import { useRouter } from "next/router";
export default function NavBar() {
const router = useRouter();
return (
<nav>
<Link href="/">
<a style={{ color: router.pathname === "/" ? "red" : "blue" }}>HOME</a>
</Link>
<Link href="/about">
<a style={{ color: router.pathname === "/about" ? "red" : "blue" }}>About</a>
</Link>
</nav>
);
}
css 적용하기
NavBar.js가 위치한 components폴더 안에 NavBar.module.css 파일을 생성해준다.
NavBar은 이름이기 때문에 본인이 하고 싶은대로 수정해도 된다. 하지만 module.css는 동일하게 작성해야한다.
그리고 NavBar.module.css 파일 안에 다음과 같이 작성한다.
.nav {
display: flex;
justify-content: space-between;
background-color: tomato;
}
그리고 다시 NavBar.js로 돌아와서 아까 style 적용한 것들은 지워주고, css파일을 import 시켜서 적용해준다.
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 className={styles.nav}>
<Link href="/">
<a>HOME</a>
</Link>
<Link href="/about">
<a>About</a>
</Link>
</nav>
);
}
css를 적용하는 부분은
<nav className={styles.nav}>
이 부분인데, 원래의 css 파일을 사용할 때는 className="nav"로 작성을 해주면 style이 적용이 되지만 우리는 module.css 파일이기 때문에 저렇게 작성하면 적용이 안된다. 위와 같이 작성해줘야한다.
이렇게 사용하는 것을 css모듈이라고 불린다. 실제로 페이지에 가서 nav태그를 보면 다음과 같이 임의의 이름으로 클래스 이름이 되어있는 것을 볼 수 있다.
그렇기 때문에 다른 컴포넌트에서 nav라는 동일한 이름을 사용해도 충돌이 발생하지 않는다.
위에서 구현했던 것을 modul.css방식을 사용해서 똑같이 구현해보자면,
<NavBar.js>
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>
</nav>
);
}
<NavBar.module.css>
.active {
color: tomato;
}
로 작성해주면 된다.
만약 두 개의 클래스 명을 적용하고 싶다면
<a className={`${styles.link} ${router.pathname === "/" ? styles.active : ""}`}>HOME</a>
이렇게 사용하는 방법과
<a className={[styles.link, router.pathname === "/about" ? styles.active : ""].join(" ")}>About</a>
요로케 사용하는 방법이 있다.
CSS를 적용하는 또 다른 방법이 있다. 위에서 썼던 방법은 CSS Modules라는 방법이고, 이제 해볼 방법은 Styled JSX방법이다. 두 개의 방법 모두 CSS-in-JS방법이고, Styled JSX방법은 NextJS의 고유의 방법이다.
이번에는 NavBar.js에 다음과 같이 작성해준다.
import Link from "next/link";
export default function NavBar() {
return (
<nav>
<Link href="/">
<a>HOME</a>
</Link>
<Link href="/about">
<a>About</a>
</Link>
<style jsx>{`
nav {
background-color: tomato;
}
a {
text-decoration: none;
}
`}</style>
</nav>
);
}
그리고 나서 웹페이지에서 className을 확인해보면 더 복잡한 클래스 이름을 갖고 있는 것을 확인할 수 있다.
Styled JSX의 장점은 방금과 같이 NavBar.js에 아래와 같이 a태그와 관련된 스타일을 작성하고
<style jsx>{`
a {
color:blue;
}
`}</style>
index.js에 가서 위와 동일하지만 색을 red로 변경한 a태그와 관련된 스타일을 작성한다고 했을 때, 서로에게 영향을 주지 않는다. 독립적으로 작동하는 것을 볼 수 있다.
즉, 다시말해서 하나의 컴포넌트에서 작성한 Styled JSX코드는 다른 컴포넌트에는 영향을 끼치지 않기 때문에 이름을 동일하게 작성해도 상관없다. 작성한 컴포넌트 내에서만 유효하다.
Global Style
그렇다면 전역 스타일을 적용하려면 어떻게 해야할까?
간단한 방법으로는 style 태그 안에 global를 붙여주면 된다.
<style jsx global>
{`
a {
color: white;
}
`}
</style>
그러나 이 방법을 사용하게 되면 작동이 잘 되지 않는 걸 볼 수 있다.
코드가 다음과 같이 되어있는 경우
<index.js>
import NavBar from "../components/NavBar";
export default function Home() {
return (
<div>
<NavBar />
<h1 className="active">Hello </h1>
<style jsx global>
{`
a {
color: white;
}
`}
</style>
</div>
);
}
<NavBar.js>
import Link from "next/link";
import { useRouter } from "next/router";
export default function NavBar() {
const router = useRouter();
return (
<nav>
<Link href="/">
<a className={router.pathname === "/" ? "active" : ""}>HOME</a>
</Link>
<Link href="/about">
<a className={router.pathname === "/about" ? "active" : ""}>About</a>
</Link>
<style jsx>{`
nav {
background-color: tomato;
}
a {
text-decoration: none;
}
.active {
color: yellow;
}
`}</style>
</nav>
);
}
<about.js>
import NavBar from "../components/NavBar";
export default function about() {
return (
<div>
<NavBar />
<h1>About us</h1>
</div>
);
}
실제로 웹페이지에 접속해서 확인해보면 home에 위치했을 경우에는 자식 컴포넌트에도 잘 적용이 되지만,
About을 클릭해서 페이지 이동을 하게 되면 HOME에는 적용이 되지 않는 모습을 볼 수 있다.
그 이유는 About을 클릭하면 /about으로 이동하게 되고, about.js 컴포넌트를 렌더링하게 되는데 현재 about.js에는 css가 존재하지 않는다. 이걸 해결하기 위한 방안으로는 global styeld JSX를 페이지마다 복붙해주면 되긴하지만 그 방법은 귀찮다.
또한 모든 페이지에서 NavBar을 사용하기 위해선 매 페이지마다 NavBar컴포넌트를 붙여넣기 해줘야했다.
이런 귀찮은 것들을 해결하기 위해서 App Component를 사용한다.
주로 Header나 Footer등과 같이 고정된 컴포넌트들이 있고, 이러한 레이아웃을 정할 수 있도록 하는 것이 App Component라고 생각하면 될 듯 싶다.
App Component는 일종의 어떤 컴포넌트의 청사진이다. 이것을 사용자화하기 위해서는 무조건 _app.js라는 이름을 가진 파일을 생성해서 사용해야한다.
Next는 어떤 컴포넌트든간에 해당 컴포넌트를 렌더링하기 전에 _app.js 컴포넌트를 먼저 본 다음에 해당 컴포넌트를 렌더링한다.
page/_app.js 파일을 생성해준다.
그리고 파일안에는
export default function App({Component, pageProps})
으로 함수를 시작해준다. App은 하고 싶은대로 작성해도 상관없다. 그러나 안에 파라미터 두개 Component와 pageProps는 항상 무조건 동일하게 작성해줘야한다.
아까 말한 것처럼 Next는 어떤 컴포넌트를 가던지 _app.js파일을 거쳐서 간다. _app.js를 거친 후 가려고 하는 컴포넌트의 내용이 파라미터 Component안에 들어있다고 생각하면 된다. 그리고 이제 return문 안에 해당 컴포넌트와 그외에 추가하고 싶은 내용들을 작성한다면 페이지는 그것들을 렌더링하게 된다.
예를 들어서 내가 렌더링하려는 컴포넌트 A가 존재하고 _app.js안에 B, C, D 등 다른 것들을 작성한다면, 최종적으로는 A, B, C, D가 모두 있는 상태를 렌더링하게 된다.
다음과 같이 _app.js를 작성한다면
export default function App({ Component, pageProps }) {
return (
<div>
<Component {...pageProps} />
<span>hello</span>
</div>
);
}
span태그 안에 있는 hello는 어느 페이지에서나 항상 보이게 된다.
그렇기 때문에 글로벌 전역 스타일을 적용하고 싶다면 이 _app.js파일 안에 style을 작성해주면 global css로 사용할 수 있다.
아까 페이지마다 있었던 NavBar 컴포넌트도 _app.js에서 한번만 넣어주고, global Styled JSX도 적용해주는 _app.js 코드는 다음과 같다.
import NavBar from "../components/NavBar";
export default function App({ Component, pageProps }) {
return (
<>
<NavBar />
<Component {...pageProps} />
<style jsx global>
{`
a {
color: white;
}
`}
</style>
</>
);
}
또한 Next에서는 global css 파일을 import할 수 없다. 하지만 _app.js에서는 import가 가능하기 때문에 global.css파일을 하나 생성해서 import 시키는 방법도 있다.
'개발 공부 > Next JS' 카테고리의 다른 글
[노마드코더] NextJS 시작하기 #4 (0) | 2022.04.09 |
---|---|
[노마드코더] NextJS 시작하기 #3 (0) | 2022.04.08 |
[노마드코더] NextJS 시작하기 #1 (0) | 2022.03.22 |
[Next] NextJS의 getInitialProps, getStaticProps, getStaticPaths, getServerSideProps 함수 (0) | 2022.03.20 |
[WEB] Next.js + Typesctipt + StyledComponents 프로젝트 생성하기 (0) | 2022.03.15 |