React의 동적 측면 마스터하기: State, Events, and Conditional Rendering! (React Day 3)
I’m happy to translate the article for you, but I don’t have the article’s text in the message. Could you please paste the content you’d like translated (excluding any code blocks or URLs you want to keep unchanged)? Once I have the text, I’ll provide the Korean translation while preserving the original formatting and markdown.
상태 관리: 로컬 데이터를 위한 useState 소개
State는 React가 시간에 따라 변하는 데이터를 기억하는 방법입니다—예를 들어 카운터 값이나 폼 입력값처럼. 부모 컴포넌트에서 전달되는 props와 달리, state는 컴포넌트에 프라이빗하게 존재하며 업데이트될 때마다 리렌더링을 트리거합니다.
useState는 훅(후에 훅에 대해 더 자세히 다룹니다)으로, 상태 변수와 그 값을 업데이트하는 setter 함수를 제공합니다. React에서 다음과 같이 임포트합니다:
import { useState } from 'react';
작동 방식
const [value, setValue] = useState(initialValue);
value는 읽기 전용입니다.- 값을 변경하려면
setValue를 호출합니다.
실시간 예제: 간단한 카운터
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
버튼을 클릭하면 → state가 업데이트되고 → 컴포넌트가 새로운 카운트와 함께 리렌더링됩니다.
실제 예제: 입력값을 추적하는 로그인 폼
import { useState } from 'react';
function LoginForm() {
const [username, setUsername] = useState('');
return (
<input
type="text"
value={username}
onChange={e => setUsername(e.target.value)}
placeholder="Username"
/>
);
}
State가 입력값을 동기화해 주어, 제출 준비가 언제든 가능하도록 합니다.
흔히 저지르는 실수
- 직접 변이 –
count++와 같이 직접 값을 증가시켜도 리렌더링이 일어나지 않습니다. 반드시 setter를 사용하세요. - setter 생략 –
setValue없이 변수를 업데이트하면 아무 일도 일어나지 않습니다.
디버깅 팁
console.log('Current count:', count);
컴포넌트 내부에 로그를 배치하면 각 렌더링 시점에 현재 값을 확인할 수 있습니다. 리렌더링은 비동기적으로 발생한다는 점을 기억하세요.
이벤트 처리: 사용자 행동에 응답하기
React의 이벤트는 HTML처럼 보이지만 camelCase(예: onClick)를 사용하고 함수 레퍼런스를 받습니다.
비유: 초인종에 리스너를 붙이는 것—사용자가 “울리면”(클릭하면) 코드가 반응합니다.
실시간 예제 (Counter에서)
<button onClick={() => setCount(count + 1)}>Increment</button>
폼 이벤트
onChange– 입력 변화 감지.onSubmit– 폼 제출 처리.
실제 예제: Todo 앱에서 아이템 추가하기
import { useState } from 'react';
function TodoForm({ addTodo }) {
const [text, setText] = useState('');
const handleSubmit = e => {
e.preventDefault(); // 페이지 새로고침 방지
addTodo(text);
setText(''); // 입력란 비우기
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={text}
onChange={e => setText(e.target.value)}
placeholder="New todo"
/>
<button type="submit">Add</button>
</form>
);
}
흔히 하는 실수
- 폼에서
e.preventDefault()를 빼먹음 → 페이지가 새로고침됩니다. - 매 렌더마다 무거운 인라인 함수를 정의함 →
useCallback사용이나 함수를 별도로 추출하는 것을 고려하세요.
디버깅 팁
React DevTools를 열고, 컴포넌트의 props와 state를 확인한 뒤 이벤트 객체를 로그하세요:
const handleClick = e => {
console.log(e);
// …your logic
};
조건부 렌더링: 표시/숨기기 기반 로직
조건에 따라 다른 UI를 렌더링합니다—일반 JavaScript의 if/else와 동일합니다.
방법
| Technique | Syntax |
|---|---|
| 삼항 연산자 | {condition ? <A /> : <B />} |
| 단축 평가 | {condition && <A />} |
| 조기 반환 | if (!condition) return null; |
실시간 예제: 토글 가시성
import { useState } from 'react';
function Toggle() {
const [isVisible, setIsVisible] = useState(false);
return (
<div>
<button onClick={() => setIsVisible(!isVisible)}>Toggle</button>
{isVisible && <p>Now you see me!</p>}
</div>
);
}
실제 예제: 로딩 스피너
import { useState, useEffect } from 'react';
function DataFetcher() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('/api/data')
.then(res => res.json())
.then(json => {
setData(json);
setLoading(false);
});
}, []);
return loading ? (
<p>Loading...</p>
) : (
<pre>{JSON.stringify(data)}</pre>
);
}
흔히 하는 실수
if문을 JSX 반환 바깥에 배치하는 경우—JSX는 표현식이므로 삼항 연산자나 단축 평가를 내부에서 사용하세요.- 깊게 중첩된 조건문 → 가독성을 위해 별도 컴포넌트로 추출합니다.
동적 UI 업데이트: 모든 것을 하나로
상태, 이벤트, 그리고 조건문을 결합하여 사용자에게 반응하는 UI를 만들기—예를 들어, 입력할 때마다 업데이트되는 필터 가능한 리스트.
실제 예시: 검색 폼
import { useState } from 'react';
function SearchList() {
const [query, setQuery] = useState('');
const items = ['Apple', 'Banana', 'Cherry'];
const filtered = items.filter(item =>
item.toLowerCase().includes(query.toLowerCase())
);
return (
<div>
<input
type="text"
value={query}
onChange={e => setQuery(e.target.value)}
placeholder="Search fruits"
/>
<ul>
{filtered.length ? (
filtered.map(item => <li key={item}>- {item}</li>)
) : (
<li>No results</li>
)}
</ul>
</div>
);
}
입력 → onChange가 query를 업데이트 → filtered가 다시 계산 → JSX가 일치하는 리스트를 다시 렌더링.
Source:
React가 컴포넌트를 다시 렌더링하는 방법
state 또는 props가 변경되면 React는:
- 컴포넌트 함수를 다시 실행합니다.
- 새로운 가상 DOM 트리를 생성합니다.
- 새 트리를 이전 트리와 비교합니다.
- 실제 DOM에 필요한 변경 사항만 적용합니다.
비유
스케치를 다시 그리는 것과 같습니다: 변경된 부분만 지우고 다시 그립니다.
렌더 사이클 시각화
다이어그램은 state/prop 변경 → render → commit → 브라우저 페인팅 흐름을 보여줍니다.
핵심 포인트
- 불변성 – 상태는 항상 불변으로 다루세요; React는 참조 변화로 업데이트를 감지합니다.
- 배칭 – 같은 이벤트 루프 내에서 여러 상태 업데이트가 하나의 렌더링으로 배치되어 성능이 향상됩니다.
- 메모이제이션 –
React.memo,useMemo,useCallback을 사용해 불필요한 재렌더링을 방지하세요.
디버깅 팁
React DevTools에서 “Highlight updates” 옵션을 활성화하면 상태 변경 후 어떤 컴포넌트가 다시 렌더링되는지 확인할 수 있습니다. 여기에 console.log 문을 추가하면 렌더 흐름을 추적할 수 있습니다.
🎉 준비 완료!
이제 React 컴포넌트를 상태가 있는, 인터랙티브한, 그리고 동적인으로 만들 수 있는 핵심 도구들을 갖추었습니다. 예제들을 실험해보고, 문제를 일으킨 뒤 다시 고쳐보세요—그 과정에서 배움이 이루어집니다. 즐거운 코딩 되세요!
상태 및 라이프사이클 개요

디버깅 팁: React DevTools Profiler를 사용하여 렌더링을 기록하고 불필요한 렌더링을 찾아보세요.
State Immutability – Why You Can’t Mutate Directly
State는 읽기 전용으로 다루어야 합니다. 상태를 변형하면(e.g., array.push(item)) React에 알리지 않으므로 UI가 업데이트되지 않습니다.
- 왜? React는 변경을 감지하기 위해 참조 동일성을 확인합니다. 변형은 동일한 참조를 유지하므로 React는 재렌더링을 건너뜁니다.
- 베스트 프랙티스: 상태를 업데이트할 때는 새로운 객체/배열을 생성하세요.
// ❌ Mutating the original array
array.push(item);
setArray(array);
// ✅ Creating a new array
setArray([...array, item]);

흔한 실수: 중첩된 객체를 변형하는 것입니다. 깊은 복사 또는 Immer와 같은 라이브러리를 사용하세요.
배치 – 효율성을 위한 업데이트 그룹화
React는 이벤트 핸들러나 라이프사이클 메서드 내부에서 특히 여러 상태 업데이트를 자동으로 배치하여 하나의 재렌더링으로 처리합니다.
// Both updates are batched → count increases by 2 in one render
setCount(c => c + 1);
setCount(c => c + 1);
- 왜? DOM 과다 업데이트를 줄이고 성능을 향상시킵니다.
- 주의점: 비동기 코드에서는 업데이트가 즉시 적용되지 않습니다. 상태가 변경된 후에 동작이 필요하면 콜백이나
useEffect를 사용하세요.
Props vs. State – 핵심 비교
| 측면 | Props | State |
|---|---|---|
| Source | 부모 컴포넌트에서 아래로 전달됨 | 컴포넌트 내부에서 관리됨 |
| Mutability | 읽기 전용 – 자식이 변경할 수 없음 | 변경 가능 – setter 함수(setX)를 통해 |
| Trigger | Props가 변경되면 자식이 다시 렌더링됨 | State가 변경되면 컴포넌트와 그 자식들이 다시 렌더링됨 |
| Analogy | 부모에게 받은 선물 – 변경할 수 없음 | 자신의 지갑 – 사용하거나 추가할 수 있음 |

- Props를 사용할 때: 설정 데이터, 부모로부터 전달되는 값, 혹은 자식 내부에서 불변이어야 하는 모든 것.
- State를 사용할 때: 사용자 상호작용, 네트워크 응답, 타이머 등으로 시간에 따라 변하는 데이터.
- 흔한 실수: 파생 데이터를 state에 저장하는 것. 대신 props/state에서 즉시 계산하여 동기화 버그를 방지하세요.
디버깅 팁: UI가 업데이트되지 않을 경우, render 함수 안에서 props와 state를 모두 로그에 출력해 기대값이 들어있는지 확인하세요.
마무리 – React 앱이 살아나다
이제 다음을 마스터했습니다:
- State – 불변 업데이트, 배칭, 디버깅.
- Props – 부모에서 자식으로의 단방향 데이터 흐름.
- Lifecycle basics – 컴포넌트가 마운트, 업데이트, 언마운트되는 시점.
이러한 개념은 카운터, 폼, 대시보드, 채팅 인터페이스와 같은 실제 기능을 구현합니다.
다음 단계: Day 4 – Lists, Keys, and Effects.
연습 아이디어: 사용자가 항목을 추가, 편집, 삭제할 수 있는 동적 todo list를 만들어 보세요. 다음을 기억하세요:
- 원본 리스트를 절대 변형하지 말고; 항상 새로운 배열을 생성하세요.
- 배칭을 활용하여 여러 상태 변경이 이전 상태에 의존할 때 함수형 업데이트를 사용하세요.
- 키를 올바르게 사용하여 리스트 항목이 안정적으로 유지되도록 하세요.
즐거운 코딩 되세요, 그리고 계속 React 하세요! 🚀
