콘텐츠로 이동

06. React: 웹을 레고처럼 조립하기

"HTML이 그림판에 그림을 그리는 것이라면, React는 데이터를 넣으면 화면이 튀어나오는 자판기입니다."

0. Introduction: 왜 리액트인가?

웹사이트를 만드는 방식은 크게 두 가지 시대로 나뉩니다.

🏠 전통적인 방식 (Vanilla JS): "수리공 모델"

전통적인 자바스크립트 방식은 이미 지어진 집(화면)에서 고장 난 곳을 찾아가 직접 고치는 방식입니다.

  • 방식: "ID가 price인 글자를 찾아서 숫자를 1,000으로 바꿔!"
  • 특징: 개발자가 화면의 모든 요소를 하나하나 감시하고 직접 명령해야 합니다.
  • 문제점: 서비스가 커져서 고칠 곳이 100개가 되면, 하나만 깜빡해도 데이터와 화면이 어긋나는 대참사가 일어납니다.

🏎️ 현대적인 방식 (React): "영화 상영기 모델"

리액트는 화면을 고치지 않습니다. 대신 데이터가 바뀔 때마다 새 화면을 찍어서 순식간에 교체합니다.

  • 방식: "데이터가 1,000이면, 화면은 이런 모습이어야 해." (규칙 선언)
  • 특징: 개발자가 데이터(State)만 관리합니다. 화면을 다시 그리는 건 리액트가 알아서 합니다.
  • 장점: 복잡한 화면도 데이터 하나만 바꾸면 모든 곳이 동시에, 정확하게 바뀝니다.

📊 한눈에 비교하기

구분 일반 JavaScript (명령형) React (선언형)
핵심 사고 "어떻게(How) 고칠까?" "무엇(What)을 보여줄까?"
작업 방식 바뀐 부분을 직접 찾아가서 수정 데이터가 변하면 화면 전체를 새로 그림
비유 수동 카메라 (초점, 셔터 다 조절) 스마트폰 카메라 (누르면 알아서 찍힘)
난이도 작은 앱에선 쉽지만, 큰 앱에선 지옥 처음엔 생소하지만, 복잡할수록 편함

💡 학습 포인트: "생각의 전환"

이제부터 우리는 "이 버튼을 누르면 이 글자를 바꿔야지"라고 생각하지 않습니다. "이 버튼을 누르면 데이터(State)를 바꿔야지. 그러면 리액트가 화면을 알아서 다시 그려줄 거야!"라고 생각해야 합니다.


0-1. 탄생 비화: 페이스북의 절박함 📜

리액트는 단순히 "좋아서" 만든 게 아니라, 버그 때문에 망할 뻔해서 만들었습니다.

  • 배경: 2010년대 초반, 페이스북의 가장 큰 골칫거리는 '읽지 않은 알림(Notification) 표시'였습니다.
  • 문제: 메시지를 확인했는데 상단 알림 아이콘의 숫자는 그대로거나, 채팅창을 껐는데 오른쪽 친구 목록에는 온라인으로 떠 있는 등 화면 곳곳의 정보가 따로 노는 버그가 끊이지 않았습니다.
  • 원인: 일반 자바스크립트로 화면의 수백 군데를 직접 수정(수리공 모델)하다 보니, 데이터가 하나 변했을 때 연관된 모든 화면을 실수 없이 업데이트하는 것이 인간의 지능으로는 불가능해진 것입니다.
  • 해결: "직접 고치지 말자. 그냥 데이터가 변하면 화면을 싹 다 다시 그려버리자!"라는 파격적인 발상을 하게 됩니다.

0-2. 비유 강화: 길 찾기 (Imperative vs Declarative) 🗺️

명령형(Vanilla JS)과 선언형(React)의 차이를 '길 찾기'로 비유해보겠습니다.

  • 명령형 (Vanilla JS): "강남역 2번 출구로 나와서 100m 직진한 다음, 편의점이 나오면 우회전하고, 다시 50m 가서..."
    • 문제: 가는 길에 건물이 하나라도 새로 생기거나 공사 중이면(코드 구조가 바뀌면) 길을 잃습니다.
  • 선언형 (React): "목적지는 강남역 역삼 초등학교 앞이야. 어떻게 가든 상관없으니 무조건 거기로 데려다줘."
    • 장점: 개발자는 목적지(데이터 상태)만 명시합니다. 그곳으로 가는 복잡한 과정(DOM 조작)은 리액트라는 내비게이션이 최적의 경로로 처리합니다.

0-3. 성능의 비밀: Virtual DOM (가상 세계) 🪞

"전체를 다시 그리면 느리지 않나요?"라는 의구심이 들 수 있습니다. 리액트는 '포토샵 레이어''거울' 같은 기술을 씁니다.

  • 핵심: 실제로 브라우저 화면을 매번 다 갈아엎는 게 아닙니다. 메모리라는 가상의 공간(Virtual DOM)에 '미리 그려보고', 이전 화면과 '틀린 그림 찾기'를 한 뒤에, 진짜 바뀐 부분만 아주 영리하게 교체합니다.
  • 유용성: 이 덕분에 개발자는 성능 걱정 없이 "다시 그려!"라고 마음 편히 선언할 수 있는 자유를 얻었습니다.

0-4. UI의 부품화 (Componentize) 🧩

왜 레고 모델이 유용한지 경제적인 관점에서 생각해보세요.

  • 중복의 제거: "좋아요 버튼" 하나를 잘 만들어두면, 뉴스피드, 댓글창, 프로필 페이지 등 어디서든 재사용할 수 있습니다.
  • 독립적인 관리: 한 부품이 고장 나도 다른 부품은 멀쩡합니다. 전체 코드를 다 뒤질 필요 없이 해당 부품 파일만 열면 됩니다.

"리액트를 배운다는 것은, 화면의 하인(명령형)이 되는 대신 화면의 주인(선언형)이 되는 법을 배우는 것입니다."

우리가 리액트를 쓰는 진짜 이유는 단순히 '빠르기 때문'이 아닙니다. 서비스가 거대해져도 데이터와 화면이 절대로 어긋나지 않도록 강제하기 때문입니다. 리액트는 개발자가 비즈니스 로직(무엇을 만들지)에만 집중하게 하고, 지루하고 실수가 잦은 화면 수정 작업(어떻게 그릴지)은 스스로 도맡아 처리합니다.


1. Setup: 도구 준비 (Vite) ⚡

우리는 리액트를 시작할 때, 과거의 표준이었던 create-react-app을 쓰지 않습니다. 대신 Vite라는 최신 도구를 사용합니다.

1-1. 왜 Vite인가요?

  • 속도: create-react-app보다 10배 이상 빠릅니다. (진짜 번개처럼 빠름)
  • 표준: 요즘 실리콘밸리 스타트업들은 다 이걸 씁니다.

🗣️ 발음 팁: "바이트"가 아니라 "비트"라고 읽습니다. (프랑스어로 '빠르다'는 뜻입니다!)

1-2. 프로젝트 생성하기 (따라하기)

터미널을 열고 바탕화면 등 원하는 위치에서 아래 명령어를 입력하세요.

Step 1. 뼈대 만들기 (Scaffolding)

# 프로젝트 생성 (이름: my-team-page)
npm create vite@latest my-team-page -- --template react-ts

(여기까지 하고 터미널을 꺼도 좋습니다.)

Step 2. 폴더 열기 (Open Folder) 📂 이제 방금 만든 폴더를 코딩 도구로 엽니다.

  1. VS Code (또는 Cursor/Antigravity) 실행.
  2. 상단 메뉴 File -> Open Folder... 클릭.
  3. 방금 만든 my-team-page 폴더를 선택하고 열기.

Step 2-1. 깃허브 창고 짓기 (Git Init & Push) 🐱 프로젝트를 만들었으니, 잃어버리지 않게 바로 깃허브에 저장을 시작합시다.

  1. GitHub 웹사이트에서 New Repository를 클릭합니다.
  2. Repository Name에 폴더명과 똑같이 my-team-page라고 적고 Create 클릭.
  3. VS Code 터미널에 아래 명령어를 한 줄씩 복사해서 붙여넣으세요.
# 내 컴퓨터에 깃 초기화
git init
git add .
git commit -m "First Commit: 리액트 프로젝트 생성"

# 깃허브랑 연결 (주소는 본인 걸로 바꾸세요!)
git branch -M main
git remote add origin https://github.com/[아이디]/my-team-page.git
git push -u origin main

🚨 생존 규칙: 저장(Save)과 커밋(Commit)은 다릅니다

Ctrl+S는 내 컴퓨터에만 저장하는 것이고, git commit은 타임머신 기록을 남기는 것입니다. 기능 하나를 완성할 때마다 커밋하는 습관을 들이세요. 에러가 나서 코드가 꼬였을 때, 커밋이 없으면 처음부터 다시 만들어야 합니다. (진짜입니다.)

Step 2-2. 터미널이 어렵다면? (GUI & AI) ✨

명령어가 복잡해 보이면 더 쉬운 방법을 쓰세요.

  1. VS Code (Source Control):
    • 왼쪽의 Y자 모양 아이콘 (소스 제어)을 클릭합니다.
    • Initialize Repository (초기화) -> Publish Branch (깃허브 게시) 버튼을 차례로 누릅니다.
    • 이후에는 + (Add) -> 메시지 작성 -> Commit -> Sync (Push) 버튼만 누르면 됩니다.
  2. Antigravity (AI):
    • 채팅창에 "방금 수정한 내용 커밋하고 푸시해줘"라고 말해보세요.
    • AI가 알아서 명령어를 실행해줍니다. (우리는 지시만 하면 됩니다.)

Step 3. 라이브러리 설치 및 실행 🚀 이제 에디터 안에서 터미널을 켭니다. (이게 훨씬 편합니다!)

  1. 상단 메뉴 Terminal -> New Terminal 클릭.
  2. 아래 명령어를 순서대로 입력하세요.
# 1. 필요한 부품(라이브러리) 다운로드
npm install

# 2. 개발 서버 실행
npm run dev

성공 확인: 터미널에 Local: http://localhost:5173/ 같은 주소가 떴나요? Ctrl을 누른 채 저 주소를 클릭해보세요. 브라우저에 Vite + React 로고가 빙글빙글 돌고 있다면 성공입니다! 🎉

2. React의 3단 구조: Page, Component, Hook

리액트 개발은 "화면을 쪼개고(Component), 조립해서(Page), 기능을 심는(Hook)" 과정입니다. 이 3가지 단어만 알면 리액트의 숲이 보입니다.

구조 역할 설명
Component Atomic UI / Props "무엇을 보여줄까?" (View)
재사용 가능한 최소 단위의 UI 부품
Page Composition / Props Drilling "어디에 배치하고 무엇을 줄까?" (Controller)
부품을 조립하고 데이터를 내려주는 완성된 화면
Hook State / Effect Logic "어떻게 움직일까?" (Logic)
컴포넌트에 생명(데이터, 기능)을 불어넣는 도구

① Component (부품)

"레고 블록 하나하나"

  • 정의: 재사용 가능한 최소 단위의 UI입니다.
  • 예시: 프로필 카드, 온라인 상태 뱃지, 필터 버튼.
  • 특징: 혼자서는 의미가 없고, 어딘가에 조립되어야 합니다.

② Page (완성품)

"레고로 만든 성(Castle)"

  • 정의: 컴포넌트들을 조립해서 만든 하나의 온전한 화면입니다.
  • 예시: 팀원 소개 페이지, 로그인 페이지.
  • 특징: 브라우저 주소창(URL) 하나당 페이지 하나가 매칭됩니다. (/team -> TeamPage)

③ Hook (장비/도구)

"레고 사람 손에 쥐어주는 마법 지팡이"

  • 정의: 컴포넌트(function)는 원래 멍청합니다. 그림만 그릴 줄 알죠. 이 컴포넌트에게 기억력(State)이나 초능력(Effect)을 부여하는 도구들을 훅(Hook)이라고 합니다.
  • 이름: 무조건 use로 시작합니다. (useState, useEffect, useRouter...)

🏫 Visible Thinking: 구조도

이 관계를 그림으로 이해하면 프로젝트 폴더 구조가 보입니다.

graph TD
    subgraph "Page (화면)"
        TeamPage["🏠 Team Page"]
    end

    subgraph "Component (부품)"
        Header["🧩 Header"]
        ProfileCard["🧩 Profile Card"]
        FilterButton["🧩 Filter Button"]
    end

    subgraph "Hook (도구)"
        UseState["⚡ useState<br>(기억하기)"]
        UseEffect["⏰ useEffect<br>(타이밍)"]
    end

    TeamPage --> Header
    TeamPage --> ProfileCard
    TeamPage --> FilterButton

    ProfileCard --> UseState
    TeamPage --> UseEffect

    style TeamPage fill:#e3f2fd,stroke:#1565c0
    style Header fill:#fff9c4,stroke:#fbc02d
    style ProfileCard fill:#fff9c4,stroke:#fbc02d
    style FilterButton fill:#fff9c4,stroke:#fbc02d
    style UseState fill:#fce4ec,stroke:#c2185b
    style UseEffect fill:#fce4ec,stroke:#c2185b

3. Props: 설계도와 부품의 연결 (TS + React)

5장에서 배운 TypeScript가 여기서 빛을 발합니다. 부품을 만들 때, "어떤 재료가 필요한지"를 Interface로 정의합니다. 이것을 React에서는 Props(Properties)라고 부릅니다.

우리는 '팀원 소개 프로필 카드'를 만들 것입니다.

// 1. 설계도 (Interface)
interface ProfileCardProps {
    name: string;
    role: "Developer" | "Designer" | "PM"; // 오타 방지!
    isOnline: boolean;
}

// 2. 부품 (Component)
function ProfileCard({ name, role, isOnline }: ProfileCardProps) {
    return (
        <div className="card">
            <h3>{name}</h3>
            <p>{role}</p>
            {/* 조건부 렌더링: 온라인일 때만 🟢 표시 */}
            {isOnline && <span>🟢 Online</span>}
        </div>
    );
}

// 3. 조립 (Usage)
function TeamPage() {
    return (
        <div>
            <ProfileCard name="철수" role="Developer" isOnline={true} />
            <ProfileCard name="영희" role="Designer" isOnline={false} />
        </div>
    );
}

4. State: 살아있는 데이터

React가 'React(반응하다)'인 이유는 데이터가 변하면 즉시 반응하기 때문입니다. 이 변화하는 데이터를 State(상태)라고 부릅니다.

개념 잡기: useState'화면 전용 변수'입니다. 일반 변수는 함수가 끝나면 사라져서 내용을 까먹지만, State는 리액트가 별도의 메모리에 저장해두기 때문에 함수가 다시 실행되어도 그 값을 기억(Memory)합니다.

Visible Thinking: '필터 스위치'를 생각하세요. "온라인만 보기(State)" 스위치만 켜면, 화면은 알아서 바뀝니다.

function TeamPage() {
    // [상태, 상태변경함수] = useState(초기값)
    const [showOnlineOnly, setShowOnlineOnly] = useState(false);

    return (
        <div>
            <button onClick={() => setShowOnlineOnly(!showOnlineOnly)}>
                {showOnlineOnly ? "모두 보기" : "온라인만 보기"}
            </button>

            {/* 상태에 따라 화면이 달라짐 */}
            {showOnlineOnly ? <OnlineMembers /> : <AllMembers />}
        </div>
    );
}

5. useEffect: 타이밍을 맞추는 마법

useState가 데이터를 저장하는 것이라면, useEffect는 특정 타이밍(Timing)에 코드를 실행하는 것입니다.

"리액트야, 화면 그리는 거 다 끝나면 그 후에(After Effect) 이 작업 좀 해줘."

5-1. 가장 많이 쓰는 패턴: "화면 켜지자마자"

파이썬 클래스의 __init__ 처럼, 페이지가 처음 뜰 때 서버에서 팀원 목록을 불러와야 합니다. (Fetch)

import { useState, useEffect } from 'react';

function TeamPage() {
    const [members, setMembers] = useState([]);

    // useEffect(함수, [감시할대상])
    useEffect(() => {
        // 1. 화면이 짠! 하고 나타난 뒤에 실행됨
        console.log("서버에 팀원 목록 요청...");

        // 💡 꿀팁: useEffect 안에서는 async를 바로 쓸 수 없습니다.
        // 대신 안에 함수를 만들어서 실행합니다.
        const fetchMembers = async () => {
            const res = await fetch("/api/members");
            const data = await res.json();
            setMembers(data); // 데이터를 받아오면 State 업데이트 -> 화면 갱신
        };

        fetchMembers(); // 만든 함수 실행

    }, []); // 👈 여기가 비어있으면([]), "맨 처음 한 번만" 실행한다는 뜻

    return (
        <div>
            {members.map(member => (
                <ProfileCard key={member.id} {...member} />
            ))}
        </div>
    );
}

⚠️ 문법 주의: useEffect는 비동기 함수가 될 수 없습니다

초보자가 가장 많이 하는 실수 중 하나입니다.

  • ❌ 안됨: useEffect(async () => { ... })
  • 이유: async 함수는 무조건 프로미스(Promise)를 반환합니다. 하지만 useEffect뒷정리 함수(Cleanup Function)를 반환하거나 아무것도 반환하지 않아야 합니다. 타입이 안 맞아서 에러가 납니다!
  • ✅ 해결: 위 예시처럼 안에서 async 함수를 따로 만들어서 실행(Call)해야 합니다.

🚨 무한 루프 주의 (Infinite Loop)

useEffect의 두 번째 괄호([])를 의존성 배열(Dependency Array)이라고 합니다. 이걸 아예 빼먹으면(useEffect(() => { ... })), 리액트는 "화면 그릴 때마다 계속 실행해!"로 알아듣습니다. 만약 이 안에서 setState를 한다면? -> 화면 갱신 -> useEffect 실행 -> 또 갱신 -> 또 실행... 브라우저가 뻗을 때까지 무한 반복됩니다. 꼭 빈 배열([])이라도 넣어주세요!

6. AI Native Workflow: 글(Text)과 그림(Image)의 협업

AI에게 코딩을 시킬 때 가장 중요한 원칙은 "기능(Logic)과 디자인(Visual)을 분리해서 명령하는 것"입니다. 한 번에 다 말하면 AI도 체합니다.

Step 1. 기획: 글로 쓰는 주문서 (Text)

먼저 "무엇이(What)" 들어가야 하는지 글로 정리합니다. 이때 디자인(색깔, 위치)은 절대 고민하지 마세요. 오직 데이터와 기능에만 집중합니다.

비유: 식당에서 음식을 주문할 때 "맛있는 거 주세요"라고 하지 않죠? "김치찌개에(메뉴), 두부 추가하고(옵션), 맵게 해주세요(조건)." 라고 정확히 말해야 합니다.

  • 활동: AI와 대화하며 요구사항 정의서(prd.md) 작성하기
  • 핵심 질문:
    • 어떤 데이터가 필요한가? (이름, 사진, 직업...)
    • 어떤 기능이 작동해야 하는가? (필터링, 검색, 클릭...)
  • 산출물: prd.md (텍스트 파일)

Step 2. 화면 구성: 눈으로 보는 도면 (Image)

기획이 "재료 준비"라면, 화면 구성은 "플레이팅(Plating)"입니다. 같은 재료라도 어떻게 배치하느냐에 따라 전혀 다른 앱이 됩니다. 이제 "어떻게(How)" 보일지를 결정합니다.

비유: 인테리어 업자에게 말로 "모던하게 해주세요" 하는 것보다, 잡지 사진 한 장을 보여주며 "이거랑 똑같이 해주세요" 하는 게 백 번 낫습니다.

  • 활동: 손그림이나 Excalidraw로 배치도 그리기 (방법: 손그림, Excalidraw, Figma 등)
  • 핵심 질문:
    • 헤더는 어디에 둘까?
    • 프로필 카드는 한 줄에 몇 개씩 보여줄까?
    • 강조할 버튼은 어디에 배치할까?
  • 산출물: wireframe.png (이미지 파일 또는 캡처)

실전: 와이어프레임 준비하기

우리가 만들 '팀원 소개 페이지'를 Excalidraw나 손그림으로 대충 그립니다. 그리고 이 그림을 wireframe.png 로 저장해두세요. 나중에 Step 4에서 AI에게 보여줄 것입니다.

Tip: 그림을 잘 그릴 필요 없습니다. 네모 박스와 글씨만 있으면 됩니다.

Step 3. 설계: 논리 구조 검증 (Diagram)

이제 "주문서(Text)"와 "도면(Image)"이 모두 준비되었습니다. 하지만 구현에 들어가기 전에 마지막으로 논리적인 모순이 없는지 검증해야 합니다.

AI에게 "이 내용을 바탕으로 클래스/시퀀스 다이어그램 파일을 작성해줘" 라고 요청하세요. 그리고 우리는 VS Code에서 그 파일을 열어 눈으로 확인만 하면 됩니다.

준비물: VS Code 확장팩 'Markdown Preview Mermaid Support' 설치 필수!

① AI에게 다이어그램 파일 요청하기

Prompt

좋아, 위 기획(PRD) 내용을 바탕으로 데이터 구조(Class Diagram)동작 흐름(Sequence Diagram)을 설계해줘. 각각 class_diagram.md, sequence_diagram.md 파일로 만들되, Mermaid 문법을 사용한 마크다운 형식으로 작성해줘.

📄 class_diagram.md (예시)

classDiagram
    class ProfileCardProps {
        +string name
        +string role
        +boolean isOnline
    }

📄 sequence_diagram.md (예시)

sequenceDiagram
    participant User
    participant Component as FilterButton (부품)
    participant Page as TeamPage (화면)
    participant Hook as useState (도구)
    participant RealUI as Browser (브라우저)

    User->>Component: 1. 클릭 (Click)
    Component->>Page: 2. 신호 보냄 (onClick)
    Page->>Hook: 3. "데이터 바꿔줘!" (setState)
    Hook-->>Page: 4. "값 변경 완료, 다시 그려!" (Trigger Re-render)
    Page->>RealUI: 5. 새로운 화면 그리기 (Update UI)

② 눈으로 검증하기 (Human Verification)

저장한 파일을 VS Code에서 열어보세요. 코드가 아니라 그림(Diagram)이 나타납니다. 우리는 코드를 읽을 필요가 없습니다. 그림을 보고 이상한 점만 찾으세요.

Step 4. 구현 (Development)

이제 저장해둔 설계도(prd.md, class_diagram.md, sequence_diagram.md)와 화면(wireframe.png)을 모두 가지고 아키텍트 프롬프트를 실행합니다.


🚀 실전: 아키텍트 프롬프트 (Architect Prompt)

단순히 "만들어줘"라고 하면 AI는 엉망인 코드를 줍니다. 아래 양식을 복사해서, 구현 목표만 바꿔서 AI에게 던져보세요. 전문가 수준의 구조를 잡아줍니다.

# 역할 부여
당신은 리액트 아키텍처 설계 전문가입니다.
**관심사의 분리(Separation of Concerns)** 원칙을 철저히 지켜 코드를 작성해주세요.

# 구현 목표
팀원 소개 프로필 카드 웹사이트를 만듭니다.
작성된 **기획서**, **설계도**, **와이어프레임**을 모두 참고하여 구현해주세요.

# 참고 자료 (반드시 내용을 확인하고 반영할 것)
1. **기획서:** `prd.md` (첨부파일)
2. **설계도:** `class_diagram.md`, `sequence_diagram.md` (첨부파일)
3. **화면 구성:** `wireframe.png` (첨부한 이미지를 시각적 가이드로 삼을 것)

# 핵심 요구 사항
1. **기능:**
    - 팀원 데이터(이름, 직업, 사진, 온라인여부) 표시
    - "온라인인 사람만 보기" 필터링 기능
2. **디자인:**
    - 와이어프레임의 레이아웃을 준수하세요.
    - Tailwind CSS를 사용하여 깔끔하고 현대적인 스타일로 구현하세요.

# 📂 디렉토리 구조 가이드 (필수 준수)
아래의 폴더 구조 규칙에 맞춰서, **가장 적절한 파일명을 당신이 직접 지어서** 코드를 작성해주세요.
모든 코드 블록의 최상단에는 `// src/hooks/useExample.ts` 처럼 **파일 경로를 주석으로 명시**해야 합니다.

1. **`src/types/`**: 공통 인터페이스 정의
2. **`src/hooks/`**: 데이터(State)와 로직(Filter)을 담당하는 Custom Hook
3. **`src/components/`**: 로직 없이 UI만 담당하는 순수 컴포넌트
4. **`src/pages/`**: Hook과 Component를 조립하는 페이지
5. **`src/App.tsx`**: 위에서 만든 페이지를 불러오는 메인 파일

# 기술 스택
- Vite + React + TypeScript
- Tailwind CSS

Step 5. 수정 및 보완 (Debugging Loop)

코드를 복사해서 실행했는데 에러가 나거나, 화면이 이상하게 나올 수 있습니다. 놀라지 마세요. 지극히 정상입니다. 개발의 50%는 에러를 잡는 과정입니다.

가장 중요한 규칙은 "직접 코드를 뜯어고치지 않는 것"입니다. 여러분이 직접 코드를 수정하면, AI가 알고 있는 코드와 달라져서 다음 질문을 했을 때 엉뚱한 답을 줄 수 있습니다.

AI와의 디버깅 3단계

  1. 에러 확인 및 복사: 터미널뿐만 아니라 브라우저 콘솔(F12 > Console)을 꼭 확인하세요! 리액트 앱은 실행 중에 발생하는 에러가 브라우저 콘솔에 훨씬 자세하게 찍힙니다. 콘솔 메시지가 없어서 디버깅이 힘들다면 AI에게 디버깅 메시지를 더 출력해달라고 합니다.
  2. AI에게 제보: 에러 메시지를 복사해서 "이런 에러가 떴어. 원인이 뭐야? 수정된 전체 코드를 줘." 하고 AI에게 붙여넣으세요.
  3. AI 코드 적용: AI가 고쳐준 코드를 그대로 덮어쓰세요. 직접 고치기 시작하면 AI가 알고 있는 코드와 달라져서 다음 질문 때 엉뚱한 답을 줄 수 있습니다.

"AI는 지치지 않는 신입 개발자입니다." 우리가 팀장(Leader)이 되어 올바른 방향으로 계속 피드백을 주는 것이 AI Native 개발 방식입니다.


🧠 Visible Thinking Activity: 컴포넌트 쪼개기 (Component Hunting)

코딩을 하기 전에 '보는 눈'을 길러야 합니다.

  1. 링크드인이나 회사 소개 페이지를 켜세요.
  2. 화면 캡처를 해서 그림판에 붙여넣으세요.
  3. 반복되는 프로필 카드에 빨간 박스를 쳐보세요.
    • "어? 사진이랑 이름만 다르고 디자인은 똑같네?" -> ProfileCard 컴포넌트

Insight: 개발자는 웹사이트를 볼 때 페이지(Page)로 보지 않습니다. 부품(Component)의 집합으로 봅니다.


7. 팀 프로젝트 협업 가이드 (Bonus) 🤝

React 프로젝트를 협업으로 진행할 때, 업무 분할은 단순히 '누가 무엇을 만든다'를 넘어 "서로의 코드를 건드리지 않고 각자 독립적으로 일할 수 있는 구조"를 짜는 것이 핵심입니다.

일반적으로 현업에서 사용하는 3가지 분할 방식을 소개합니다.

7-1. 역할 중심 분할 (Function-based)

가장 전통적인 방식으로, 팀원의 강점에 따라 로직UI를 나누는 방식입니다.

  • 비즈니스 로직 담당 (Logic/Hook): API 통신, 데이터 가공, 상태 관리(State) 로직을 전담합니다. (src/hooks 폴더 작업 위주)
  • UI/퍼블리싱 담당 (Component): 디자인 가이드를 바탕으로 Tailwind CSS나 CSS 등을 활용해 실제 화면 부품을 만듭니다. (src/components 폴더 작업 위주)

장점: 전문성이 극대화됩니다. 한 명은 기능에, 한 명은 디자인에만 집중할 수 있습니다. 단점: 두 명의 코드가 합쳐질 때(Hook을 Component에 연결할 때) 소통 비용이 발생합니다.

7-2. 페이지/기능 중심 분할 (Feature-based) 🔥

가장 권장되는 방식으로, 특정 기능(화면) 단위로 통째로 떼어서 맡기는 방식입니다.

  • A 개발자: '팀원 목록 페이지'와 그에 필요한 '필터링 기능' 담당.
  • B 개발자: '마이페이지'와 '프로필 수정 기능' 담당.
  • 장점: 각자 맡은 폴더가 명확하므로 코드 충돌(Git Conflict)이 거의 발생하지 않습니다.
  • 단점: 공통으로 쓰이는 컴포넌트(예: 버튼, 입력창)를 중복으로 만들 위험이 있습니다.

7-3. 원자 단위 분할 (Atomic Design 기반)

프로젝트 규모가 클 때 사용하며, 공통 부품을 먼저 만드는 사람과 이를 조립하는 사람으로 나눕니다.

  1. 플랫폼/공통팀: 버튼, 인풋박스, 모달창 같은 기초 부품(Atoms)을 만듭니다.
  2. 서비스팀: 공통팀이 만든 부품을 가져다가 페이지(Page)를 조립하고 비즈니스 로직을 입힙니다.

🤝 협업을 위한 3가지 황금 규칙

업무를 나누기 전, 이 세 가지만 맞춰도 싸울 일이 80% 줄어듭니다.

① Interface(설계도) 먼저 합의하기

코딩 시작 전, 서로 주고받을 데이터 형식을 먼저 정하세요.

"내가 ProfileCardname이랑 isOnline 값을 넘길 건데, 변수명 이렇게 써도 괜찮아?"

② Git 전략 세우기

같은 파일을 동시에 고치면 Git 충돌이 납니다. 기능별 브랜치를 따서 작업하세요.

  • feature/team-list, feature/login-page 식으로 이름을 붙입니다.

③ 디자인 시스템(Tailwind) 규칙 정하기

"여백(Padding)은 4의 배수만 쓰자", "브랜드 컬러는 blue-500으로 통일하자" 같은 약속을 미리 정해야 화면이 누더기가 되지 않습니다.

🏫 Visible Thinking: 협업 워크플로우

sequenceDiagram
    participant Leader as 팀장 (설계)
    participant Dev_A as 개발자 A (UI)
    participant Dev_B as 개발자 B (Logic)

    Leader->>Leader: Typescript Interface 정의 (공통 규격)
    Note over Dev_A, Dev_B: 공유된 Interface를 바탕으로 각자 작업 시작
    Dev_A->>Dev_A: 컴포넌트 마크업 & CSS 작업
    Dev_B->>Dev_B: API 연동 및 Custom Hook 개발
    Dev_A->>Leader: UI 완성 (Pull Request)
    Dev_B->>Leader: 로직 완성 (Pull Request)
    Leader->>Leader: 두 코드를 조립 (Integration)