Next.js 개발 요청사항

1. Routing 정책 - App Router를 쓰는지 그렇다면 use client를 써야하는 상황 

- App Router vs. Page Router

→ App Router 방식을 사용합니다.
공시문서: https://nextjs.org/docs#app-router-vs-pages-router 
App Router에서는 streaming과 같은 최신 React 기능을 사용할 수 있는 이점이 있습니다.
 
Next.js 13.3까지 Page Router 방식을 사용했고 App Router는 베타 단계였고,
Next.js 13.4부터 App Router가 정식 버전으로 채택되었습니다.
App Router의 가장 큰 변화는 RSC(React Server Component)를 default로 쓰고 있다는 점입니다.
Client component란 server에서 렌더링되고 client에서 hydrate되고, Server component란 서버에서 렌더링을 보장하는 컴포넌트로 hydrate되지 않습니다 → 퍼포먼스(JS 번들 사이즈 감소)와 유연성이 더 나아졌다는 이점이 있고, 구현하기 조금 더 복잡해졌다는 단점이 있긴 합니다.
Page router는 folder-base와 file-base routing을 했던 반면, App router는 folder-base routing으로 각각의 해당 폴더에 layout.tsx을 정의할 수 있어 라우트 별로 독립적 layout (sidebar등)을 쉽게 사용할 수 있는 이점이 있습니다. 즉, 부모와 자식에 layout.tsx가 nested 될 수 있음. (page router의 _app.tsx와 _document.tsx가 layout.tsx로 합쳐져서 더 직관적이게 바뀌었다.)
 
또한 Page router에서는 server side에서 data fetching을 할 때 반드시 Next.js에서 지원해주는 getStaticProps() (SSG)와 getServerSideProps() (SSR)을 사용하고 같은 component에서 client로 props 형태로 넘겨주어야해서 사용적인 면에서 제약이 많았다. 그러나 App Router로 오면서 native Fetch API를 사용할 수 있어 더 유연하고 편해졌습니다.
SEO 최적화도 Page router에서는 getStaticProps()를 쓰고 <Head /> component를 넣어야해서 사용이 까다로웠지만, App Router에서는 export const metadata로 간단히 할 수 있습니다. (→ Next.js가 자동으로 빌드타임이나 런타임에 <Head />에 넣어준다.)
Next.js 14에서는 Page Router도 지원을 하고 있지만, 어떤 버전에서부터 지원을 중단(deprecated)할지 모르고, 공식 문서에서도 새로운 프로젝트는 App Router를 권장하고 있습니다.
 

- 'use client'를 써야하는 상황

→ Client component를 언제 써야하는가와 동일한 뜻으로, 한 가지만 생각하면 됩니다 → User Interactivity가 있는가?
있다면 'use client'를 사용합니다.
공식문서 : https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#when-to-use-server-and-client-components 
1. onClick 이벤트가 있는가?
2. Input 필드에 정보를 입력하는 부분이 있는가?
3. 그 외 이벤트 trigger가 있는가?
4. React hook을 사용하는가?
그럴 때는 client component를 사용합니다.
 

2. 상태관리툴 사용 여부 - React Query로 대신 할 수 있는지

→ Zustand와 React-Query 둘 다 상태 관리 툴로 쓰는 것을 추천합니다.
    용어 정리:
     - client state : input form에서 사용자가 입력하는 값처럼 client가 소유하고 제어하는 데이터
     - server state : client가 서버로부터 받아오거나, client 혹은 server에서 API 호출을 통해 받아오는 모든 데이터. 이로 인해 비동기적 상태를 가지고, client에서 가져온 데이터지만 client가 제어하고 관리할 수 없고 더 이상 유효하지 않은 데이터일 수 있어서 server state라고 불린다.
    즉, client state management는 Zustand로, server state management는 React-Query로 관리합니다.
    Server state를 react-query로 관리 시 Redux-Thunk와 Redux-Saga 조합보다도 코드가 훨씬 깔끔해지는 이점이 있습니다.
 
참고:
uni-directional flux 패턴의 상태관리: Redux, Zustand
bi-directional 상태관리: MobX
atomic model: Recoil, Jotai
 

3. API 호출 - React Query 사용하는것으로 아는데 어떤 상황에서 사용하는지, 캐싱 정책, 옵

→ 카카오 및 수많은 기업들에서 API 통신을 위해서 React Query를 사용하고 있음.
우리 X2BEE 또한 규격화된 방식으로 간단하고 직관적으로 API를 사용하기 위해서 선택함.

- 간단하게 Client Component에서 api호출시 useEffect + Promise를 사용하여 호출해야됨.
그러나 React Query사용시 다음과 같이 간단하게 사용 및 공통화가 가능함.
(해당 코드의 경우 ClientRestApi 안에서 React Query를 사용하고 있음)

'use client';

import { COMMON } from '../constants/x2beeConstants';
import ClientRestApi from '@/plugins/clientRestApi';

const Home = () => {

  const response = ClientRestApi.getInstance().get(
    COMMON.API_URL + '/api/display/v1/shop/1?dispMediaCd=20');

  console.log(response);

  return (
    <div>
      <h1>Home</h1>
    </div>
  );
};

export default Home;

- 캐싱 정책의 경우 내부적으로 따로 사용하지는 않음. api 호출시마다 새로운 데이터를 조회하는게 맞다고 생각하며, 또한 클라이언트단에서 너무 많은 캐싱을 남발할 경우 메모리를 많이 사용하기 때문에 브라우저에 부담을 줄수도 있다고 생각하기 때문.
또한 캐싱이 필요한 데이터의 경우 스프링(서버)에서 이미 ehcache등을 활용하여 데이터를 캐싱하고 있기 때문임.

그러나 각각 개발시에 React Query를 활용하여 캐싱 기능을 사용하고 싶다면 제한하지는 않음.

const { isPending, isError, isFetching, status, data, error } = useQuery({ 
	queryKey: ['test1'], // queryKey
    queryFn: testFetch, 
    gcTime: 10000, // 10초로 설정, 기본값은 5분임 (비활성화된 쿼리가 캐시에서 삭제될 때까지의 시간으로 garbage collected 되는 시간을 말함. 항상 staleTime 시간보다 길어야 캐싱이 유지됨)
    staleTime: 5000 // 5초로 설정, 기본값은 3초임 (stale 되는 시간, staleTime 값이 클수록, Query는 fresh 상태로 오래 유지되어 있기에 새로운 데이터를 업데이트하는 주기가 길어짐. 즉 캐싱 유지 되는 시간을 의미함)
});

다음과 같이 설정하면 캐시타임이 5초로 설정되며, test1이라는 이름으로 캐시가 설정됨. 그리고 5초 후에는 캐시가 사라져서 새롭게 데이터를 조회하며, 마지막 조회 후 10초 뒤에는 데이터가 완전히 삭제됨.
 

4. 레이아웃 정책 - 기본룰에 대한 가이드

→ 1. Root layout에 들어가는 항목, 및 2. Route Groups를 통해 group별로 layout을 다르게 가져가는 폴더 구조 방식이 있습니다.
1. Root layout에 들어가는 항목은
(1) metadata 및 favicon 설정  01. Setup글에서 확인 https://x2bee.tistory.com/213 
(2) font 설정 03. 퍼블가이드에서 확인 https://x2bee.tistory.com/214
(3) globals.css를 import 하는 부분
(4) header, footer component import 부분
(5) children을 props로 넣는 부분
(6) Context Provider 혹은 theme을 감싸는 부분이 있습니다.
예시: 

import type { Metadata } from "next";
import { Inter, Space_Grotesk } from "next/font/google";
import "@/app/globals.css";

const inter = Inter({
  subsets: ["latin"],
  weight: ["100", "200", "300", "400", "500", "600", "700", "800", "900"],
  variable: "--font-inter",
});
const spaceGrotesk = Space_Grotesk({
  subsets: ["latin"],
  weight: ["300", "400", "500", "600", "700"],
  variable: "--font-inter",
});

export const metadata: Metadata = {
  title: {
    default: "NEXT MALL",
    template: "%s | NEXT MALL",
  },
  description: "X2BEE MALL FO by Plateer",
  icons: {
    icon: "/favicon.ico",
  },
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className={`${inter.variable} ${spaceGrotesk.variable}`}>
        {children}
      </body>
    </html>
  );
}

 
2. Route Groups에 의한 다른 layout
시나리오 : 다른 모든 경우에서는 기본 footer를 사용하고, 상품상세 페이지에서만 footer에 '바로 구매'와 '장바구니에 담기' 버튼을 그리고 싶을 때, Route Groups를 사용합니다.
Route Groups란 폴더에 괄호()를 치면 folder-base route의 이름에 전혀 영향을 미치지 않고, 폴더를 정리하는 용도로 쓰이고,
추가로 각 괄호에 있는 폴더별로 공통 layout을 설정할 수 있습니다.
예시:

 
실제 Root Layout (가장 밑에 파일)은 children만 통과시키고, 
(root)/(home)/page.tsx에는 원래 root page를 옮기고,
(root)에는 기본 layout.tsx을 사용, (goods-detail)에는 다른 layout.tsx을 적용하는 방법.
공식문서 참조: https://nextjs.org/docs/app/building-your-application/routing/route-groups
 

5. 기본 tailwind 구문의 정리 정책 (파일을 따로 뺀다던지 or 컴포넌트 내부에서 조합을 해서 className을 줄일 수 있는 가이드 등등)

→ utility class 재사용 방법 
1. tailwind.config.js
이미 정의되어있는 utility class를 재정의하거나, 새로운 utility class를 정의할 때 사용
개발가이드 참조: https://x2bee.tistory.com/221 
2. globals.css 
위 개발가이드 참조
base는 주로 reset CSS 관련 코드
components는 재사용할 className 정의
utilities도 재사용할 className을 정의하지만 components보다 우선 순위를 가지고, 보통 작은 코드나 미디어 쿼리, pseudo-class를 정의할 때 사용
3. ui library 방식의 .tsx 파일로 정의
개발가이드 참조 : https://x2bee.tistory.com/267
 

6. 공통유틸, 모듈별 유틸 정의 가이드 - 어떤 폴더에 어떤 형식으로 정리 하는게 좋을지

→ moonstore-next-fo-vanilla 프로젝트에서 깃에서 받아서 확인하면 폴더별로 구분이 되어 있음. 간단하게 폴더별로 설명하면 다음과 같음.

1. api 폴더 : api를 정의함.

 
2. components 폴더 : component를 정의함.

 

3. models 폴더 : interface, type을 정의함.

 
4. lib 폴더 : 상수, 커스텀 훅, Context(Provider), Zustand 상태객체, 함수등의 유틸을 정의함.

 
 

7. ts 사용에 대한 가이드 - 대부분 js를 써왔는데 ts에 대한 기본적인 가이드가 필요하다고 생각

→ 타입스크립트는 interface를 이용하여 클래스 또는 객체의 타입만 지정하면 되기 때문에 크게 가이드는 크게 필요없지만 밑에서 간단하게 사용법만 설명함.
type도 있지만 interface와 큰 차이가 없고 타입 지원시 interface 사용이 권장됨.

타입스크립트의 문제점은 동네북 Any, 애니스크립트라는 말이 있을 정도로 모든 타입을 any나 Object로 남발하는 문제가 생김.
그렇기 때문에 귀찮더라도 개발시에 작은 코드라도 타입을 선업하는 습관을 가지는게 좋음.
 
- 개발시 규칙

1. 선언하는 쪽(Class, Function등)은 무조건 interface 및 타입을 선언해야됨.
귀찮다고 하나라도 any를 남발하게 되는 순간 동네북 Any가 됨.
또한 해당 타입선언으로 자바, C등의 코드와 같이 사용하는 쪽에서도 매개변수 및 반환값을 명확하게 알 수 있으므로 장점이 됨.

2. 사용하는 쪽에서는 왠만하면 선언하는 쪽에서 만들어놓은 타입 및 기본 타입이 있을거기 때문에 해당 타입을 사용함.
그러나 정말 어쩔수 없는 경우(이벤트의 타입을 어떻게 정의해줘야 할 지 몰라서 any를 쓰는 경우등 → 물론 이경우에도 e: React.changeEvent<HTMLInputElement> 다음과 같은 등으로 사용하면됨)에는 any를 사용하는 것은 허용함.

- 간단 사용법

1. 클래스에서 interface 사용

interface Testtype {
  getTest(): string;
}

class Testclass implements Testtype {
  test: string;

  constructor(test: string) {
    this.test = test;
  }

  getTest() {
    return this.test;
  }
}

 
2. 객체에서 interface 사용

interface Testtype {
  test: string;
}

const test: Testtype = {
  test: '테스트값이야'
};

 
3. 함수에서 타입 선언

function test(test1: string, test2: number): string {
   return test1 + ' / ' + test2;
}

 

8. 구글페이지스피드 점수를 높게하기 위한 가이드

→ 

1. 이미지 최적화 
=> 페이지 속도에 영향을 미치는 요인의 중요 요소입니다.
=> 이미지를 최적화하고 압축하여 파일의 크기를 줄입니다.
=> 기본적으로 next/image 컴포넌트를 사용하면 이미지 최적화를 지원합니다.

2. css, javascript 
=> tailwindcss를 사용하기에 패스, 대부분 장점요소입니다.
=> 가능한 관련 파일을 축소하고 불필요한 문자를 제거합니다.

3. 캐싱 
=> 캐싱은 서버에 대한 요청 수를 줄여 페이지 속도를 향상시키는 데 중요한 역할을 합니다.
=> 캐싱을 최대한 활용하여 주요 페이지들의 로드 시간을 줄입니다.

4. 서버 응답 시간
=> 서버가 사용자 브라우저의 요청에 응답하는 데 걸리는 시간은 페이지 속도에 영향을 줍니다.
=> 서버 응답 시간을 정기적으로 모니터링하고 최적화합니다.

5. 브라우저 개발자 도구
=> 개발자 도구창에서 콘솔로그에 오류가 나타나지않도록 소스를 유지보수합니다.

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유