석이의 개발일지

Next.js 기능 본문

React/Next

Next.js 기능

믹석이 2023. 2. 23. 19:34
728x90

전 게시물에 기능들을 나열해 봤는데 따로 만드는 게 나을 거 같아서 게시물을 써봅니다.

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를 초기화한다.
    이를 재정의하고 페이지 초기화를 제어할 수 있다.
  1. 페이지 변경 간에 레이아웃 유지
  2. 페이지 탐색 시 state 유지
  3. componentDidCatch를 사용한 Custom 에러 처리
  4. 페이지에 추가 데이터 삽입
  5. 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 할 필요가 없는 경우 클라이언트 측에서 데이터를 가져올 수 있다.

  1. 먼저 데이터가 없는 페이지를 즉시 표시한다.
  2. 페이지의 일부는 Static Generation을 사용해 pre-render할 수 있다.
  3. 없는 데이터를 위해 loading 상태를 표시할 수 있다.
  4. 그런 다음 클라이언트 측에서 데이터를 가져와 준비가 되면 표시한다.

이 접근 방식은 예를 들어 사용자 대시보드 페이지에 적합하다.

왜냐하면 대시보드는 사용자별 비공개 페이지이기 때문에 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변수에 두 개의 파라미터 값이 배열형태로 저장된다.

값을 불러오는 방법은 두 가지

  1. 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를 통해 얻어올 수 있다.
  2. 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

기능은 계속 추가할 예정

LIST

'React > Next' 카테고리의 다른 글

Next.js Quiz  (2) 2023.02.24
Next.js란?  (8) 2023.02.22
Comments