useRef() Hook을 이용해 DOM을 참조<form> 사용 자제 → 서버 제출 시 깨질 수 있음app/폴더/layout.jslayout.js 파일을 가질 경우 중첩 레이아웃이 됨{}를 사용"19"로 쓰면 문자열 타입으로 전달됨. 문자열도 {}로 감쌀 수 있음개념: 부모 컴포넌트가 자식 컴포넌트에게
name,version속성을 props로 전달하고,자식 컴포넌트는 구조 분해 할당으로 받아서 렌더링하는 기본 props 전달 패턴
부모 컴포넌트 — props를 넘겨주는 쪽
import ChildComponent from "./ChildComponent";
function Exam01Props() {
return (
<div className="card">
<div className="card-header">Exam01Props</div>
<div className="card-body">
{/* name은 문자열, version은 숫자({}로 감쌈), 태그 사이 내용은 children으로 전달됨 */}
<ChildComponent name="React" version={19}>
<div>자식 내용입니다.</div>
</ChildComponent>
</div>
</div>
);
}
export default Exam01Props;
props 객체 구조 — 자식 컴포넌트가 실제로 받는 객체 형태
{
name: "React", // 문자열
version: 19, // 숫자 ({}로 전달했기 때문)
children: "<div>자식 내용입니다.</div>" // 태그 사이 내용은 자동으로 children에 담김
}
자식 컴포넌트 — props를 받아서 사용하는 쪽
// 매개변수에서 구조 분해 할당으로 props를 바로 꺼내 씀
// version=18 → 부모에서 version을 안 넘겨주면 기본값 18로 사용
function ChildComponent({ name, version = 18, children }) {
return (
<div className="card">
<div className="card-header">ChildComponent</div>
<div className="card-body">
<div>프레임워크: {name}</div>
<div>버전: {version}</div>
<div>버전 타입: {typeof version}</div> {/* 숫자로 전달됐는지 확인 */}
{children} {/* 부모 태그 사이에 작성한 내용이 여기 렌더링됨 */}
</div>
</div>
);
}
export default ChildComponent;
useState를 사용한다"use client" 필요useEffect 활용)개념: 상태가 객체일 때 스프레드 연산자(
...)로 기존 값을 복사한 뒤,변경할 속성만 덮어씌워 완전히 새로운 객체로 setState하는 패턴
"use client";
import { useState } from "react";
function Exam03ObjectTypeState() {
// 상태를 객체로 정의 - number와 color를 하나의 상태로 묶어서 관리
const [state, setState] = useState({
number: 0,
color: "black",
});
const addNumber = () => {
// ...state로 기존 객체 복사 후, number만 +1한 새 객체 생성
// color는 건드리지 않고 그대로 유지됨
setState({ ...state, number: state.number + 1 });
};
const changeColor = () => {
// ...state로 기존 객체 복사 후, color만 랜덤값으로 덮어씀
// number는 건드리지 않고 그대로 유지됨
setState({ ...state, color: getRandomColor() });
};
// 랜덤 hex 색상 생성 함수
// Math.random() → 0~1 사이 소수
// parseInt("ffffff", 16) → 16진수 ffffff를 10진수로 변환 (= 16777215)
// 곱한 후 floor로 정수화 → toString(16)으로 다시 16진수 문자열로 변환
const getRandomColor = () => {
return "#" + Math.floor(Math.random() * parseInt("ffffff", 16)).toString(16);
};
return (
<div className="card mt-2">
<div className="card-header">Exam03ObjectTypeState</div>
<div className="card-body">
<button onClick={addNumber} className="btn btn-info btn-sm me-2">숫자 증가</button>
<button onClick={changeColor} className="btn btn-info btn-sm me-2">색깔 변경</button>
<hr />
{/* state.color를 인라인 스타일로 적용, state.number를 텍스트로 출력 */}
<h3 style={{ color: state.color }}>{state.number}</h3>
</div>
</div>
);
}
export default Exam03ObjectTypeState;
개념: 여러 input을 하나의 핸들러 함수로 통합 관리하는 패턴.
event.target을 이용해 어떤 input에서 이벤트가 발생했는지 판별한다.
이벤트가 실제로 발생한 DOM 요소를 가리킨다.
<input> 태그에 onChange가 발생하면 event.target은 그 <input> 요소 자체다.
| 속성 | 의미 | 예시 |
|---|---|---|
event.target | 이벤트가 발생한 DOM 요소 | <input name="age" value="25"> |
event.target.name | 그 요소의 name 속성값 | "age" |
event.target.value | 그 요소의 현재 입력값 | "25" |
// input 태그에 name 속성을 붙여두면
// 어떤 input에서 이벤트가 발생했는지 event.target.name으로 구별 가능
const handleChange = (event) => {
console.log(`${event.target.name}: ${event.target.value}`);
// 예: "age: 25", "username: hello" 처럼 출력됨
};
// [event.target.name] → 대괄호 안에 변수를 넣으면 그 변수의 값이 키로 사용됨
// event.target.name이 "age"이면 → { ...user, age: "25" } 와 동일
setUser({ ...user, [event.target.name]: event.target.value });
// 비교: 대괄호 없이 쓰면 "event.target.name" 이라는 문자열 그대로 키가 됨 (잘못된 사용)
// setUser({ ...user, event.target.name: event.target.value }); ❌
실제 사용 예시 — input이 여러 개여도 핸들러 함수 하나로 처리
// name 속성이 상태 객체의 키와 일치해야 함
<input name="username" onChange={handleChange} />
<input name="age" onChange={handleChange} />
<input name="email" onChange={handleChange} />
✅ 앞으로 form 입력 데이터는 상태로 관리하기!
개념: Setter가 비동기로 동작하기 때문에 같은 상태를 연속으로 여러 번 바꾸려면
값 대신 함수를 전달해야 한다.
function Exam05RepeatUpdate() {
const [number, setNumber] = useState(0);
// ❌ 값 전달 방식 - 두 번 호출해도 +1만 됨
// setNumber가 비동기라 두 번째 호출 시점에도 number는 아직 이전 값
// → setNumber(0 + 1), setNumber(0 + 1) 로 동일하게 실행됨
const addNumber1 = () => {
setNumber(number + 1);
setNumber(number + 1);
};
// ✅ 함수 전달 방식 - 두 번 호출하면 +2 됨
// React가 함수들을 큐에 쌓아 순서대로 실행
// prevNumber는 직전 업데이트가 반영된 최신값을 보장
// → setNumber(0→1), setNumber(1→2) 순차 실행
const addNumber2 = () => {
setNumber(prevNumber => prevNumber + 1);
setNumber(prevNumber => prevNumber + 1);
};
}
| 방식 | 설명 |
|---|---|
addNumber1 | number를 그 시점의 값으로 읽어 업데이트 → 두 번 호출해도 +1만 됨 |
addNumber2 | 함수를 전달 → 차곡차곡 쌓여 순차적으로 업데이트 → +2 됨 |
| Hook | 설명 |
|---|---|
useState() | 상태 생성 및 초기화 |
useEffect() | 상태 변경 후 콜백 함수 등록 |
useRef() | DOM 직접 참조 |
Hook:
use로 시작하며 컴포넌트의 상태, 생명주기 등을 함수형 컴포넌트에서 사용할 수 있게 해주는 특별한 함수