[React] Day_72 데일리 정리

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: 행복한 미래를 꿈꾸며...