석이의 개발일지
Next.js 기능 본문
전 게시물에 기능들을 나열해 봤는데 따로 만드는 게 나을 거 같아서 게시물을 써봅니다.
pages
- pages 폴더 안에 있는 파일명에 따라 route가 결정된다.
pages/about.js 생성 -> localhost:3000/about ✅ - 다만 예외사항으로 index.js의 경우에는 앱이 시작하는 파일이라고 보면 된다.
localhost:3000 그 자체다 뒤에 /index로 붙이면 안 된다.❌
routing
import Link from "next/link";
import { useRouter } from "next/router";
export default function NavBar() {
const router = useRouter();
console.log(router);
return (
<nav>
<Link
className="hello"
style={{ color: router.pathname === "/" ? "red" : "blue" }}
href="/"
>
Home
</Link>
<Link
href="/about"
style={{ color: router.pathname === "/about" ? "red" : "blue" }}
>
About
</Link>
</nav>
);
}
- Next.js 13 버전 이후로 태그 안에 태그가 들어가면 Unhandled
- Link 안에 a를 빼거나 Link 안에 legacyBehavior를 추가해야만 a를 사용할 수 있다.
- useRouter()라는 기능이 있는데 이건 react에 useLocation()이랑 똑같다
Built-In CSS Support (내장 CSS 지원)
- Next.js를 사용하면 JavaScript 파일에서 CSS 파일을 가져올 수 있다.
이것은 Next.js가 import 개념을 JavaScript 이상으로 확장하기 때문에 가능하다.
CSS-in-JS
- 격리된 범위 CSS에 대한 지원을 제공하기 위해 styled-jsx를 번들로 제공한다.
목표는 불행히도 서버 렌더링을 지원하지 않고 JS 전용인 Web Components와 유사한 "Shadow CSS"를 지원하는 것이다.
style-jsx를 사용한 컴포넌트는 다음과 같다.
<style jsx>{`
CSS 스타일..
`}</style>
- 사용하면서 느낀 점은 react에서 styled-components 비슷하다는 느낌을 받았다.
Adding Component-Level CSS
- Next.js는 [name]. module.css 파일 명명 규칙을 사용하여 CSS Module을 지원
Sass Support
- Next.js를 사용하면. scss 및. sass 확장자를 모두 사용하여 Sass를 가져올 수 있다.
Custom App
- Next.js 는 App 컴포넌트를 사용하여 page를 초기화한다.
이를 재정의하고 페이지 초기화를 제어할 수 있다.
- 페이지 변경 간에 레이아웃 유지
- 페이지 탐색 시 state 유지
- componentDidCatch를 사용한 Custom 에러 처리
- 페이지에 추가 데이터 삽입
- Global CSS 추가
기본 App을 재정의하려면 아래와 같이./pages/_app.js 파일을 만든다.
export default function MyApp({ Component, pageProps }) {
return < Component {...pageProps} />
- export default function 이름은 크게 상관없지만 custom을 할 거면 _app.js 파일명은 무조건이다.(규칙)
Custom App (with TypeScript)
_app.ts 가 아닌 _app.tsx파일을 만들고 아래와 같이 만든다
import type { AppProps } from 'next/app'
export default function MyApp({ Component, pageProps }: AppProps){
return < Component {...pageProps} />
}
+ 추가적으로 파일명. module.css 파일 형태를 제외한 모든 나머지 css 파일들은 _app.js에서만 import 해와서 사용해야 한다. (글로버 css 간의 충돌을 피하기 위해서이다.)
Layouts
import NavBar from "./NavBar";
export default function Layout({ children }) {
return (
<>
<NavBar />
<div>{children}</div>
</>
);
}
- React 모델을 사용하면 페이지를 일련의 컴포넌트로 분해할 수 있다.
이러한 컴포넌트 중 많은 부분이 페이지 간에 재사용되는 경우가 많다.
예를 들어 모든 페이지에 동일한 navigation과 footer가 있을 수 있다.
Head (next/head)
// key를 지정해주지 않으면 meta og:title가 중복해서 2번 랜더링됩니다.
// (title은 지정하지 않아도 2번 랜더링 되지 않음)
< Head>
< title>My page title< /title>
< meta property="og:title" content="My page title" key="title" />
< /Head>
< Head>
< meta property="og:title" content="My new title" key="title" />
< /Head>
- 페이지 head에 엘리먼트를 추가하기 위한 내장 컴포넌트를 노출한다.
head에 태그가 중복되지 않도록 하려면 위 예제와 같이 태그가 한 번만 렌더링 되도록 하는 key 속성을 사용할 수 있다.
이 경우 두 번째 meta property="og:title"만 렌더링 된다. 중복 키 속성이 있는 메타 태그는 자동으로 처리된다.
next.config.js
/** @type {import('next').NextConfig} */
const API_KEY = "*********************";
const nextConfig = {
reactStrictMode: true,
async redirects() {
return [
{
source: "/old-blog/:path*",
destination: "/new-sexy-blog/:path*",
permanent: false,
},
];
},
async rewrites() {
return [
{
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}`,
},
];
},
};
module.exports = nextConfig;
- Next.js에서 커스텀 설정을 하기 위해서는 프로젝트 디렉터리의 루트(package.json 옆)에 next.config.js 또는 next.config.mjs 파일을 만들 수 있다.
next.config.js는 JSON 파일이 아닌 일반 Node.js 모듈이다.
Next.js 서버 및 빌드 단계에서 사용되며 브라우저 빌드에는 포함되지 않는다.
redirects (URL 변경됨)
- redirect을 사용하면 들어오는 request 경로를 다른 destination 경로로 redirect 할 수 있다.
redirect을 사용하려면 next.config.js에서 redirects 키를 사용할 수 있다. - redirects은 source, destination 및 permanent 속성이 있는 객체를 포함하는 배열을 반환하는 비동기 함수이다.
- source : 들어오는 request 경로 패턴 (request 경로)
- destination : 라우팅하려는 경로 (redirect 할 경로)
- permanent : true인 경우 클라이언트와 search 엔진에 redirect를 영구적으로 cache 하도록 지시하는 308 status code를 사용하고, false인 경우 일시적이고 cache 되지 않는 307 status code를 사용한다.
rewrites (URL 변경되지 않음)
- rewrites를 사용하면 들어오는 request 경로를 다른 destination 경로에 매핑할 수 있다.
rewrites은 URL 프록시 역할을 하고 destination 경로를 mask 하여 사용자가 사이트에서 위치를 변경하지 않는 것처럼 보이게 한다.
반대로 redirects은 새 페이지로 reroute 되고 URL 변경 사항을 표시한다.
문제점 1. 주소에 한글이 들어가는 경우 Error
before
`https://openapi.gg.go.kr/RegionMnyFacltStus?KEY=${API_KEY}&Type=json&pIndex=1&pSize=20&SIGUN_NM=${SIGUN_NM}`
(SIGUN_NM : 지역 시/군 한글입력)
after
encodeURI(
`https://openapi.gg.go.kr/RegionMnyFacltStus?KEY=${API_KEY}&Type=json&pIndex=1&pSize=20&SIGUN_NM=${SIGUN_NM}`
)
- 한글이 들어가는 주소는 encodeURI() 전체를 감싸서 변경해 주니 error 해결
문제점 2. 주소 & 인식 Error
error 예시
// next.config.js
{
source: "/api/:params",
destination: `https://some.api/items?key=${API_KEY}&:params`
}
- destination에서 "&" 부분을 그대로 인식하지 않고 "&__ESC_COLON_" 이라는 문자열로 바뀌어버린다.
해결
`https://some.api/items?key=${API_KEY}${encodeURIComponent("&")}:params`
- :params로 넘어온 문자열이 &와 문제없이 결합한다.(해결)
getServerSideProps
- 페이지에서 서버 측 렌더링 함수인 getServerSideProps함수를 export 하는 경우 Next.js는 getServerSideProps에서 반환된 데이터를 사용하여 각 request에서 이 페이지를 pre-render 한다.
- getServerSideProps는 서버 측에서만 실행되며 브라우저에서는 실행되지 않는다.
예시
export default function Home({ results }) {
...
// 데이터 랜더링
}
// 매 request마다 실행된다.
export async function getServerSideProps() {
const { results } = await (
await fetch(`http://localhost:3000/api/movies`)
).json();
// props를 통해 page에 results 전달
return {
props: {
results,
},
};
}
fetch 할 때 오류 뜨는경우 https를 http로 바꿔주시면 된다.
- request 시 데이터를 fetch하고 결과를 pre-render 하는 방법
getServerSideProps (타입스크립트 함께 사용하기)
import { GetServerSideProps } from 'next'
type Data = { ... }
export const getServerSideProps: GetServerSideProps<{ data: Data }> = async (context) => {
const res = await fetch('https://.../data')
const data: Data = await res.json()
return {
props: {
data,
},
}
}
궁금증1. 언제 getServerSideProps를 사용해야 할까?
- request time에 반드시 데이터를 fetch해와야 하는 페이즈를 pre-render 해야 하는 경우에만 getServerSideProps를 사용해야 한다.
데이터를 pre-render 할 필요가 없다면 client side에서 데이터를 가져오는 것을 고려해야 한다.
클라이언트 측에서 데이터 가져오는 과정 (Fetching data on the client side)
페이지에 자주 업데이트되는 데이터가 포함되어 있고 데이터를 pre-render 할 필요가 없는 경우 클라이언트 측에서 데이터를 가져올 수 있다.
- 먼저 데이터가 없는 페이지를 즉시 표시한다.
- 페이지의 일부는 Static Generation을 사용해 pre-render할 수 있다.
- 없는 데이터를 위해 loading 상태를 표시할 수 있다.
- 그런 다음 클라이언트 측에서 데이터를 가져와 준비가 되면 표시한다.
이 접근 방식은 예를 들어 사용자 대시보드 페이지에 적합하다.
왜냐하면 대시보드는 사용자별 비공개 페이지이기 때문에 SEO와는 관련이 없으며 페이지를 미리 렌더링 할 필요가 없다.
또한 데이터는 자주 업데이트되므로 요청 시 데이터를 가져와야 한다.
궁금증 2. getServerSideProps가 오류 페이지를 렌더링 할까?
- getServerSideProps 내부에서 오류가 발생하면 pages/500.js 파일이 표시된다.
500 page(서버 렌더링 오류 페이지)는 사용자가 커스텀 마이징 할 수 있다.
개발 중에는 이 파일이 사용되지 않고 대신 개발 오버레이가 표시된다.
Dynamic Routes
- Next.js에서는 page에 대괄호([id])를 추가하여 Dynamic Route를 생성할 수 있다.
Catch all routes
- 대괄호 안에 세 개의 점(...)을 추가하여 모든 경로를 포착하도록 Dynamic Routes를 확장할 수 있다.
- pages/movies/[... params]. js는 /movies/1/2, /movies/1/a/b 등과도 일치하다.
일치하는 매개변수는 페이지에 쿼리 매개변수로 전송되며 항상 배열이므로 /movies/a 경로에는 다음 쿼리 개체가 있다.
- 홈페이지를 거치지 않고, 위와 같은 페이지로 이동하게 되면, 저절로 Next.js가 만든 서버에, params 객체가 만들어지고, 그 안의 params변수에 두 개의 파라미터 값이 배열형태로 저장된다.
값을 불러오는 방법은 두 가지
- router를 이용해서 받아오는 방법 : 다만, router를 생성하려면 자바스크립트를 통해 라우터를 형성하는 시간이 필요하다.
그래서 만약 router를 생성해서, router를 통해 params 값을 받아오려면
(const [title, id] = router.query.params), 처음에는 에러가 난다.
에러가 나는 이유는, router가 없으니, router.query.params 값도 얻을 수 없는데,
const [title, id] = router.query.params; 식으로 title이나 id 변수에, 없는 값을 할당하려 하니 에러가 발생한다.
그래서 에러를 방지하기 위해 빈 배열을 이용한 것이다.
const [title, id] = router.query.params || [];
조금 시간이 지나 router가 생성되면, 서버에서 간직하고 있는 params 객체 값을 router.query.params를 통해 얻어올 수 있다. - router를 이용하지 않고, 디렉트로 server로부터 받아오는 방법 :
export function getServerSideProps({params:{params}}) {
return {props : {params}};
}
이것은 {params: {params}} 객체를 서버로부터 받아오고,
지금 페이지(현재의 컴포넌트 함수)에게 props로 {params} 객체를 리턴하는 것
export default function Detail( {params} ){
const [title, id] = params || [];;
return (
<div>
<h4>{title}</h4>
</div>
);
}
params값을 빼내서 사용할 수 있게 된다.
- next.js 서버에 이렇게 params 객체를 갖고 있다.
그래서 getServerSideProps 함수를 이용해서, 서버로 부터 그 객체 모양 그대로 받아오는 것이다.
- 리턴은 {params}를 props로 해서 리턴한다.
그러면 해당 url 주소가 되면 활성화되는 함수인 Detail 함수가, {params} 객체를 인자로 받아들여서, 그 안의 내용을 원하는 변수에 넣어서 사용할 수 있다.
궁금증 3. 홈페이지를 거쳐서 해당 URL로 왔을 경우
만약 최초에 해당 url로 접속하게 되면 서버가 생성하는 params 내용은
이럭 식으로 params: ["Spider...", "634..."] 형태로 title, id라는 변수가 없다.
그런데 홈페이지에서 라우터를 만들고 라우터를 통해서 params 내용을 수정할 수도 있다.
이렇게 하면 params는 params:{title: "Spider...", id: "634..."} 식으로 객체 형태로 바뀌게 된다.
주의해야 할 점은 배열형태가 아닌 객체형태, 그리고 title, id 변수가 추가된다는 점.
그래서, 홈페이지에서 위와 같이 router를 통해 params 모양을 객체로 바꾼 상태에서, 홈페이지에서 다른 url(예를 들어, movies/###/***)로 이동하게 되면, 그 url과 관련된 컴포넌트에서, router나 서버를 통해서, params를 얻게 되면, 변형된 params를 얻게 되니, 당연히 id와 title 변수가 들어간 객체 형태의 params를 얻게 된다.
그래서 ### 값을 얻으려면, router.query.title로 얻어야 되고, *** 값을 얻으려면 router.query.id로 얻어야 된다.
이것과 비디오 해서, 홈페이지를 거치지 않아서 params가 수정되지 않은 경우에는 params는 [###, ***] 배열 안에 title, id라는 변수 없이 저장되어 있기 때문에, 그 값을 얻으려면 const [title, id] = params; 식으로 얻어내야 된다. (구조분해할당)
router.push(url, as, option)
- 클라이언트 측 전환을 처리한다.
이 방법은 next/link 가 충분하지 않은 경우에 유용하다. (React useNavigate() 유사하다)
url : UrlObject | String : 탐색할 URL
as : UrlObject | String : 브라우저 URL 표시줄에 표시될 경로에 대한 선택적 데코레이터이다.
// router
const onClick = (id, title) => {
router.push(
{
pathname: `/movies/${id}`,
query: {
title,
},
},
`/movies/${id}` // as
);
// router.push(`/movies/${title}/${id}`);
};
// Link
<Link
href={{
pathname: `/movies/${movie.id}`,
query: {
title: movie.original_title,
},
}}
as={`movies/${movie.id}`}
// href={`/movies/${movie.original_title}/${movie.id}`}
>
{movie.original_title}
</Link>
https://nextjs.org/docs/api-reference/next/router#routerpush
next/router | Next.js
Learn more about the API of the Next.js Router, and access the router instance in your page with the useRouter hook.
nextjs.org
기능은 계속 추가할 예정
'React > Next' 카테고리의 다른 글
Next.js Quiz (2) | 2023.02.24 |
---|---|
Next.js란? (8) | 2023.02.22 |