JSX 심화
1. JSX 심화
이번 장에서는 JSX의 고급 기능들과 실제 개발에서 자주 사용되는 패턴들을 학습해보겠습니다.
1.1 리스트 렌더링
JavaScript 배열을 사용해서 여러 개의 요소를 렌더링할 수 있습니다.
1.1.1 기본 리스트 렌더링
function App() {
const fruits = ['사과', '바나나', '오렌지', '포도'];
return (
<div>
<h1>과일 목록</h1>
<ul>
{fruits.map((fruit, index) => (
<li key={index}>{fruit}</li>
))}
</ul>
</div>
);
}
1.1.2 객체 배열 렌더링
function App() {
const users = [
{ id: 1, name: '김개발', age: 25, job: '프론트엔드 개발자' },
{ id: 2, name: '이디자인', age: 28, job: 'UI/UX 디자이너' },
{ id: 3, name: '박백엔드', age: 30, job: '백엔드 개발자' }
];
return (
<div>
<h1>팀 구성원</h1>
<div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap' }}>
{users.map(user => (
<div key={user.id} style={{
border: '1px solid #ddd',
borderRadius: '8px',
padding: '15px',
minWidth: '200px'
}}>
<h3>{user.name}</h3>
<p>나이: {user.age}세</p>
<p>직업: {user.job}</p>
</div>
))}
</div>
</div>
);
}
:::warning Key의 중요성
리스트를 렌더링할 때 각 항목에 고유한 key 속성을 제공해야 합니다. React가 변경사항을 효율적으로 추적할 수 있게 도와줍니다. 가능하면 배열 인덱스보다는 고유한 ID를 사용하는 것이 좋습니다.
:::
1.2 조건부 렌더링 심화
1.2.1 if-else 패턴
function App() {
const user = {
name: '김개발',
isVip: true,
points: 1500
};
// 조건에 따라 다른 컴포넌트 반환
const getUserBadge = () => {
if (user.points > 1000) {
return <span style={{color: 'gold'}}>⭐ 골드 회원</span>;
} else if (user.points > 500) {
return <span style={{color: 'silver'}}>🥈 실버 회원</span>;
} else {
return <span style={{color: 'bronze'}}>🥉 브론즈 회원</span>;
}
};
return (
<div>
<h1>안녕하세요, {user.name}님!</h1>
<p>{getUserBadge()}</p>
{user.isVip && (
<div style={{
background: 'linear-gradient(45deg, #ff6b6b, #4ecdc4)',
color: 'white',
padding: '10px',
borderRadius: '5px',
margin: '10px 0'
}}>
🎉 VIP 회원 혜택을 받으실 수 있습니다!
</div>
)}
</div>
);
}
1.2.2 논리 연산자 활용
function App() {
const todos = [
{ id: 1, text: 'React 공부하기', completed: false },
{ id: 2, text: 'JSX 이해하기', completed: true },
{ id: 3, text: '프로젝트 만들기', completed: false }
];
const completedCount = todos.filter(todo => todo.completed).length;
return (
<div>
<h1>할 일 목록</h1>
<p>완료된 할 일: {completedCount}개</p>
{todos.length === 0 ? (
<p>할 일이 없습니다.</p>
) : (
<ul>
{todos.map(todo => (
<li key={todo.id} style={{
textDecoration: todo.completed ? 'line-through' : 'none',
color: todo.completed ? '#888' : '#000'
}}>
{todo.text}
{todo.completed && ' ✅'}
</li>
))}
</ul>
)}
{completedCount === todos.length && todos.length > 0 && (
<p style={{color: 'green', fontWeight: 'bold'}}>
🎉 모든 할 일을 완료했습니다!
</p>
)}
</div>
);
}
1.3 이벤트 처리 기초
JSX에서 이벤트를 처리하는 방법을 알아봅시다.
1.3.1 기본 이벤트 처리
function App() {
const handleButtonClick = () => {
alert('버튼이 클릭되었습니다!');
};
const handleInputChange = (event) => {
console.log('입력값:', event.target.value);
};
const handleFormSubmit = (event) => {
event.preventDefault(); // 페이지 새로고침 방지
alert('폼이 제출되었습니다!');
};
return (
<div>
<h1>이벤트 처리 예제</h1>
<button onClick={handleButtonClick}>
클릭하세요
</button>
<br /><br />
<input
type="text"
placeholder="입력해보세요"
onChange={handleInputChange}
/>
<br /><br />
<form onSubmit={handleFormSubmit}>
<input type="text" placeholder="이름을 입력하세요" />
<button type="submit">제출</button>
</form>
</div>
);
}
1.3.2 이벤트 객체와 매개변수 전달
function App() {
const colors = ['red', 'blue', 'green', 'yellow', 'purple'];
const handleColorClick = (color, event) => {
console.log(`선택된 색상: ${color}`);
console.log('클릭된 요소:', event.target);
};
return (
<div>
<h1>색상 선택</h1>
<div style={{ display: 'flex', gap: '10px' }}>
{colors.map(color => (
<button
key={color}
style={{
backgroundColor: color,
color: 'white',
border: 'none',
padding: '10px 20px',
borderRadius: '5px',
cursor: 'pointer'
}}
onClick={(event) => handleColorClick(color, event)}
>
{color}
</button>
))}
</div>
</div>
);
}
1.4 동적 스타일링
조건에 따라 스타일을 동적으로 변경하는 방법입니다.
function App() {
const cards = [
{ id: 1, title: '긴급', priority: 'high', content: '버그 수정 필요' },
{ id: 2, title: '보통', priority: 'medium', content: '기능 개선' },
{ id: 3, title: '낮음', priority: 'low', content: '문서 정리' }
];
const getPriorityStyle = (priority) => {
const baseStyle = {
padding: '15px',
margin: '10px',
borderRadius: '8px',
border: '2px solid'
};
switch (priority) {
case 'high':
return { ...baseStyle, borderColor: '#ff4757', backgroundColor: '#fff0f0' };
case 'medium':
return { ...baseStyle, borderColor: '#ffa502', backgroundColor: '#fffaf0' };
case 'low':
return { ...baseStyle, borderColor: '#2ed573', backgroundColor: '#f0fff0' };
default:
return baseStyle;
}
};
const getPriorityEmoji = (priority) => {
switch (priority) {
case 'high': return '🔴';
case 'medium': return '🟡';
case 'low': return '🟢';
default: return '⚪';
}
};
return (
<div>
<h1>작업 카드</h1>
{cards.map(card => (
<div key={card.id} style={getPriorityStyle(card.priority)}>
<h3>{getPriorityEmoji(card.priority)} {card.title}</h3>
<p>{card.content}</p>
<small>우선순위: {card.priority}</small>
</div>
))}
</div>
);
}
1.5 실습: 간단한 계산기 UI
지금까지 배운 내용을 활용해서 계산기 UI를 만들어봅시다:
function App() {
const buttons = [
['C', '±', '%', '÷'],
['7', '8', '9', '×'],
['4', '5', '6', '−'],
['1', '2', '3', '+'],
['0', '.', '=']
];
const handleButtonClick = (value) => {
console.log('버튼 클릭:', value);
};
const getButtonStyle = (value) => {
const baseStyle = {
border: 'none',
borderRadius: '8px',
fontSize: '20px',
cursor: 'pointer',
transition: 'all 0.2s'
};
// 숫자 버튼
if (!isNaN(value) || value === '.') {
return {
...baseStyle,
backgroundColor: '#f0f0f0',
color: '#000',
padding: '20px'
};
}
// 연산자 버튼
if (['+', '−', '×', '÷', '='].includes(value)) {
return {
...baseStyle,
backgroundColor: '#ff9500',
color: '#fff',
padding: '20px'
};
}
// 기능 버튼
return {
...baseStyle,
backgroundColor: '#a6a6a6',
color: '#000',
padding: '20px'
};
};
return (
<div style={{
maxWidth: '300px',
margin: '20px auto',
padding: '20px',
backgroundColor: '#000',
borderRadius: '20px'
}}>
{/* 디스플레이 */}
<div style={{
backgroundColor: '#000',
color: '#fff',
fontSize: '48px',
textAlign: 'right',
padding: '20px',
marginBottom: '20px',
borderRadius: '10px',
minHeight: '60px'
}}>
0
</div>
{/* 버튼 그리드 */}
{buttons.map((row, rowIndex) => (
<div key={rowIndex} style={{
display: 'grid',
gridTemplateColumns: rowIndex === 4 ? '2fr 1fr 1fr' : 'repeat(4, 1fr)',
gap: '10px',
marginBottom: '10px'
}}>
{row.map((button, buttonIndex) => (
<button
key={button}
style={getButtonStyle(button)}
onClick={() => handleButtonClick(button)}
>
{button}
</button>
))}
</div>
))}
</div>
);
}
1.6 JSX 베스트 프랙티스
1.6.1 가독성을 위한 구조화
function App() {
// 복잡한 JSX는 변수로 분리
const header = (
<header>
<h1>제목</h1>
<nav>네비게이션</nav>
</header>
);
const footer = (
<footer>
<p>© 2025 My App</p>
</footer>
);
return (
<div>
{header}
<main>메인 콘텐츠</main>
{footer}
</div>
);
}
1.6.2 조건부 렌더링 간소화
// ❌ 복잡한 조건부 렌더링
function App() {
return (
<div>
{user.isLoggedIn ? (
user.isVip ? (
<VipWelcome user={user} />
) : (
<RegularWelcome user={user} />
)
) : (
<LoginPrompt />
)}
</div>
);
}
// ✅ 함수로 분리
function App() {
const renderWelcome = () => {
if (!user.isLoggedIn) return <LoginPrompt />;
return user.isVip ? <VipWelcome user={user} /> : <RegularWelcome user={user} />;
};
return <div>{renderWelcome()}</div>;
}
1.7 정리
JSX의 고급 기능들을 학습했습니다:
- 리스트 렌더링과
key속성의 중요성 - 조건부 렌더링의 다양한 패턴
- 이벤트 처리 기초
- 동적 스타일링 방법
- JSX 베스트 프랙티스
다음 장에서는 React의 핵심 개념인 컴포넌트에 대해 더 자세히 알아보겠습니다.