ReactReact 기초강의 10개 중 2번째난이도 기초

Props와 State — 데이터 전달과 상태 관리

발행 읽는 시간 약 1 분

  • React
  • props
  • state
  • useState
  • 리렌더링

강의 소개

props로 컴포넌트에 데이터를 전달하고, useState로 컴포넌트 내부 상태를 관리하는 방법을 배웁니다. 불변성과 리렌더링 원리도 이해합니다.

Props: 데이터 전달#

Props는 부모 컴포넌트가 자식에게 전달하는 데이터입니다.

TSX
// 자식 컴포넌트
interface UserCardProps {
    name: string;
    email: string;
    avatar?: string;
    isAdmin?: boolean;
}

function UserCard({ name, email, avatar, isAdmin = false }: UserCardProps) {
    return (
        <div className="card">
            {avatar && <img src={avatar} alt={name} />}
            <h3>{name}</h3>
            <p>{email}</p>
            {isAdmin && <span className="badge">관리자</span>}
        </div>
    );
}

// 부모 컴포넌트
function App() {
    return (
        <div>
            <UserCard name="철수" email="kim@example.com" isAdmin />
            <UserCard name="영희" email="lee@example.com" />
        </div>
    );
}

Props는 읽기 전용#

TSX
function BadComponent({ count }: { count: number }) {
    // count = count + 1;  // ❌ props 직접 수정 금지
    return <div>{count}</div>;
}

children props#

TSX
interface CardProps {
    title: string;
    children: React.ReactNode;  // JSX를 받는 타입
}

function Card({ title, children }: CardProps) {
    return (
        <div className="card">
            <h2>{title}</h2>
            <div className="content">{children}</div>
        </div>
    );
}

// 사용
<Card title="프로필">
    <p>이름: 철수</p>
    <p>이메일: kim@example.com</p>
</Card>

useState: 상태 관리#

TSX
import { useState } from "react";

function Counter() {
    // [현재값, 변경함수] = useState(초기값)
    const [count, setCount] = useState(0);

    return (
        <div>
            <p>카운트: {count}</p>
            <button onClick={() => setCount(count + 1)}>+</button>
            <button onClick={() => setCount(count - 1)}>-</button>
            <button onClick={() => setCount(0)}>초기화</button>
        </div>
    );
}

상태 업데이트 원리#

Diagram · Mermaid
TSX
// 함수형 업데이트 (이전 값 기반)
setCount(prevCount => prevCount + 1);

// 배치 업데이트 (React 18)
// 여러 setState가 하나의 리렌더링으로 처리됨
function handleClick() {
    setCount(c => c + 1);  // 이 두 개가
    setName("새 이름");    // 하나의 리렌더링으로 처리
}

객체 상태: 불변성#

TSX
interface UserForm {
    name: string;
    email: string;
    age: number;
}

function UserFormComponent() {
    const [form, setForm] = useState<UserForm>({
        name: "",
        email: "",
        age: 0,
    });

    function handleChange(field: keyof UserForm, value: string | number) {
        // ❌ 직접 수정 — React가 변경을 감지하지 못함
        // form.name = "새 이름";

        // ✅ 스프레드로 새 객체 생성
        setForm(prev => ({ ...prev, [field]: value }));
    }

    return (
        <form>
            <input
                value={form.name}
                onChange={e => handleChange("name", e.target.value)}
            />
        </form>
    );
}

배열 상태: 불변성#

TSX
function TodoList() {
    const [todos, setTodos] = useState<string[]>([]);
    const [input, setInput] = useState("");

    function addTodo() {
        if (!input.trim()) return;
        // ✅ 새 배열 생성
        setTodos(prev => [...prev, input]);
        setInput("");
    }

    function removeTodo(index: number) {
        // ✅ filter로 새 배열
        setTodos(prev => prev.filter((_, i) => i !== index));
    }

    return (
        <div>
            <input value={input} onChange={e => setInput(e.target.value)} />
            <button onClick={addTodo}>추가</button>
            <ul>
                {todos.map((todo, i) => (
                    <li key={i}>
                        {todo}
                        <button onClick={() => removeTodo(i)}>삭제</button>
                    </li>
                ))}
            </ul>
        </div>
    );
}

State 끌어올리기 (Lifting State Up)#

두 컴포넌트가 같은 상태를 공유해야 할 때, 공통 부모로 상태를 올립니다.

TSX
function TemperatureConverter() {
    const [celsius, setCelsius] = useState(0);

    const fahrenheit = (celsius * 9) / 5 + 32;

    return (
        <div>
            <input
                type="number"
                value={celsius}
                onChange={e => setCelsius(Number(e.target.value))}
            />
            <span>°C = {fahrenheit.toFixed(1)}°F</span>
        </div>
    );
}

정리#

개념특징
props부모 → 자식, 읽기 전용
childrenJSX를 props로 전달
useState컴포넌트 내부 상태
불변성직접 수정 금지, 새 객체/배열 생성
State 끌어올리기공유 상태는 공통 부모로

다음 편에서는 이벤트 처리 — 클릭, 입력, 폼 제출 등 다양한 이벤트를 다루는 방법을 배웁니다.

Follow · Ask · Work

이 글이 도움이 됐다면

짧은 작업 기록과 데모는 인스타그램에 올립니다. 만들고 싶은 것이 있다면 프로젝트 의뢰나 협업 제안도 편하게 보내 주세요.

글쓴이

파란여우

직접 만든 AI 앱·제품의 개발·배포를 공개하는 실전형 테크 크리에이터

파란여우 소개 Instagram @bluefox._.hi

이어서 보기

만들고 싶은 것이 있다면 프로젝트 의뢰로 알려 주세요.