React TIL

[React] Day_72 데일리 정리

림졍 2024. 12. 31. 21:48
728x90
반응형

벌써 2025년이야? (한숨)

 

2024의 마지막 내용은 최종 플젝 시작 전, 폴더구조 정하기...

바로 가볼깝쇼? (후딱 쓰고 잘거임)

 

 

 

 

챌린지반 강의정리 - 프로젝트 구조 효율적으로 조직하기 (Next.JS)

으아아아아 너무 어려워요

 

알다가도 모르겠는 구조 네이넘... ㅇㅍㅇ

 

 

Next.js 폴더 구조의 중요성

 

- 유지보수성 :  체계적인 구조는 코드가 복잡해질수록  유지보수가 쉬워진다.

- 협업 효율성 : 팀원 간 작업 분배가 명확 + 코드 탐색 빠르게 Ok!

- 재사용성 및 확장성 : 공통 컴포넌트, 기능별 파일 분리 → 프로젝트 확장 시 충돌을 방지

 

 

Next.js 폴더 구조 및 라우팅 규칙

app/
├─ home/
│  ├─ page.tsx         # /home
│  ├─ HomeBanner.tsx   # 라우트 안됨 (UI 컴포넌트)
├─ about/
│  ├─ page.tsx         # /about
├─ api/
│  ├─ hello/
│  │  └─ route.ts      # /api/hello (API 라우트)
├─ (admin)/
│  ├─ dashboard/
│  │  └─ page.tsx      # /dashboard (라우트 그룹)
│
├─ _components/        # 전역 컴포넌트 (라우트 안됨)
│  ├─ Button.tsx
│  ├─ Header.tsx
│  ├─ Footer.tsx

 

 

- page.tsx : 폴더가 경로, page.tsx는 해당 라우트로 매핑

- API 라우트 : route.ts를 사용, API 엔드포인트 생성 가능

- 라우터 그룹 : (폴더명)을 사용, URL에 포함되지 않아 폴더 정리 가능

- 비공개 폴더 : _components처럼 _로 시작 시, 라우팅에서 제외

 

 

폴더 구조 전략

 

- 단순 구조 (소규모 프로젝트)

app/
├─ home/
│  ├─ page.tsx
│  └─ Banner.tsx
├─ components/
│  ├─ Button.tsx
│  ├─ Header.tsx
│  └─ Footer.tsx
  • components/ 폴더에 모든 컴포넌트 집중
    • 장점 : 빠르게 설정 가능
    • 단점 : 프로젝트가 커지면 파일이 뒤엉킬 수 있음

 

- 기능별 구조 (대규모 프로젝트)

app/
├─ user/
│  ├─ page.tsx
│  ├─ _components/
│  │  ├─ UserProfile.tsx
│  │  ├─ UserCard.tsx
├─ product/
│  ├─ page.tsx
│  ├─ ProductDetail.tsx
│  ├─ ProductList.tsx
  • 특정 기능별로 파일을 분리 (user, product).
  • 각 폴더 안에 필요한 컴포넌트를 _components에 저장
    • 장점: 기능별로 모든 관련 파일이 한곳에 모임
    • 단점: 공통 컴포넌트가 중복될 가능성

 

- Atomic Design 기반 구조

components/
├─ atoms/
│  ├─ Button.tsx
│  ├─ Input.tsx
├─ molecules/
│  ├─ SearchBar.tsx
│  ├─ UserCard.tsx
├─ organisms/
│  ├─ Header.tsx
│  ├─ Footer.tsx
  • Atoms → Molecules → Organisms로 UI를 설계
    • 장점 : 재사용성이 높고 디자인 시스템과의 호환성이 뛰어남
    • 단점 : 초기 설계 난이도가 높음

 

Route Handler에서 Supabase 사용 예시

 

→ 서버에서 Supabase 클라이언트를 생성하여 DB 연산을 수행

import { createClient } from "@/utils/supabase/server";

export async function POST(request: Request) {

  const supabase = await createClient();
  const body = await request.json();
  const { data, error } = await supabase.from("todos").insert(body);
    
  if (error) {
    return new Response(JSON.stringify({ error: error.message }), { status: 400 });
  }
  return new Response(JSON.stringify({ data }), { status: 200 });
}

 

 

 

 

로그인 및 회원가입 예제

 

- 서버 액션으로 로그인 구현 → 실패 시 에러 페이지로 리다이렉트, 성공 시 메인 페이지로 이동.

"use server";

import { revalidatePath } from 'next/cache';
import { redirect } from 'next/navigation';
import { createClient } from '@/utils/supabase/server';

export async function login(formData: FormData) {

  const supabase = await createClient();
  const data = {
    email: formData.get('email') as string,
    password: formData.get('password') as string,
  };

  const { error } = await supabase.auth.signInWithPassword(data);
  if (error) redirect('/error');
  revalidatePath('/', 'layout');
  redirect('/');

}

 

 

API 트리거 예시 (회원가입 자동 동기화)

 

- auth.users 테이블에 새 사용자 추가 시, users 테이블에 자동 삽입

CREATE OR REPLACE FUNCTION public.handle_new_user()

RETURNS TRIGGER AS $$
BEGIN
  INSERT INTO public.users (id, email)
  VALUES (NEW.id, NEW.email);
  RETURN NEW;
END;

$$ LANGUAGE plpgsql;

CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW

EXECUTE FUNCTION public.handle_new_user();

 

 

커스텀 훅으로 데이터 로직 분리

 

기존 (데이터 로직과 UI가 혼재) - 데이터 패칭 로직과 UI가 강하게 결합되는 문제점 발생

export function UserProfile({ userId }) {

  const [user, setUser] = useState(null);

  useEffect(() => {
    fetch(`/api/user/${userId}`)
      .then(res => res.json())
      .then(setUser);
  }, [userId]);

  return <div>{user?.name}</div>;

}

 

개선 (커스텀 훅 사용)

// hooks/useUser.ts
import { useEffect, useState } from 'react';

export function useUser(userId: string) {
  const [user, setUser] = useState(null);
  useEffect(() => {
    fetch(`/api/user/${userId}`)
      .then(res => res.json())
      .then(setUser);
  }, [userId]);

  return user;
}

// UserProfile.tsx
import { useUser } from '@/hooks/useUser';

export default function UserProfile({ userId }) {
  const user = useUser(userId);
  
  return <div>{user?.name}</div>;
}
  • 장점
    • UI와 데이터 로직이 분리되어 가독성이 높아짐.
    • 커스텀 훅으로 데이터 로직 재사용 가능.

 

확장 가능한 API 서비스 (서비스 레이어)

- API 호출 로직, 서비스 레이어로 분리  다른 곳에서도 재사용 가능

// services/userService.ts
export async function getUser(userId: string) {
  const res = await fetch(`/api/user/${userId}`);
  if (!res.ok) throw new Error('Failed to fetch user');
  return res.json();
}

 

 

서비스 레이어와 커스텀 훅 결합

- 커스텀 훅 없이도 서비스 레이어를 통해 API 호출을 쉽게 확장 가능

// UserProfile.tsx
import { useEffect, useState } from 'react';
import { getUser } from '@/services/userService';

export default function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  
  useEffect(() => {
    getUser(userId).then(setUser);
  }, [userId]);
  
  return <div>{user?.name}</div>;

}

 

 

마무리 - 햎 뉴여~

이 편지는 영국에서 시작되어...

 

진짜 너무 고생했던 2024년이 끝났다..

사람이 이렇게까지 억까를 당할 수 있는건가 싶을 정도로 주변 상황이 너무 안좋게 흘러갔었는데..

그래도 주변에 있던 좋은 사람들 덕에 견딜 수 있었던 한 해였던 것 같다!

내년에도 알차게 코딩해야지!

구롬 20000! 내년에 보자구.

 

 

오늘의 KPT 회고

 

Keep: 내년에도 코딩 킵고잉

Problem: 올해의 문제는 버리고간다.

Try: 행복한 미래를 꿈꾸며...

728x90
반응형