컴포넌트에 props 전달하기
부모 컴포넌트는 props를 줌으로써 자식 컴포넌트에게 정보를 전달 가능
✔️ 친숙한 props
props : JSX 태그에 전달하는 정보
function Avatar() {
return (
<img
className="avatar"
src="https://i.imgur.com/1bX5QH6.jpg"
alt="Lin Lanying"
width={100}
height={100}
/>
);
}
export default function Profile() {
return (
<Avatar />
);
}
^ className, src, alt, width, height와 같은 속성은 <img> 태그에 전달 가능
✔️ 컴포넌트에 props 전달하기
export default function Profile() {
return (
<Avatar />
);
}
^ 어떠한 props도 전달하지 않는 상태
1단계 : 자식 컴포넌트에 props 전달하기
export default function Profile() {
return (
<Avatar
person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }}
size={100}
/>
);
}
^ person (객체)과 size (숫자)를 전달
2단계 : 자식 컴포넌트 내부에서 props 읽기
function Avatar({ person, size }) {
// person과 size는 이곳에서 사용가능합니다.
}
✔️ prop의 기본값 지정하기
값이 지정되지 않았을 때, prop에 기본값을 주길 원한다면, 변수 바로 뒤에 기본값을 넣어줌
function Avatar({ person, size = 100 }) {
// ...
}
> size prop이 없이 렌더링 된다면, size는 100으로 설정됨
✔️ JSX spread 문법으로 props 전달하기
function Profile({ person, size, isSepia, thickBorder }) {
return (
<div className="card">
<Avatar
person={person}
size={size}
isSepia={isSepia}
thickBorder={thickBorder}
/>
</div>
);
}
^ Profile이 4개의 데이터를 받아서 Avatar에게 일일이 하나씩 전달하는 코드
--> 가독성은 높지만, 데이터의 양이 많아지면 코드가 길어짐
function Profile(props) {
return (
<div className="card">
<Avatar {...props} />
</div>
);
}
^ spread 문법을 통해 Profile이 받는 모든 props를 Avatar에게로 전달하는 코드
--> 코드가 깔끔해짐
* spread 문법은 편하지만, 남용하는 것은 좋지 않음
위의 예시처럼 Profile이 단순히 Avatar의 wrapper 역할을 할 때에만 사용하는 것이 좋음
= 받은 데이터 그대로 전달할 때에만
✔️ 자식을 JSX로 전달하기
<Card>
<Avatar />
</Card>
^ Card : 부모 / Avatar : 자식
부모 태그 사이의 있는 콘텐츠는 children이라는 이름으로 부모 컴포넌트에게 전달됨
import Avatar from './Avatar.js';
function Card({ children }) {
return (
<div className="card">
{children} {/* ← 이 자리가 바로 Avatar가 나타날 곳 */}
</div>
);
}
export default function Profile() {
return (
<Card>
<Avatar
size={100}
person={{
name: 'Katsuko Saruhashi',
imageId: 'YfeOqp2'
}}
/>
</Card>
);
}
Profile() 내부에서 Card 컴포넌트 아래에 Avatar 컴포넌트가 존재 --> Card : 부모, Avatar : 자식 즉, children
조건부 렌더링
React는 if문, && 및 ? : 연산자와 같은 자바스크립트 문법을 사용하여 조건부로 JSX를 렌더링할 수 있음
✔️ 조건부로 JSX 반환하기
function Item({ name, isPacked }) {
if (isPacked) {
return <li className="item">{name} ✅</li>;
}
return <li className="item">{name}</li>;
}
export default function PackingList() {
return (
<section>
<h1>Sally Ride's Packing List</h1>
<ul>
<Item
isPacked={true}
name="Space suit"
/>
<Item
isPacked={true}
name="Helmet with a golden leaf"
/>
<Item
isPacked={false}
name="Photo of Tam"
/>
</ul>
</section>
);
}
^ isPacked prop이 true이면 이 코드는 다른 JSX 트리를 반환
✔️ 조건부로 null을 사용하여 아무것도 반환하지 않기
컴포넌트는 반드시 무언가를 반환하여야 하는데, 아무것도 반환하고 싶지 않을 때에는
return null;
ㄴ 흔한 경우는 아님
✔️ 삼항 조건 연산자 (? : )
return (
<li className="item">
{isPacked ? name + ' ✅' : name}
</li>
);
^ isPacked가 참이면 (?) name + ' ✔'을 렌더링하고, 그렇지 않으면 (:) name을 렌더링
✔️ 논리 AND 연산자 (&&)
A && B
- A가 true이면 B를 결과값으로 선택
- A가 false이면 A를 결과값으로 선택
* A를 boolean 값으로 만들기
return (
<li className="item">
{name} {isPacked && '✅'}
</li>
);
^ isPacked이면 이름과 함께 체크 표시를 렌더링, 그렇지 않으면 이름 외에는 렌더링하지 않음
✔️ 변수에 조건부로 JSX를 할당하기
if문과 변수를 사용하는 방법도 O
* let으로 정의된 변수는 재할당 가능
function Item({ name, isPacked }) {
let itemContent = name;
if (isPacked) {
itemContent = name + " ✅";
}
return (
<li className="item">
{itemContent}
</li>
);
}
export default function PackingList() {
return (
<section>
<h1>Sally Ride's Packing List</h1>
<ul>
<Item
isPacked={true}
name="Space suit"
/>
<Item
isPacked={true}
name="Helmet with a golden leaf"
/>
<Item
isPacked={false}
name="Photo of Tam"
/>
</ul>
</section>
);
}
리스트 렌더링
React에서 filter()와 map()을 사용해 데이터 배열을 필터링하고 컴포넌트 배열로 변환 가능
✔️ 배열을 데이터로 렌더링하기
<ul>
<li>Creola Katherine Johnson: mathematician</li>
<li>Mario José Molina-Pasquel Henríquez: chemist</li>
<li>Mohammad Abdus Salam: physicist</li>
<li>Percy Lavon Julian: chemist</li>
<li>Subrahmanyan Chandrasekhar: astrophysicist</li>
</ul>
^ 내용이 있는 리스트가 있다고 가정
배열에서 항목 리스트를 생성하는 방법
1. 데이터를 배열로 이동
const people = [
'Creola Katherine Johnson: mathematician',
'Mario José Molina-Pasquel Henríquez: chemist',
'Mohammad Abdus Salam: physicist',
'Percy Lavon Julian: chemist',
'Subrahmanyan Chandrasekhar: astrophysicist'
];
2. people의 요소를 새로운 JSX 노드 배열인 listItems에 매핑
const listItems = people.map(person => <li>{person}</li>);
3. <ul>로 래핑된 컴포넌트의 listItems를 반환
return <ul>{listItems}</ul>;
const people = [
'Creola Katherine Johnson: mathematician',
'Mario José Molina-Pasquel Henríquez: chemist',
'Mohammad Abdus Salam: physicist',
'Percy Lavon Julian: chemist',
'Subrahmanyan Chandrasekhar: astrophysicist'
];
export default function List() {
const listItems = people.map(person =>
<li>{person}</li>
);
return <ul>{listItems}</ul>;
}
✔️ 배열의 항목들을 필터링하기
const people = [{
id: 0,
name: 'Creola Katherine Johnson',
profession: 'mathematician',
}, {
id: 1,
name: 'Mario José Molina-Pasquel Henríquez',
profession: 'chemist',
}, {
id: 2,
name: 'Mohammad Abdus Salam',
profession: 'physicist',
}, {
id: 3,
name: 'Percy Lavon Julian',
profession: 'chemist',
}, {
id: 4,
name: 'Subrahmanyan Chandrasekhar',
profession: 'astrophysicist',
}];
위 데이터에서, 직업이 chemist인 항목만 필터링하는 과정
1. people에서 filter()를 호출해 person.profession === 'chemist'로 필터링해서 "chemist"로만 구성된 새로운 배열 chemists를 생성
const chemists = people.filter(person =>
person.profession === 'chemist'
);
2. 이제 chemists를 매핑
const listItems = chemists.map(person =>
<li>
<img
src={getImageUrl(person)}
alt={person.name}
/>
<p>
<b>{person.name}:</b>
{' ' + person.profession + ' '}
known for {person.accomplishment}
</p>
</li>
);
3. 마지막으로 컴포넌트에서 listItems를 반환
return <ul>{listItems}</ul>;
* 화살표 함수는 암시적으로 => 바로 뒤에 식을 반환하기 때문에 return문이 필요하지 않음
const listItems = chemists.map(person =>
<li>...</li> // 암시적 반환!
);
* 하지만 => 뒤에 중괄호가 오는 경우 return을 명시적으로 작성해야 함
const listItems = chemists.map(person => { // 중괄호
return <li>...</li>;
});
✔️ key를 사용해서 리스트 항목을 순서대로 유지하기
각 배열 항목에 다른 항목 중에서 교유하게 식별할 수 있는 문자열 또는 숫자를 key로 지정해야 함
<li key={person.id}>...</li>
* map() 호출 내부의 JSX 엘리먼트에는 항상 key가 필요함
Key는 각 컴포넌트가 어떤 배열 항목에 해당하는지 React에 알려주어 나중에 일치시킬 수 있도록 함
✔️ key를 가져오는 곳
데이터 소스마다 다른 key 소스를 제공
- 데이터베이스의 데이터: DB에서 데이터를 가져오는 경우, 본질적으로 고유한 DB의 key/ID를 사용할 수 있음
- 로컬에서 생성된 데이터: 데이터가 로컬에서 생성되고 유지되는 경우, 항목을 만들 때 증분 일련번호나
crypto.randomUUID()또는uuid같은 패키지를 사용해야 함
✔️ key 규칙
- key는 형제 간에 고유해야 함
- key는 변경되어서는 안 됨
컴포넌트를 순수하게 유지하기
순수 함수: 오직 연산만을 수행하는 함수
컴포넌트를 엄격하게 순수 함수로만 작성하면 코드베이스의 규모가 커지더라도 버그를 피할 수 있음
✔️ 순수성: 수식으로서의 컴포넌트
순수 함수의 특징
- 자신의 일에만 집중 ㅡ 함수가 호출되기 전에 존재했던 어떤 객체나 변수를 변경하지 않음
- 같은 입력, 같은 출력 ㅡ 같은 입력이 주어졌다면 순수 함수는 항상 같은 결과를 반환
React는 모든 컴포넌트가 순수 함수라고 가정
--> React 컴포넌트에 같은 입력이 주어진다면 늘 같은 JSX를 반환한다는 것을 의미
✔️ 사이드 이펙트: 의도하지 (않은) 결과
React의 렌더링 과정은 항상 순수해야 함
ㄴ 컴포넌트는 JSX만 반환해야 하며, 렌더링 이전에 존재했던 어떤 객체나 변수도 변경해서는 안 됨
let guest = 0;
function Cup() {
// 나쁜 지점: 이미 존재했던 변수를 변경하고 있습니다!
guest = guest + 1;
return <h2>Tea cup for guest #{guest}</h2>;
}
export default function TeaSet() {
return (
<>
<Cup />
<Cup />
<Cup />
</>
);
}
^ 그러한 규칙을 위반하는 컴포넌트
function Cup({ guest }) {
return <h2>Tea cup for guest #{guest}</h2>;
}
export default function TeaSet() {
return (
<>
<Cup guest={1} />
<Cup guest={2} />
<Cup guest={3} />
</>
);
}
^ guest 변수를 Prop으로 넘겨 컴포넌트를 수정
✔️ 지역 변경: 컴포넌트의 작은 비밀
위 예시에서의 문제는 컴포넌트가 기존 변수를 렌더링 중에 변경했다는 것
그러나 이는 외부 변수를 변경했기 때문이고, 함수 내부 변수를 변경하는 것은 상관하지 않음
= 지역 변경은 OK
function Cup({ guest }) {
return <h2>Tea cup for guest #{guest}</h2>;
}
export default function TeaGathering() {
const cups = [];
for (let i = 1; i <= 12; i++) {
cups.push(<Cup key={i} guest={i} />);
}
return cups;
}
^ cups 변수나 [] 배열이 ToGathering 내부에서 생성되었기 때문에 괜찮음
✔️ 사이드 이펙트를 일으킬 수 있는 지점
사이드 이펙트 : 화면을 업데이트하고, 애니메이션을 시작하고, 데이터를 변경하는 변화들
ㄴ 렌더링 중에 발생하는 것이 아니라 '사이드에서' 발생하는 현상
React는 렌더링 중에 사이드 이펙트가 일어나는 것을 좋아하지 않음
--> 사이드 이펙트는 보통 이벤트 핸들러 내부에 위치
ㄴ 이벤트 핸들러는 사용자가 클릭하는 등의 행동을 했을 때만 실행됨
--> 이벤트 핸들러는 순수할 필요 X
사이드 이펙트를 처리할 적합한 이벤트 핸들러를 찾지 못했다면 즉, 사용자 조작 없이 화면이 나타나자마자 자동으로 일어나야 한다면
컴포넌트에서 useEffect를 호출해 반환된 JSX에 해당 사이드 이펙트를 연결 가능
ㄴ React가 렌더링을 마치고 사이드 이펙트가 허용된 시점에 그것을 실행하도록 만듦
* useEffect는 최후의 수단이어야 함
데이터 흐름을 추적하기 어렵게 만들고, 리렌더링이 자주 발생하고, 무한 루프에 빠지기 좋기 때문
'React > 공식 문서' 카테고리의 다른 글
| useReducer (0) | 2026.05.21 |
|---|---|
| 상태 구조 설계와 공유 (0) | 2026.05.07 |
| 불변 업데이트 패턴 (0) | 2026.04.28 |
| 렌더링과 State 업데이트 (0) | 2026.04.08 |
| 이벤트 처리와 State (0) | 2026.04.02 |