조건부 렌더링은 컴포넌트가 특정 조건을 만족할 때만 화면에 표시되거나, 조건에 따라 다른 컴포넌트를 표시하는 방법을 의미합니다.
리액트에서는 사용자에게 보여줄 UI를 컴포넌트 단위로 관리하는데, 조건부 렌더링을 통해 동적으로 컴포넌트를 제어할 수 있습니다.
이를 통해 사용자 인터페이스의 다양한 변화를 쉽게 처리할 수 있습니다.
주요 활용 사례
조건부 렌더링은 다양한 상황에서 활용될 수 있으며, 대표적인 몇 가지 예시는 다음과 같습니다:
로그인 상태에 따른 UI 변경
사용자가 로그인했을 때와 로그아웃 상태일 때, 화면에 표시되는 컴포넌트가 달라집니다. 로그인 상태라면 "로그아웃" 버튼과 프로필 정보가 보이지만, 로그아웃 상태라면 "로그인" 버튼이나 회원 가입 안내 등이 표시됩니다.
로딩 상태 표시
데이터를 불러오는 중에는 Loading...
텍스트나 로딩 스피너를 보여주고, 데이터가 로드되면 본 내용을 표시하는 방식입니다. 조건부 렌더링을 통해 "로딩 중"과 "데이터 표시" 상태를 쉽게 전환할 수 있습니다.
권한에 따른 UI 표시
사용자의 권한에 따라 접근 가능한 컴포넌트가 다를 수 있습니다. 예를 들어 관리자 권한이 있는 사용자에게만 "관리자 메뉴"가 보이게 하는 등 특정 권한에 따라 화면을 다르게 구성할 수 있습니다.
조건부 렌더링이 필요한 이유
리액트는 기본적으로 UI 상태를 동적으로 관리하기 위해 설계되었습니다. 조건부 렌더링을 활용하면, 컴포넌트의 상태나 외부의 데이터 변화에 따라 UI를 동적으로 렌더링할 수 있습니다. 또한 조건부 렌더링을 통해 불필요한 컴포넌트의 렌더링을 막아 성능을 최적화하는데 도움을 줍니다.
function Greeting(props) { if (props.isLoggedIn) { return <h1>Welcome back!</h1>; } return <h1>Please sign up.</h1>; }
props.isLoggedIn
이 참일 경우에는 "Welcome back!"이라는 메시지를,function Greeting(props) { return ( <div> {props.isLoggedIn ? <h1>Welcome back!</h1> : <h1>Please sign up.</h1>} </div> ); }
&&
연산자는 특정 조건이 참일 때만 렌더링하는 경우에 사용할 수 있습니다.
이 방식은 조건을 만족할 때만 UI
요소를 표시하고, 만족하지 않으면 아무것도 렌더링하지 않습니다.
function Mailbox(props) { const unreadMessages = props.unreadMessages; return ( <div> <h1>Hello!</h1> {unreadMessages.length > 0 && ( <h2>You have {unreadMessages.length} unread messages.</h2> )} </div> ); }
unreadMessages
배열의 길이가 0
보다 클 때만“You have {unreadMessages.length} unread messages.”
가 화면에 렌더링됩니다.각 방식의 이해를 돕기 위해 간단한 예제를 하나 더 들어보겠습니다.
로그인 여부에 따라 ‘로그인’ 또는 ‘로그아웃’ 버튼을 보여주는 경우를 생각해보면
function LoginButton(props) { return <button onClick={props.onClick}>Log in</button>; } function LogoutButton(props) { return <button onClick={props.onClick}>Log out</button>; } function UserGreeting(props) { return <h1>Welcome back!</h1>; } function GuestGreeting(props) { return <h1>Please sign up.</h1>; } function Greeting(props) { return props.isLoggedIn ? <UserGreeting /> : <GuestGreeting />; } function App(props) { const isLoggedIn = props.isLoggedIn; return ( <div> <Greeting isLoggedIn={isLoggedIn} /> {isLoggedIn ? <LogoutButton /> : <LoginButton />} </div> ); }
isLoggedIn
이라는 상태에 따라 Greeting
컴포넌트와 버튼 컴포넌트를 다르게 렌더링하게 되며,컴포넌트를 통해 조건부 렌더링을 구현하는 방식은 리액트의 강력한 컴포넌트 재사용성과 분리된 상태 관리의 장점을 잘 활용할 수 있는 방법입니다. 이 방식은 특히 복잡한 조건을 처리하거나, 여러 컴포넌트가 서로 다른 조건에 따라 렌더링될 때 유용합니다.
리액트는 컴포넌트를 기반으로 UI를 구성하므로, 조건에 따라 다른 컴포넌트를 선택적으로 렌더링할 수 있습니다. 조건이 맞을 때마다 특정 컴포넌트를 반환하게 하면, 코드가 더 깔끔하고 재사용성이 높아집니다. 예를 들어, 로그인이 되었는지 여부에 따라 "로그인 상태 표시 컴포넌트" 또는 "로그인 권유 컴포넌트"를 보여줄 수 있습니다.
조건에 따라 다른 컴포넌트를 렌더링하는 방법은 간단하게 함수형 컴포넌트를 사용하는 것입니다.
몇 가지 예제를 살펴보겠습니다.
예제 1: Greeting
컴포넌트로 조건부 렌더링 구현
function UserGreeting() { return <h1>Welcome back!</h1>; } function GuestGreeting() { return <h1>Please sign up.</h1>; } function Greeting(props) { const isLoggedIn = props.isLoggedIn; if (isLoggedIn) { return <UserGreeting />; } return <GuestGreeting />; }
Greeting
컴포넌트는 isLoggedIn
이라는 props
을 받아서,UserGreeting
이나 GuestGreeting
컴포넌트를 렌더링합니다.Greeting
컴포넌트가 조건에 따라 다른 컴포넌트로 전환하는 역할을 합니다.예제 2: 더 복잡한 조건 처리
여러 가지 조건을 처리할 경우, 중첩된 if
문보다는 별도의 함수를 이용하거나,
다중 조건 컴포넌트를 만들어 각기 다른 상황에 맞는 컴포넌트를 반환할 수 있습니다.
function AdminGreeting() { return <h1>Welcome, Admin!</h1>; } function UserGreeting() { return <h1>Welcome back!</h1>; } function GuestGreeting() { return <h1>Please sign up.</h1>; } function Greeting(props) { const { userType } = props; if (userType === 'admin') { return <AdminGreeting />; } else if (userType === 'user') { return <UserGreeting />; } return <GuestGreeting />; }
userType
에 따라 AdminGreeting
, UserGreeting
, 그리고 GuestGreeting
가독성: 복잡한 조건을 if 문이나 삼항 연산자로 한 컴포넌트 내에 전부 담는 것보다 가독성이 좋고 유지보수가 쉬워집니다.
컴포넌트 분리: 컴포넌트를 역할에 맞게 분리할 수 있습니다. 각 조건별 컴포넌트는 독립적으로 관리되므로 수정이나 재사용이 용이합니다.
테스트 용이성: 조건에 따라 각기 다른 컴포넌트를 개별적으로 테스트할 수 있으므로, 조건부 렌더링을 위한 테스트가 더 쉽습니다.
리액트에서는 조건에 따라 보여줄 컴포넌트를 분리하기 위해 렌더링 로직을 별도의 함수로 분리할 수 있습니다.
function renderGreeting(userType) { if (userType === 'admin') { return <AdminGreeting />; } else if (userType === 'user') { return <UserGreeting />; } return <GuestGreeting />; } function Greeting(props) { return ( <div> {renderGreeting(props.userType)} </div> ); }
renderGreeting
이라는 함수를 별도로 작성하여, Greeting
컴포넌트 내부에서 해당 함수를 호출하는 방식입니다.컴포넌트를 활용한 조건부 렌더링은 유지보수가 용이하고 재사용 가능한 컴포넌트를 만들 수 있는 좋은 방법입니다. 이러한 방식은 특히 상태 관리와 조건이 많은 경우에 매우 유용하며, 다양한 조건에 따라 적절하게 UI를 구성할 수 있어 사용자 경험을 더욱 향상시킬 수 있습니다.
function App(props) { const isLoggedIn = props.isLoggedIn; return ( <div> {isLoggedIn ? ( <div> <h1>Welcome back, User!</h1> <button>Logout</button> </div> ) : ( <div> <h1>Please log in.</h1> <button>Login</button> </div> )} </div> ); }
import React, { useState, useEffect } from 'react'; function DataFetchingComponent() { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { fetchData().then(fetchedData => { setData(fetchedData); setLoading(false); }); }, []); if (loading) { return <div>Loading...</div>; } return <div>Data: {data}</div>; }
위 예제에서는 데이터를 불러오는 동안 loading
상태가 참이므로 로딩 메시지 “Loading...”을 보여줍니다.
데이터가 로드되면 로딩 상태를 false
로 변경하여 데이터를 화면에 렌더링합니다.
로딩 상태 관리는 사용자 경험을 크게 개선할 수 있는 중요한 조건부 렌더링 사례입니다.
비동기 요청(예: API 호출) 시 데이터를 불러오는 동안 로딩 상태를 사용자에게 보여주는 방식은 흔히 사용되는 조건부 렌더링의 예입니다.
function AdminPanel(props) { return <h1>Admin Panel</h1>; } function UserDashboard(props) { return <h1>User Dashboard</h1>; } function App(props) { const { userRole } = props; return ( <div> {userRole === 'admin' ? <AdminPanel /> : <UserDashboard />} </div> ); }
userRole
이 admin
일 때만 AdminPanel
컴포넌트를 렌더링하고, 그 외에는 UserDashboard
를 렌더링합니다.function App() { const [isDarkMode, setIsDarkMode] = useState(false); const toggleDarkMode = () => setIsDarkMode(!isDarkMode); return ( <div style={{ background: isDarkMode ? '#333' : '#FFF', color: isDarkMode ? '#FFF' : '#333' }}> <h1>{isDarkMode ? 'Dark Mode' : 'Light Mode'}</h1> <button onClick={toggleDarkMode}> Switch to {isDarkMode ? 'Light' : 'Dark'} Mode </button> </div> ); }
isDarkMode
상태에 따라 배경색과 텍스트 색상을 조정하며,UI
의 스타일을 동적으로 변경합니다.function SignupForm() { const [password, setPassword] = useState(''); const [confirmPassword, setConfirmPassword] = useState(''); const isMatch = password && confirmPassword && password === confirmPassword; return ( <div> <input type="password" placeholder="Password" onChange={(e) => setPassword(e.target.value)} /> <input type="password" placeholder="Confirm Password" onChange={(e) => setConfirmPassword(e.target.value)} /> <button disabled={!isMatch}>Submit</button> {!isMatch && <p>Passwords do not match</p>} </div> ); }
password
와 confirmPassword
가 일치할 때만 버튼이 활성화되고,위에서 살펴본 다양한 사례를 통해 리액트에서 조건부 렌더링을 사용하여 사용자 경험을 동적으로 조정할 수 있음을 알 수 있습니다. 실제 프로젝트에서 조건부 렌더링을 잘 활용하면 상태에 따른 UI 제어, 사용자 권한에 따른 접근 제한, 사용자 입력에 따른 유효성 검증 등 유용하고 직관적인 UI
구성을 할 수 있습니다.
아직 배우지 못한 개념이 있기때문에 서술하지 않았으나, 한 번쯤 찾아보시면 좋을것 같습니다!
미리 서술하지 못했는데, 리액트 챌리지반에 도전하게 됐다.
첫 타자로 리액트의 조건부 렌더링에 대한 발표자료를 만들고 발표를 하게 됐는데
왜 발표자료를 준비하라고한지 조금은 알 것 같다.
직접 조사하고 공부하면서 이런 개념들에 대해 알아가는것이 목표인듯 하다.
여담이지만 첫 수업을 들었는데...
잘못됐다라는 생각이 가장 먼저 들었다.
생각했던것보다 더욱 어려운 난이도 같다.
잠시 고민했으나, 이왕 고생하려고 온거 죽어보자 하고 도전해보기로 했다.
개인과제, 팀 과제는 물론이고 챌린지반 과제는 또 따로있다.
시간을 만들어서 해내야하기 때문에 이것이 가장 어려울것 같다.
어렵겠지만...
해보자!!!
해내자!!!