동적 UI 제어: 조건부 렌더링과 리스트 렌더링
1. 조건부 렌더링 (Conditional Rendering)
JSX 내부에서는
if문이나 for문을 직접 사용할 수 없습니다. 대신 자바스크립트의 논리 연산자를 활용하여 렌더링을 제어합니다.- 삼항 연산자 (
조건 ? 참 : 거짓): 조건에 따라 두 UI 중 하나를 명확히 선택할 때 사용합니다. (예: 로그인 버튼 / 로그아웃 버튼 스위칭) - 논리 AND 연산자 (
조건 && 참): 조건이 참일 때만 무언가를 렌더링하고, 거짓일 때는 아무것도 그리지 않을 때 사용합니다. (예: 에러 메시지 팝업, 알림창)
&& 사용 시 주의사항
0 && <div>...</div>의 경우 숫자 0이 화면에 그대로 렌더링됩니다. 배열 길이를 체크할 때는 items.length > 0 && ... 처럼 명확한 boolean 값으로 평가되도록 작성하세요!
LoginGreeting.jsx
import React, { useState } from 'react';
export default function LoginGreeting() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
return (
<div style={{ padding: '20px', background: '#f8fafc', borderRadius: '8px' }}>
<h2 style={{ marginTop: 0 }}>조건부 렌더링 예제</h2>
{/* 삼항 연산자 (? :) 활용 */}
<div style={{ marginBottom: '20px' }}>
<p>상태: {isLoggedIn ? <strong style={{color: 'green'}}>로그인 됨</strong> : <strong style={{color: 'red'}}>로그아웃 상태</strong>}</p>
<button
onClick={() => setIsLoggedIn(!isLoggedIn)}
style={{ padding: '8px 16px', background: '#3b82f6', color: '#fff', border: 'none', borderRadius: '4px', cursor: 'pointer' }}
>
{isLoggedIn ? '로그아웃 하기' : '로그인 하기'}
</button>
</div>
{/* 논리 AND (&&) 연산자 활용 */}
{isLoggedIn && (
<div style={{ padding: '15px', background: '#dcfce7', color: '#166534', borderRadius: '8px' }}>
환영합니다! 회원 전용 콘텐츠입니다. 👋
</div>
)}
</div>
);
}2. 리스트 렌더링 (List Rendering)
배열 데이터를 반복하여 렌더링할 때는 자바스크립트 배열의
map() 함수를 사용합니다. 데이터가 많아질수록 일일이 하드코딩할 수 없기 때문에 실무에서 가장 많이 쓰이는 패턴 중 하나입니다.이때 반복되는 요소의 최상위 태그에는 반드시 고유한
key 속성을 부여해야 합니다. 리액트는 이 key를 통해 어떤 아이템이 추가/수정/삭제되었는지 빠르고 효율적으로 추적합니다. (주의: 배열의 인덱스 index를 key로 사용하면 아이템 순서가 바뀔 때 버그가 발생할 수 있으므로, 고유한 ID값을 사용하는 것이 좋습니다.)ProductList.jsx
import React from 'react';
export default function ProductList() {
const products = [
{ id: 1, name: '노트북', price: 1500000, inStock: true },
{ id: 2, name: '마우스', price: 50000, inStock: false },
{ id: 3, name: '키보드', price: 120000, inStock: true }
];
return (
<div style={{ padding: '20px', background: '#f8fafc', borderRadius: '8px' }}>
<h2 style={{ marginTop: 0 }}>리스트 렌더링 예제</h2>
{/* 데이터 길이가 0보다 클 때만 제목 표시 */}
{products.length > 0 && <h3>상품 목록 ({products.length}개)</h3>}
{/* map 함수를 이용한 반복 렌더링 */}
<ul style={{ paddingLeft: '20px' }}>
{products.map((item) => (
<li key={item.id} style={{ opacity: item.inStock ? 1 : 0.5, marginBottom: '10px' }}>
<strong>{item.name}</strong> - {item.price.toLocaleString()}원
{!item.inStock && <span style={{ color: 'red', marginLeft: '8px' }}>[품절]</span>}
</li>
))}
</ul>
</div>
);
}