1. 오늘 한 것 (What I Did)
- Props 전달하는 부분 해부
- 이벤트 핸들러의 'e' 매개변수 이해
2. 새로 이해한 것 (What I Learned)
Props는 "함수의 인자"와 똑같다!
// 일반 JavaScript 함수
function greet(name, age) {
return `안녕하세요, ${age}살 ${name}님!`;
}
greet("철수", 25); // 함수 호출 시 인자 전달
// React 컴포넌트 (똑같은 원리!)
function Welcome(props) {
return <h1>안녕하세요, {props.age}살 {props.name}님!</h1>;
}
// 컴포넌트 사용 시 props 전달
<Welcome name="철수" age={25} />
Props 전달 과정 step by step
// 1단계: 부모 컴포넌트에서 데이터 준비
function App() {
const userName = "김철수";
const userAge = 30;
const isLoggedIn = true;
return (
<div>
{/* 2단계: 자식 컴포넌트에 props로 전달 */}
<UserCard
name={userName} // name이라는 이름으로 전달
age={userAge} // age라는 이름으로 전달
loggedIn={isLoggedIn} // loggedIn이라는 이름으로 전달
/>
</div>
);
}
// 3단계: 자식 컴포넌트에서 props 받기
function UserCard(props) {
// props는 객체 형태로 받아짐:
// props = {
// name: "김철수",
// age: 30,
// loggedIn: true
// }
return (
<div>
<h2>{props.name}</h2> {/* props.name으로 접근 */}
<p>나이: {props.age}</p>
<p>상태: {props.loggedIn ? "로그인됨" : "로그아웃됨"}</p>
</div>
);
}
구조 분해 할당으로 더 깔끔하게
// 방법 1: props 객체 그대로 받기
function UserCard(props) {
return <h1>{props.name}</h1>;
}
// 방법 2: 구조 분해 할당 (더 많이 사용)
function UserCard({ name, age, loggedIn }) {
// 이제 props. 없이 직접 사용 가능!
return (
<div>
<h2>{name}</h2>
<p>나이: {age}</p>
<p>상태: {loggedIn ? "로그인됨" : "로그아웃됨"}</p>
</div>
);
}
Props 전달 다양한 방법들
function App() {
const user = {
name: "홍길동",
age: 25,
email: "hong@example.com"
};
const colors = ["red", "blue", "green"];
return (
<div>
{/* 문자열 전달 */}
<Component title="안녕하세요" />
{/* 숫자 전달 (중괄호 필요!) */}
<Component count={42} />
{/* 변수 전달 */}
<Component userName={user.name} />
{/* 객체 전달 */}
<Component user={user} />
{/* 배열 전달 */}
<Component colors={colors} />
{/* 불린값 전달 */}
<Component isVisible={true} />
<Component isHidden /> {/* true와 같음 */}
{/* 함수 전달 */}
<Component onSave={() => console.log("저장됨")} />
</div>
);
}
function Component({ title, count, userName, user, colors, isVisible, onSave }) {
return (
<div>
<h1>{title}</h1>
<p>카운트: {count}</p>
<p>사용자: {userName}</p>
<p>이메일: {user.email}</p>
<p>첫 번째 색: {colors[0]}</p>
{isVisible && <span>보임!</span>}
<button onClick={onSave}>저장</button>
</div>
);
}
'e'는 이벤트 객체! React가 자동으로 전달해줌
function InputExample() {
function handleChange(e) {
// e는 이벤트 객체 - React가 자동으로 전달
console.log("이벤트 객체:", e);
console.log("입력된 값:", e.target.value);
console.log("이벤트 타입:", e.type); // "change"
console.log("발생한 요소:", e.target); // input 요소
}
function handleClick(e) {
console.log("클릭 위치 X:", e.clientX);
console.log("클릭 위치 Y:", e.clientY);
console.log("클릭된 요소:", e.target);
}
return (
<div>
{/* React가 자동으로 이벤트 객체를 handleChange에 전달 */}
<input onChange={handleChange} />
<button onClick={handleClick}>클릭</button>
</div>
);
}
이벤트 객체 안에 뭐가 들어있나?
function EventAnalyzer() {
function handleInputChange(e) {
console.log("=== 이벤트 객체 분석 ===");
// 가장 중요한 것들
console.log("입력값:", e.target.value); // 현재 입력값
console.log("요소 이름:", e.target.name); // input의 name 속성
console.log("요소 타입:", e.target.type); // input의 type 속성
// 키보드 이벤트에서 유용한 것들
console.log("눌린 키:", e.key); // 어떤 키가 눌렸는지
console.log("Ctrl 키:", e.ctrlKey); // Ctrl 키가 눌려있는지
console.log("Shift 키:", e.shiftKey); // Shift 키가 눌려있는지
}
function handleSubmit(e) {
e.preventDefault(); // 기본 동작 막기 (페이지 새로고침 방지)
console.log("폼 제출 처리");
}
return (
<form onSubmit={handleSubmit}>
<input
name="username"
type="text"
onChange={handleInputChange}
onKeyDown={handleInputChange}
/>
<button type="submit">제출</button>
</form>
);
}
이벤트 객체 없이 쓸 때 vs 있을 때
function ComparisonExample() {
const [count, setCount] = useState(0);
const [message, setMessage] = useState('');
// 이벤트 객체가 필요 없는 경우
function simpleClick() {
setCount(count + 1); // 단순히 count만 증가
}
// 이벤트 객체가 필요한 경우
function inputChange(e) {
setMessage(e.target.value); // 입력값이 필요하므로 e.target.value 사용
}
function keyPress(e) {
if (e.key === 'Enter') { // 어떤 키가 눌렸는지 확인 필요
console.log("엔터 키 눌림!");
}
}
return (
<div>
{/* 이벤트 객체 필요 없음 */}
<button onClick={simpleClick}>카운트: {count}</button>
{/* 이벤트 객체 필요함 */}
<input
value={message}
onChange={inputChange} // e.target.value 필요
onKeyDown={keyPress} // e.key 필요
/>
</div>
);
}
이벤트 객체와 다른 인자를 함께 사용하기
function AdvancedExample() {
function handleDelete(id, e) {
e.stopPropagation(); // 이벤트 버블링 방지
console.log(`${id}번 항목 삭제`);
}
function handleSave(formData, e) {
e.preventDefault(); // 기본 폼 제출 방지
console.log("저장할 데이터:", formData);
}
return (
<div>
{/* 이벤트 객체와 다른 인자를 함께 전달 */}
<button onClick={(e) => handleDelete(123, e)}>
삭제
</button>
<form onSubmit={(e) => handleSave({name: "test"}, e)}>
<button type="submit">저장</button>
</form>
</div>
);
}
3. 실전 예제 - Props와 이벤트를 함께
// 부모 컴포넌트
function TodoApp() {
const [todos, setTodos] = useState([
{ id: 1, text: "공부하기", done: false }
]);
// 자식에게 전달할 함수들
function handleToggle(id) {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, done: !todo.done } : todo
));
}
function handleDelete(id) {
setTodos(todos.filter(todo => todo.id !== id));
}
return (
<div>
{todos.map(todo => (
<TodoItem
key={todo.id}
todo={todo} // 객체 prop 전달
onToggle={handleToggle} // 함수 prop 전달
onDelete={handleDelete} // 함수 prop 전달
/>
))}
</div>
);
}
// 자식 컴포넌트
function TodoItem({ todo, onToggle, onDelete }) {
// 이벤트 핸들러들
function handleToggleClick() {
onToggle(todo.id); // 부모의 함수 호출
}
function handleDeleteClick(e) {
e.stopPropagation(); // 이벤트 버블링 방지
onDelete(todo.id); // 부모의 함수 호출
}
return (
<div onClick={handleToggleClick}>
<span style={{
textDecoration: todo.done ? 'line-through' : 'none'
}}>
{todo.text}
</span>
<button onClick={handleDeleteClick}>삭제</button>
</div>
);
}
Props 이해하기
- Props = 함수의 인자: 부모가 자식에게 데이터 전달하는 방법
- 전달: <Component name="값" age={숫자} />
- 받기: function Component({ name, age }) { ... }
이벤트 객체 'e' 이해하기
- 자동 전달: React가 이벤트 핸들러에 자동으로 전달
- 주요 속성: e.target.value, e.key, e.preventDefault()
- 선택적 사용: 필요할 때만 매개변수로 받으면 됨