[NextJS] 기초 다지기

혜린·2023년 1월 31일
2

NextJS

목록 보기
1/1
post-thumbnail

들어가며


🌱 NextJS의 기초를 다지고자 노마드코더의 NextJS입문 강의를 완강했다. 강의를 따라가며 공부한 내용을 기록해두고자 한다!



0. Creating a Project


TypeScript로 프로젝트를 시작하고자 한다면, --typescript를 추가해주면 된다.

npx create-next-app@latest
npx create-next-app@latest --typescript



1. Library vs Framework


(1) Library

👩🏻‍💻 Library는 개발자로서 내가 사용하는 것

  • 내가 원하는대로 코드를 작성할 수도 있고, library를 사용하고 싶을 때 사용할 수도 있다.
  • 대표적인 예는 React이다. React는 router를 만들든 component를 만들든 내가 코드를 작성하기 나름이고, 폴더명을 짓는 것에 있어서도 자유롭다. 자유도가 높다는 것을 알 수 있다!

(2) Framework

👩🏻‍💻 Framework는 나의 코드를 불러오는 것

  • 코드를 적절한 위치에 잘 적기만 하면 Framework가 내 코드를 불러와서 모든 것을 동작하게 한다.
  • 대표적인 예는 NextJS이다. Router 설정을 따로 하지 않아도 NextJS의 index.js에서 작성한 코드가 홈에 뜨는 것을 쉽게 확인할 수 있다.



2. Pages


💁🏻‍♀️ NextJS에서 페이지를 생성하려면? pages 폴더만 보면 된다!

  • NextJS는 pages에 생성된 파일의 이름을 가져다가 URL의 이름으로 사용한다. (따라서 컴포넌트명은 중요하지 않다!)
  • export default 컴포넌트이름 과 같이 default로 export를 꼭 해주어야한다는 것만 잘 지키자!
  • 앱의 홈은 기본적으로 pages 폴더에 위치한 index.js가 나오게 되어 있다.



3. Static Pre Rendering


✨ NextJS의 가장 좋은 기능 중 하나는, 앱에 있는 페이지들이 미리 렌더링된다는 것이다.


(1) React (CSR)

CSR은 나의 브라우저가 UI를 만드는 모든 것을 한다는 것을 의미한다!

  • 브라우저는 프론트 서버로부터 JavaScript를 전달받아 웹페이지 상의 모든 UI를 만들어낸다.
  • create-react-app으로 React 프로젝트를 시작할 때를 생각해보자. index.html파일의 body태그에는 <div id="root"></div>밖에 없는 것을 볼 수 있다. 사실상 비어있는 div태그이며, 브라우저가 프론트 서버로부터 프론트 관련 소스(JavaScript파일 등)를 전달받아 UI가 그려진다.


(2) NextJS (SSR)

NextJS는 React.js를 백엔드에서 동작시켜서 페이지를 미리 만든다!

  • NextJS는 초기 컴포넌트가 렌더링 된 HTML 파일을 먼저 받아 화면에 띄운다.
  • 그러면 유저는 JavaScript 와 React.js가 로딩되지 않았더라도 콘텐츠를 먼저 볼 수 있게 된다.
  • 그리고 React.js가 로딩되면, 이미 화면에 그려진 것들과 연결이 되어서 일반적인 React.js 앱이 되는 것이다.



4. Routing


✨ NextJS에 앱 내에서 페이지를 네비게이트할 때 사용해야만 하는
Link 컴포넌트가 존재한다. (따라서 a태그를 사용하면 경고표시가 뜬다!)

Link태그 사용하지 않으면?
브라우저가 다른 페이지로 보내기 위해 전체 페이지를 새로고침하며,
이는 속도 저하를 야기한다.

import Link from "next/link";
    
export default function NavBar() {
  return (
    <nav>
      <Link href="/">Home</Link>
      <Link href="/about">About</Link>
    </nav>
  );
}



5. CSS Modules


(1) 사용법

  • CSS Modules을 사용해 클래스 이름을 추가할 때, 클래스 이름을 텍스트로서 적지 않는다. 자바스크립트 오브젝트에서의 프로퍼티 형식으로 적는다.
import styles from "./NavBar.module.css";

export default function NavBar() {
      return (
        <nav className={styles.nav}>
          // 생략
        </nav>
      );
}

(2) 장점

  • 클래스이름이 자동적으로 생성됨에 따라 충돌이 일어나지 않는다.
  • 이는 다른 컴포넌트에서도 같은 클래스 이름을 사용할 수 있다는 것을 의미한다.



6. Styles JSX


<style>{`
	nav {
		background-color: tomato;
	}
	a {
		text-decoration: none;
	}
	.active {
		color: ${props.color};
	}
`}</style>



7. Custom App


(1) page 초기화의 효과

NextJS는 App 컴포넌트를 사용하여 page를 초기화한다. 이는 다음과 같은 효과가 있다.

  1. 페이지 변경 간에 레이아웃 유지
  2. 페이지 탐색 시 state 유지
  3. componentDidCatch를 사용한 Custom 에러 처리
  4. 페이지에 추가 데이터 삽입
  5. Global CSS 추가

(2) App 재정의하는 법

  • 기본 App을 재정의하려면 ./pages/_app.js 파일을 만든다.
  • 그러면 NextJS는 index.js를 렌더링하기 전에 _app.js을 보고 내용물을 렌더링한다. 그 뒤, index.js의 내용물을 렌더링한다.
export default function MyApp({ Component, pageProps }) {
  return (
    <>
      <NavBar />
      <Component {...pageProps} />
      <style jsx global>{`
        a {
          color: white;
        }
      `}</style>
    </>
  );
}



8. Patterns


  • custom app component를 사용할 때 Layout 패턴을 사용한다.
  • 아주 큰 리액트 App 컴포넌트를 사용하기 보다는, Layout component를 만들어 사용해주는 것이다.
  • children은 React가 제공하는 prop으로, 하나의 component를 또 다른 component 안에 넣을 때 사용할 수 있다.

(1) 예시

Layout 컴포넌트를 만들어 App 컴포넌트에 적용시켜준다.

// Layout 컴포넌트
import NavBar from "./NavBar";

export default function Layout({ children }) {
  return (
    <>
      <NavBar />
      <div>{children}</div>
    </>
  );
}
// _app 컴포넌트
import Layout from "components/Layout";

export default function MyApp({ Component, pageProps }) {
  return (
    <Layout>
      <Component {...pageProps} />
    </Layout>
  );
}

(2) 예시

NextJS에서 제공하는 Head 컴포넌트를 사용해
페이지를 이동할 때마다 해당 title이 나타나게 만들어준다.
다음 이미지는 About 페이지로 이동했을 때의 모습이다.

// Seo.js
import Head from "next/head";

export default function Seo({ title }) {
  return (
    <Head>
      <title>{title} | Next Movies</title>
    </Head>
  );
}
// About.js
import Seo from "components/Seo";

export default function about() {
  return (
    <div>
      <Seo title="Home" />
      <h1>About</h1>
    </div>
  );
}



9. Redirect and Rewrite


(1) Redirect

  • redirect를 이용해서 한 페이지에서 다른 페이지로 이동하게 할 수도 있고, 아예 다른 URL의 웹사이트로 이동하게 할 수도 있다.
  • /old-blog/포스트숫자를 url에 입력하면, /new-sexy-blog/포스트숫자로 이동하는 것을 확인할 수 있다.
  • :path* 와 같이 뒤에 별표를 붙여주면 /old-blog/1212/comments/122 와 같이 뒤에 오는 모든 경로를 다 잡아낸다.
module.exports = {
  reactStrictMode: true,
  async redirects() {
    return [
      {
        source: "/old-blog/:path*",
        destination: "/new-sexy-blog/:path*",
        permanent: false,
      },
    ];
  },
};

(2) Rewrite

  • redirects는 old-blog로 접속할 때, 유저가 url이 바뀌는 것을 볼 수 있다. (new-sexy-blog로!)
  • rewrites는 유저를 redirect시키기는 하지만, url은 변하지 않는다!
  • 설정한 source를 통해 destination에 접근할 수 있다! (ex)fetch("/api/movies")
const API_KEY = "0123456789";

module.exports = {
  reactStrictMode: true,
  async redirects() {}, // 생략
  async rewrites() {
    return [
      {
        source: "/api/movies",
        destination: `https://api.themoviedb.org/3/movie/popular?api_key=${API_KEY}`,
      },
    ];
  },
};

(3) API key 숨기기

  • .env 파일 생성하고 가져다가 쓰면 된다.
  • gitignore 됐는지 확인할 것!
// .env 파일
API_KEY=0123456789
// next.config.js
const API_KEY = process.env.API_KEY;



10. Server Side Rendering


(1) getServerSideProps 함수

💥 서버에서만 실행되는 함수임

  • getServerSideProps 함수는 오직 백엔드(서버)에서만 실행된다.
  • 따라서, getServerSideProps 함수에 API key를 써주면 client한테 보여지지 않는다.

🎁 props란 key를 갖는 객체를 return함

  • getServerSideProps는 props라는 key를 갖는 object를 return한다.
  • props라는 key에는 원하는 데이터를 넣을 수 있다.
  • 이로써 원하는 데이터를 props로 page에게 전달 할 수 있다.
// index.js
export default function Home({ results }) {
  // 생략
}
export async function getServerSideProps() {
  const { results } = awiat(await fetch("/api/movies")).json();
  return {
    props: {
      results,
    },
  };
}

(2) SSR vs. CSR

  • Server Side Rendering으로 렌더링되는 상태에선 API가 호출되기 전까지
    아무것도 화면에 보이지 않을 것이다.
  • 데이터가 유효할 때 화면을 보여주는 것(SSR)이 좋은 지,
    loading 화면을 보여준 뒤 데이터를 받는 것(CSR)이 좋은지는 나의 선택이다.
  • SSR 방식은 해당 페이지의 데이터가 들어오기 전까진 아무것도 볼 수 없다가 해당 페이지의 데이터만 들어오면 전체를 다 볼 수 있다. (다른 페이지를 갈 때도 이 과정이 필요하다.)
  • CSR 방식은 모든 JS파일들이 들어와야 (’Loading…’) 보여지는데, 그 대신 다른 페이지를 갈 때는 이미 JS 파일들을 받았으니 SSR 방식보다는 빠르게 화면을 볼 수 있다.



11. Dynamic Routes


URL에 변수를 넣는 방법

  • pages폴더에 movies 폴더 생성해준 뒤 [id].js파일 생성
  • 이름 짓는 것은 자유다. 대괄호만 잘 작성해주기!



12. Detail


(1) Link로 navigating

<Link href={`/movies/${movie.id}`}>{movie.original_title}</Link>

(2) 이벤트 발생 시 navigating

// index.js
export default function Home({ results }) {
	const router = useRouter();
	const onClick = (id) => {
	    router.push(`/movies/${id}`);
	};
	
	return (
	{results?.map((movie) => (
	   <div onClick={() => onClick(movie.id)} className="movie" key={movie.id}>
	       {/* 생략 */}
	   </div>
	))
	)
}

(3) URL에서 URL로 state 넘기기

  • 아래와 같이 router를 설정하면, 영화 상세보기 시에 url이 다음과 같이 나오는 것을 볼 수 있다.
    http://localhost:3000/movies/315162?id=315162&title=potatos
  • router의 2번째 속성인 as는 브라우저의 URL을 마스킹한다. , 뒤에 브라우저에 보일 URL을 작성하면 된다.
  • router.query.title은 유저가 홈→상세로 넘어올 때만 존재한다.
// index.js Home컴포넌트
const onClick = (id, title) => {
  router.push(
    {
      pathname: `/movies/${id}`,
      query: {
          title: title,
      },
    },
    `/movies/${id}`
  );
};

// [id].js
export default function Detail() {
      const router = useRouter();
      console.log(router);
      return (
        <div>
          <h4>{router.query.title || "Loading..."}</h4>
        </div>
      );
}



13. Catch All


  • catch-all URL은 뭐든 캐치해내는 URL이다.
  • router.query.params || []와 같은 처리를 해주는 이유
    • 홈페이지를 거쳐서 가는것이 아니라 바로 상세페이지로 가면,
      서버는 영화에 대한 정보를 모르기 때문에 error 발생
// index.js
export default function Home({ results }) {
  const router = useRouter();
  const onClick = (id, title) => {
    router.push(`/movies/${title}/${id}`);
  };
  return (
		<Link href={`/moives/${movie.original_title}/${movie.id}`}>
       {movie.original_title}
    </Link>
	)
}
// [...params].js
export default function Detail() {
  const router = useRouter();
  const [title, id] = router.query.params || [];

  return (
    <div>
      <h4>{title}</h4>
    </div>
  );
}
profile
FE Developer

2개의 댓글

comment-user-thumbnail
2023년 2월 12일

많은 도움 되었습니다.

1개의 답글