명함 입력 폼 만들기

튜토리얼 — 명함 입력 폼 만들기
SignupForm은 name과 email 두 칸이었습니다. 입력이 세 칸으로 늘면 객체 상태와 펼침 연산자가 더 가치를 합니다. 같은 패턴을 다른 모양에 그대로 옮겨 봅니다 — 이름·회사·직책 세 칸을 받아, 아래에 명함 미리보기를 띄우는 화면입니다.
개념
입력칸이 늘어도 패턴은 똑같습니다.
- 관련된 입력값들은 객체 하나로 묶고 —
{ name, company, role } - 한 칸만 바꿀 땐 펼침 연산자로 나머지를 그대로 두고 —
{ ...card, name: 새값 }
핵심은 ...card입니다. 이걸 빼먹고 setCard({ name: 새값 })이라고만 하면 company와 role이 사라져 버려요. 객체 상태를 바꿀 땐 항상 "기존을 펼친 다음, 바꿀 칸만 덮어쓴다" — 이 한 줄을 손에 익히는 게 이번 연습의 목표입니다.
함께 해보기
1단계 — BusinessCard 컴포넌트 만들기
components/BusinessCard.tsx를 만듭니다.
"use client"; import { useState } from "react"; type Card = { name: string; company: string; role: string; }; export default function BusinessCard() { const [card, setCard] = useState<Card>({ name: "", company: "", role: "", }); return ( <div className="p-4 space-y-3"> <input className="block w-full border px-2 py-1" value={card.name} onChange={(e) => setCard({ ...card, name: e.target.value })} placeholder="이름" /> <input className="block w-full border px-2 py-1" value={card.company} onChange={(e) => setCard({ ...card, company: e.target.value })} placeholder="회사" /> <input className="block w-full border px-2 py-1" value={card.role} onChange={(e) => setCard({ ...card, role: e.target.value })} placeholder="직책" /> {/* 미리보기 명함 */} <div className="mt-4 rounded border-2 border-gray-300 bg-white p-4 shadow"> <p className="text-lg font-bold">{card.name || "(이름)"}</p> <p className="text-sm text-gray-600"> {card.role || "(직책)"} · {card.company || "(회사)"} </p> </div> </div> ); }
세 칸 모두 같은 모양입니다.
value={card.이름}— 객체에서 해당 칸을 읽어 표시onChange={(e) => setCard({ ...card, 이름: e.target.value })}— 기존을 펼치고 그 칸만 바꾸기
SignupForm이 두 줄이던 게 세 줄이 됐을 뿐, 패턴은 한 글자도 다르지 않습니다. 미리보기는 card.name || "(이름)"처럼 빈 문자열일 때 안내 글자가 나오게 했어요 — 빈 문자열은 falsy라 || 뒤 값이 쓰입니다.
2단계 — 페이지에 올리기
app/card/page.tsx를 만듭니다.
import BusinessCard from "@/components/BusinessCard"; export default function CardPage() { return ( <main style={{ padding: 24 }}> <h2>명함 만들기</h2> <BusinessCard /> </main> ); }
3단계 — 확인
/card를 엽니다.
- 처음엔 미리보기에
(이름),(직책) · (회사)가 보입니다. - 이름부터 입력해 봅니다 → 미리보기의 굵은 글자가 그대로 따라옵니다 ✅
- 그 상태에서 회사도 입력합니다 → 이름은 그대로 있고, 회사 자리만 채워집니다 ✅
- 마지막으로 직책도 입력 → 셋 다 미리보기에 나타납니다 ✅
확인 ✅ — 회사칸에 글자를 칠 때 이름이 사라지지 않는 게 보이시나요? 그게 바로 ...card의 역할입니다. 한 칸을 바꿔도 다른 칸은 그대로 유지돼요. 만약 onChange를 setCard({ company: e.target.value })라고 쓰면 (펼침을 빼면), 회사에 한 글자 칠 때마다 이름·직책이 빈 칸으로 돌아가는 걸 볼 수 있습니다. 한 번 일부러 빼 보고 다시 넣어 보세요 — 펼침 연산자가 왜 필요한지 손에 박힙니다.
정리
- 입력칸이 두 개든 세 개든, 하나의 객체 상태로 묶는 패턴은 같습니다.
- 한 칸만 바꿀 때는
{ ...기존, 그칸: 새값 }으로 — 기존을 펼친 다음 그 칸을 덮어씁니다. - 펼침을 빼면 다른 칸들이 사라집니다. 객체를 통째로 새로 만들어 주는 게 React가 변화를 알아채는 방식이라 그래요.
연습 거리
- 이메일 칸 하나 더 추가하기 — 타입에 한 줄, 입력 하나, 똑같은 onChange 한 번 더. 패턴이 그대로인지 확인.
- "지우기" 버튼 만들기 —
onClick={() => setCard({ name: "", company: "", role: "" })}로 객체를 통째로 갈아끼우기 (이때는 펼침이 필요 없음 — 전부 다시 만드는 거니까) - 미리보기를
card.name && <p>...</p>처럼 있을 때만 줄을 보여 주도록 조건부 렌더링으로 바꿔 보기

댓글
댓글을 작성하려면 이 필요합니다.