본문 바로가기
리액트

[react] 올바른 리액트 조건부 렌더링 (if else 구문과 ternary operator, && 차이)

by jaewooojung 2019. 9. 9.

ReactJS


리액트의 조건부 렌더링

리액트에서 JSX를 조건에 따라 렌더링 할 때에는 크게 두 가지 방법이 있습니다. 1) if, else 구문을 사용하는 방법과 2) ternary operator를 사용하는 방법입니다. 두 가지 방법 모두 겉으로 보기에는 condition에 따른 JSX를 렌더링 한다는 점에서 비슷하지만, 경우에 따라 성능상의 차이가 크게 나타나기도 합니다. 간단한 예시를 통해서 어떤  차이가 있는지 살펴보겠습니다.

 

1. if / else

if, else를 활용한 예시입니다. showing state에 따라서 Header 컴포넌트의 렌더링 여부를 결정하도록 구현했습니다.

import React, { useState } from "react";
import "./App.css";

function App() {
  const [showing, setShowing] = useState(false);
  const toggleShowing = () => setShowing(!showing);
  if (showing) {
    return (
      <div className="app">
        <button onClick={toggleShowing}>toggle</button>
        <Header>Header</Header>
        <Main>Main</Main>
        <Footer>Footer</Footer>
      </div>
    );
  } else {
    return (
      <div className="app">
        <button onClick={toggleShowing}>toggle</button>
        <Main>Main</Main>
        <Footer>Footer</Footer>
      </div>
    );
  }
}

function Header() {
  return <div>Header</div>;
}

function Main() {
  return <div>Main</div>;
}

function Footer() {
  return <div>Footer</div>;
}

export default App;

showing이 true이면 Header 컴포넌트를 렌더링 하고 false이면 렌더링 하지 않습니다.

 

if / else 예시

 

toggle버튼을 누를 때마다 showing 스텟이 변화하면서 Header 컴포넌트를 렌더링 합니다. 간단한 코드이지만, 성능상의 문제가 있습니다.
 
확인을 위해 각 컴포넌트 렌더링시에 console 메시지를 출력해 보겠습니다.

function Header() {
  console.log("Header rendering");
  return <div>Header</div>;
}

function Main() {
  console.log("Main rendering");
  return <div>Main</div>;
}

function Footer() {
  console.log("Footer rendering");
  return <div>Footer</div>;
}

콘솔 출력 gif

 

Header 컴포넌트가 추가되거나 삭제됨에 따라서 Main과 Footer 컴포넌트가 불필요하게 리렌더링 되고 있습니다. 여기서 리렌더링을 막기 위해 첫 번째로 생각할 수 있는 방법은 useMemo나 React.memo를 사용해서 state의 변화에 따른 렌더링을 방지하는 방법입니다.
  
React.memo로 컴포넌트를 감싸고, console 메시지를 수정합니다.

const Header = React.memo(function Header() {
  console.log("Header rendering / memo");
  return <div>Header</div>;
});

const Main = React.memo(function Main() {
  console.log("Main rendering / memo");
  return <div>Main</div>;
});

const Footer = React.memo(function Footer() {
  console.log("Footer rendering / memo");
  return <div>Footer</div>;
});

memo 적용 후 콘솔 출력 gif

 

React.memo를 사용했음에도 여전히 불필요한 렌더링이 일어나고 있습니다. state의 변화에 따른 불필요한 렌더링을 잡아주게 된 것은 맞지만, 여기서의 원인은 그것이 아닙니다.
 
문제는 if / else 구문에 있습니다.
 
App 컴포넌트를 다시 보겠습니다.

function App() {
  const [showing, setShowing] = useState(false);
  const toggleShowing = () => setShowing(!showing);
  if (showing) {
    return (
      <div className="app">
        <button onClick={toggleShowing}>toggle</button>
        <Header>Header</Header>
        <Main>Main</Main>
        <Footer>Footer</Footer>
      </div>
    );
  } else {
    return (
      <div className="app">
        <button onClick={toggleShowing}>toggle</button>
        <Main>Main</Main>
        <Footer>Footer</Footer>
      </div>
    );
  }
}

 

조건에 따라서 서로 다른 JSX를 렌더링 하고 있습니다. 두 가지 조건에서 모두 동일한 Main과 Footer 컴포넌트를 사용하고 있지만, react는 이를 각각 개별적인 컴포넌트로 취급합니다. 즉, 같은 Main이라도 if절의 Main과 else절의 Main으로 번갈아가면서 렌더링 하기 때문에 리렌더링이 발생한 것입니다.

 

이를 해결하기 위해서는 하나의 return문 안에서 ternary operator를 사용해야 합니다.

 

2. ternary operator

function App() {
  const [showing, setShowing] = useState(false);
  const toggleShowing = () => setShowing(prevShowing => !prevShowing);
  return (
    <div className="app">
      <button onClick={toggleShowing}>toggle</button>
      {showing === true ? <Header>Header</Header> : null}
      <Main>Main</Main>
      <Footer>Footer</Footer>
    </div>
  );
}

 

if / else 구문을 지우고, ternary operator를 사용했습니다.

{showing === true ? <Header>Header</Header> : null}

 

showing이 true이면 Header를 반환하고 false일 때는 null을 반환합니다.

 

위 코드는 if, else 구문과 동일하게 보이지만 성능상 큰 차이가 있습니다. 바로 showing state에 관계없이 아래에 있는 Main과 Footer가 동일한 JSX로 유지된다는 것입니다.

ternary operator gif

 

콘솔창을 통해 Main과 Footer는 렌더링 되지 않고, Header만 렌더링 되는 모습을 확인할 수 있습니다.

 

참고로 ternary operator는 다음과 같이 && 구문을 사용하여 줄여 쓸 수 있습니다.

{showing && <Header>Header</Header>}

 

조건에 따라서 전혀 다른 JSX를 반환하는 경우에는 if, else 구문을 사용하는 것이 가독성에 좋다고 생각합니다. 하지만 예시에서와 같이 레이아웃이 동일한 상태에서 일부분만 조건부 렌더링을 하는 경우에는, 하나의 return문 안에서 ternary operator를 활용해서 조건에 따른 최소한의 JSX만 바꿔주는 것이 좋습니다. 성능상 유리합니다. 감사합니다.


react document - conditional rendering

 

Conditional Rendering – React

The library for web and native user interfaces

react.dev



        
답변을 생성하고 있어요.