front/next

next.js 설치 및 폴더 설정

jeong_ga 2024. 3. 6. 10:54

CSR, SSR차이 - next.js 설치 및 공사콕 웹앱 폴더 설정

1, next.js

리액트를 위해 만든 오픈소스 자바스크립트 웹 프레임워크로 리액트에선 없는 기능을 제공

  • 서버 사이드 렌더링 server-side rendering(SSR)
  • 정적 사이트 생성 static site generation(SSG)
  • 증분 정적 재생성 incremental static regeneration(ISR)

SSR

  • 로딩시간 단축 : 서버사이드 렌더링은 서버에서 자바스크립트를 로딩함으로 클라이언트 측에서는 자바스크립트를 로딩하는 시간이 줄어들게 됨
  • SEO : 검색엔진이 자바스크립트를 읽는 게 아닌 서버측에서 자바스크립트, html, css를 만들어 컨텐츠에 직접 업로드 & meta 태그를 자유롭게 추가함으로 SEO를 용이하게 할 수 있음

1, SSR와 CSR의 차이

<aside> 📖 SSR - next.js 브라우저가 html파일 → JS 파일 순으로 다운 받으며, JS를 다운로드 받는 동안 html 렌더링을 시작하기 때문에 웹페이지에 표시가 빠르게 된다. 하지만 JS가 다 받아진 상황이 아니라 제대로 동작하지 않을 수 있다. 페이지를 이동했을 때에도 같은 동작이 반복되기 때문에 렌더링은 빠르나 깜빡임이 생길 수 있다.

CSR - react url요청으로 웹문서가 가지고 있는 모든 정보를 한 번에 가지고 온다. 초기 화면 로드가 느리지만 사이트를 돌아다닐 때에는 사용성이 좋아진다. (예:페이스북) 보통 로드가 될 때 로딩중을 표시하는 화면이 표시되도록 한다. 링크를 이동할 때 JS를 이용하여 동적으로 화면을 바꾸기 때문에 html문서가 가지고 있는 정보가 적어SEO가 나쁨

</aside>

2, SPA (Single Page Application)

리액트는 CSR 방식을 채택한 것이며, Single Page Application의 구축을 가능하게 해줌.

초반에 표시되는 index.html 외 html문서는 없음.

index.html의 내용으로 JS를 이용해 재 렌더링 해주는 방식으로 페이지를 구성하며 표시해야 할 내용은 파일이 아닌 컴포넌트 형식으로 구성

3, Virtual DOM

DOM

  • ‘Document Object Model’의 약자로 주로 html 문서 내에 요소
  • html, css, javascript 로 만들었던 웹사이트에서는 querySelector 나 getElementbyID 같은 명령어로 직접 DOM 요소를 찾아 직접 조작
    • 직접 요소를 조작하는 방식은 페이지 내 상태가 변경될 때 페이지를 새로 로드하기 때문에 페이지 용량이 크면 클수록 느려지는 단점이 있음

Virtual DOM

  • CSR 방식으로 한번에 모든 정보를 받고 Virtual DOM 을 이용해 페이지 내에 변한 부분만을 감지해서 그 부분만 변경해주게 되면 훨씬 부담을 줄일 수 있다.
  • 유저 인터랙션이 일어나면 Virtual DOM에 의해 구성된 DOM 트리는 이전 페이지와 바뀐 부분들을 감지한다. 그래서 변화된 부분만 재 렌더링

2, 설치 & 설정

node.js는 설치가 되어있다고 가정하고 next.js 설치방법만 작성

npx create-next-app [프로젝트이름]
  • 처음엔 카멜케이스 방식의 프로젝트 이름을 사용하여 오류가 났다. (프로젝트 이름은 소문자 혹은 언더스네이크 방식으로 작성)

✔ Would you like to use TypeScript? … No / Yes

  • 타입스크립트를 사용할 것인지 물음 (Yes가 기본)

✔ Would you like to use ESLint? … No / Yes

  • ESLint를 사용할 것인지 물음 (Yes가 기본)

✔ Would you like to use Tailwind CSS? … No / Yes

  • Tailwind CSS를 사용할 것인지 물음 (No가 기본)

✔ Would you like to use src/ directory? … No / Yes

  • src/ 방식의 폴더 규칙을 사용할 것인지 물음 (No가 기본)

✔ Would you like to use App Router? (recommended) … No / Yes

  • App Router 방식을 사용할 것인지 물음 (Yes가 기본)
  • next.js 13버전부터 사용

✔ Would you like to customize the default import alias (@/*)? … No / Yes

  • 절대경로를 사용할 것인지 물음 (No가 기본)

 

공사콕 웹앱 폴더 정리

1, 레파지토리

X

2, url

next.js 13버전부턴 app router 방식을 사용한다. app 폴더 내부에 page.jsx(page.tsx) 로 작성된 파일을 url path로 인식하게 되므로 react의 react-router-dom처럼 별도 라이브러리를 사용하지 않고 router 이용이 가능하다.

page.tsx

// app/dashboard/page.tsx

export default function Layout({
  children, // will be a page or nested layout
}: {
  children: React.ReactNode;
}) {
  return <section>sec{children}</section>; 
	// 해당 layout 파일이 있는 폴더의 page는 sction 내부에 코드가 렌더링된다.
}

layout.tsx

  • 같은 폴더 내에 있는 layout 혹은 상위 폴더의 layout은 다른 page.tsx에서 함께 사용할 수 있다.
  • 공용으로 사용해야 하는 컴포넌트 혹은 meta tag 같은 경우 상위 layout 코드에 작성한다.
  • 최상위 routeLayout에는 html, body 태그를 작성해야 한다.
  • app에서 루트레이아웃을 삭제하고, 폴더 내부에 각각 따로 루트 레이아웃을 작성하여 사용할 수도 있음
// app/layout.tsx
import { Metadata } from "next";

export const metadata: Metadata = {
  title: "Next.js!!!!!!",
};
// app/page.tsx에 해당 title tag를 넣으면 router 이동 시 title이 사라지게 됨. 다른 페이지에서도 사용할 수 있게 layout.tsx에 작성

export default function RootLayout({
  children, 
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <nav>nav!</nav>
        {children}
      </body>
    </html>
  );
}

3, 기능별 폴더 정리

1, route 지정

<aside> 📌 next.js13 이후 버전에서는 app routing 방식을 사용하기 때문에 app 폴더 내부에 폴더를 생성 & page라는 이름으로 컴포넌트를 생성하면 url path로 이용이 가능하다.

  • react-router-dom을 따로 설치할 필요가 없다.

</aside>

  • app 폴더에 작성된 page.tsx의 url주소는 https::localhost3000/ 이 된다.
  • app>login>page.tsx의 url주소는 https::localhost3000/login
  • () 괄호를 이용하여 폴더를 생성한 경우 app 폴더 내부에 생성된 경우더라도 url로 인식하지 않는다.

home에 사용된 파일을 (home) 폴더에 작성하였다.

2, css

css는 css모듈을 사용하고 있다.

page.tsx와 동일한 위치에 {name}.module.css 파일을 생성하여 css 를 작성한다.

// nav/page.tsx

<header className={styles.navWrap}>
	<div className={styles.head}>
	</div>
</header>
// nav/nav.module.css

.navWrap {
  width: 100%;
  height: auto;
}
.navWrap a {
  width: 100%;
  height: auto;
}
.head {
  width: 100%;
  height: auto;
}

와 같은 방식으로 사용하면 된다.

3, component

레이아웃 혹은 반복 사용되는 구역의 경우 컴포넌트 폴더로 따로 분류하여 사용한다.

4, constans

프로젝트에서 사용하는 stiring 관리 폴더이다.

1, 서버 관리

// url.ts

let currentURL = "relase";

export default function urlPrefixCk() {
  if (currentURL === "dev") {
    return "<https://devawsback.gongsacok.com>";
  } else if (currentURL === "stage") {
    return "<https://stageawsback.gongsacok.com>";
  } else if (currentURL === "relase") {
    return "<https://releaseawsback.gongsacok.com>";
  }
}

2, endpoint 관리

// api.ts

import urlPrefixCk from "./url";
export const urlPrefix = urlPrefixCk();

// 로그인
export const urlLogin = urlPrefix + "/pub/login";

// 메인
export const urlLikeSerach = urlPrefix + "/pub/likeSearch";

5, hooks

사용성을 위해 useHook을 만들게 될 경우 /hooks 폴더에 파일을 작성한다.

현재는 사용자의 위치를 파악하는 useGeolocation 파일이 있다.

  • 파일 예시
  •  
import { useState, useEffect } from "react";

interface locationType {
  loaded: boolean;
  coordinates?: { lat: number; lng: number };
  error?: { code: number; message: string };
}

const useGeolocation = () => {
  const [location, setLocation] = useState<locationType>({
    loaded: false,
    coordinates: { lat: 0, lng: 0 },
  });

  // 성공에 대한 로직
  const onSuccess = (location: {
    coords: { latitude: number; longitude: number };
  }) => {
    setLocation({
      loaded: true,
      coordinates: {
        lat: location.coords.latitude,
        lng: location.coords.longitude,
      },
    });
  };

  // 에러에 대한 로직
  const onError = (error: { code: number; message: string }) => {
    setLocation({
      loaded: true,
      error,
    });
  };

  useEffect(() => {
    // navigator 객체 안에 geolocation이 없다면
    // 위치 정보가 없는 것.
    if (!("geolocation" in navigator)) {
      onError({
        code: 0,
        message: "Geolocation not supported",
      });
    }
    navigator.geolocation.getCurrentPosition(onSuccess, onError);
  }, []);

  return location;
};

export default useGeolocation;

6, image

프로젝트에서 사용하는 image파일은 /image 폴더에 저장

이미지는 next/image 로 관리

import Image from "next/image";
import profilePic from "@/image/logo.png";

export default function Head() {
  return <Image
              src={profilePic}
              width={50}
              height={50}
              alt="공사콕 로고 이미지"
              placeholder="blur"
            />
}

8, services

기능에 관련된 폴더 & 파일은 해당 폴더 내부에 작성한다.

현재는 fetch기능과 cookie 기능이 적용되어 있다.

// fetch

export const post = async (url: string, data: any) => {
  const handleAwait = await fetch(url, {
    method: "post",
    headers: {
      "Content-type": "application/json",
    },
    body: JSON.stringify(data),
  }).then((response) => response.json());
  return handleAwait;
};

// token

"use client";
import { useCookies } from "next-client-cookies";

export const setToken = (accessToken: string) => {
  const cookies = useCookies();
  cookies.set("TOKEN", accessToken);
};

export const getToken = () => {
  const cookies = useCookies();
  cookies.get("TOKEN");
};