리액트의 조건부 렌더링이란?

안현희·2024년 11월 1일
1

React를 배워보자!

목록 보기
10/20

1. 조건부 렌더링이란?

조건부 렌더링은 컴포넌트가 특정 조건을 만족할 때만 화면에 표시되거나, 조건에 따라 다른 컴포넌트를 표시하는 방법을 의미합니다.
리액트에서는 사용자에게 보여줄 UI를 컴포넌트 단위로 관리하는데, 조건부 렌더링을 통해 동적으로 컴포넌트를 제어할 수 있습니다.
이를 통해 사용자 인터페이스의 다양한 변화를 쉽게 처리할 수 있습니다.

주요 활용 사례
조건부 렌더링은 다양한 상황에서 활용될 수 있으며, 대표적인 몇 가지 예시는 다음과 같습니다:

  • 로그인 상태에 따른 UI 변경
    사용자가 로그인했을 때와 로그아웃 상태일 때, 화면에 표시되는 컴포넌트가 달라집니다. 로그인 상태라면 "로그아웃" 버튼과 프로필 정보가 보이지만, 로그아웃 상태라면 "로그인" 버튼이나 회원 가입 안내 등이 표시됩니다.

  • 로딩 상태 표시
    데이터를 불러오는 중에는 Loading...텍스트나 로딩 스피너를 보여주고, 데이터가 로드되면 본 내용을 표시하는 방식입니다. 조건부 렌더링을 통해 "로딩 중"과 "데이터 표시" 상태를 쉽게 전환할 수 있습니다.

  • 권한에 따른 UI 표시
    사용자의 권한에 따라 접근 가능한 컴포넌트가 다를 수 있습니다. 예를 들어 관리자 권한이 있는 사용자에게만 "관리자 메뉴"가 보이게 하는 등 특정 권한에 따라 화면을 다르게 구성할 수 있습니다.

조건부 렌더링이 필요한 이유
리액트는 기본적으로 UI 상태를 동적으로 관리하기 위해 설계되었습니다. 조건부 렌더링을 활용하면, 컴포넌트의 상태나 외부의 데이터 변화에 따라 UI를 동적으로 렌더링할 수 있습니다. 또한 조건부 렌더링을 통해 불필요한 컴포넌트의 렌더링을 막아 성능을 최적화하는데 도움을 줍니다.


2. 리액트에서 조건부 렌더링을 사용하는 방법

(1) if 문을 사용한 조건부 렌더링

function Greeting(props) {
    if (props.isLoggedIn) {
        return <h1>Welcome back!</h1>;
    }
    return <h1>Please sign up.</h1>;
}
  • 이 예제에서는 props.isLoggedIn이 참일 경우에는 "Welcome back!"이라는 메시지를,
    그렇지 않다면 "Please sign up."이라는 메시지를 렌더링합니다.

(2) 삼항 연산자

function Greeting(props) {
    return (
        <div>
            {props.isLoggedIn ? <h1>Welcome back!</h1> : <h1>Please sign up.</h1>}
        </div>
    );
}
  • 삼항 연산자는 코드가 짧아지고, 한눈에 조건부 렌더링을 확인할 수 있는 장점이 있습니다.
    다만, 조건이 복잡해지면 코드 가독성이 떨어질 수 있어, 간단한 조건을 처리할 때 유용합니다.

(3) && 연산자

&&연산자는 특정 조건이 참일 때만 렌더링하는 경우에 사용할 수 있습니다.
이 방식은 조건을 만족할 때만 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컴포넌트와 버튼 컴포넌트를 다르게 렌더링하게 되며,
    삼항 연산자와 조건부 컴포넌트 구성을 동시에 활용한 예제입니다.

3. 컴포넌트로서의 조건부 렌더링

컴포넌트를 통해 조건부 렌더링을 구현하는 방식은 리액트의 강력한 컴포넌트 재사용성분리된 상태 관리의 장점을 잘 활용할 수 있는 방법입니다. 이 방식은 특히 복잡한 조건을 처리하거나, 여러 컴포넌트가 서로 다른 조건에 따라 렌더링될 때 유용합니다.

컴포넌트 기반 조건부 렌더링의 개념

리액트는 컴포넌트를 기반으로 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를 구성할 수 있어 사용자 경험을 더욱 향상시킬 수 있습니다.


4. 실제 사용 사례

1. 로그인 상태에 따른 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>
    );
}
  • 이 예제는 로그인 상태에 따른 정보를 나타내줍니다.

2. 로딩 상태 표시 (Loading Indicator)

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 호출) 시 데이터를 불러오는 동안 로딩 상태를 사용자에게 보여주는 방식은 흔히 사용되는 조건부 렌더링의 예입니다.


3. 사용자 권한에 따른 UI 제한

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>
    );
}
  • 위 예제에서는 userRoleadmin일 때만 AdminPanel컴포넌트를 렌더링하고, 그 외에는 UserDashboard를 렌더링합니다.
    이처럼 조건부 렌더링을 통해 관리자 권한이 있는 사용자에게만 특정 기능을 노출할 수 있습니다.

4. 다크 모드 전환

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의 스타일을 동적으로 변경합니다.
    버튼을 클릭하면 다크 모드와 라이트 모드가 전환되어 사용자 경험이 개선됩니다.

5. 폼 유효성 검증

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>
    );
}
  • 위 예제에서는 passwordconfirmPassword가 일치할 때만 버튼이 활성화되고,
    일치하지 않을 경우 “Passwords do not match”메시지를 보여줍니다.
    조건부 렌더링을 통해 사용자가 조건에 맞는 입력을 할 수 있도록 안내할 수 있습니다.

위에서 살펴본 다양한 사례를 통해 리액트에서 조건부 렌더링을 사용하여 사용자 경험을 동적으로 조정할 수 있음을 알 수 있습니다. 실제 프로젝트에서 조건부 렌더링을 잘 활용하면 상태에 따른 UI 제어, 사용자 권한에 따른 접근 제한, 사용자 입력에 따른 유효성 검증 등 유용하고 직관적인 UI구성을 할 수 있습니다.


고급 조건부 렌더링 및 최적화

아직 배우지 못한 개념이 있기때문에 서술하지 않았으나, 한 번쯤 찾아보시면 좋을것 같습니다!


발표자료 준비를 마치며...

미리 서술하지 못했는데, 리액트 챌리지반에 도전하게 됐다.
첫 타자로 리액트의 조건부 렌더링에 대한 발표자료를 만들고 발표를 하게 됐는데
왜 발표자료를 준비하라고한지 조금은 알 것 같다.
직접 조사하고 공부하면서 이런 개념들에 대해 알아가는것이 목표인듯 하다.

여담이지만 첫 수업을 들었는데...
잘못됐다라는 생각이 가장 먼저 들었다.
생각했던것보다 더욱 어려운 난이도 같다.
잠시 고민했으나, 이왕 고생하려고 온거 죽어보자 하고 도전해보기로 했다.

개인과제, 팀 과제는 물론이고 챌린지반 과제는 또 따로있다.
시간을 만들어서 해내야하기 때문에 이것이 가장 어려울것 같다.
어렵겠지만...

해보자!!!
해내자!!!

그럼이만

0개의 댓글