IT

[영어로 배우는 React] 7. 조건적 랜더링

생각파워 2022. 4. 13. 07:39

공식사이트 : https://reactjs.org/docs/conditional-rendering.html

 

 

리액트에서 각각의 캡슐화된 컴포넌트를 만들어 state의 상태에 따라 필요한 컴포넌트를 랜더링 할 수 있습니다.

리액트의 조건적 랜더링은 자바스크립트의 조건식과 같은 방식으로 작동합니다. 다음 두개의 컴포넌트를 살펴보겠습니다. 

function UserGreeting(props) {
  return <h1>Welcome back!</h1>;
}

function GuestGreeting(props) {
  return <h1>Please sign up.</h1>;
}

이제 사용자의 로그인 상태에 따라 다른 인사를 보여주는 Greeting 컴포넌트를 만들어 보겠습니다. 

function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {    
  	return <UserGreeting />;  
  }  return <GuestGreeting />;
}

ReactDOM.render(
  // Try changing to isLoggedIn={true}:
  <Greeting isLoggedIn={false} />,  
  document.getElementById('root')
);

위 예는 isLoggedIn의 값에 따라 각각 다른 컴포넌트를 랜더링합니다. 그래서 다른 인사말이 사용자에게 보이게 됩니다.

 

앨리먼트 변수

앨리먼트를 저장하기 위해 변수를 사용할 수 있습니다. 이것은 컴포넌트의 일부분만 변경되었을 때 조건적으로 랜더링할수 있게 해줍니다. 로그인과 로그아웃을 표현하는 아래 두 컴포넌트를 살펴보겠습니다.

function LoginButton(props) {
  return (
    <button onClick={props.onClick}>
      Login
    </button>
  );
}

function LogoutButton(props) {
  return (
    <button onClick={props.onClick}>
      Logout
    </button>
  );
}

아래의 예에서 LoginControl 이라는 상태유지 컴포넌트를 만들어보겠습니다. 여기서 <LoginButton />이나 <LogoutButton />을 현재 state에 따라 각각 랜더링하게 될것입니다. 또, 이전 예에서 봤던 <Greeting /> 컴포넌트로 랜더링 할것입니다. 

class LoginControl extends React.Component {
  constructor(props) {
    super(props);
    this.handleLoginClick = this.handleLoginClick.bind(this);
    this.handleLogoutClick = this.handleLogoutClick.bind(this);
    this.state = {isLoggedIn: false};
  }

  handleLoginClick() {
    this.setState({isLoggedIn: true});
  }

  handleLogoutClick() {
    this.setState({isLoggedIn: false});
  }

  render() {
    const isLoggedIn = this.state.isLoggedIn;
    let button;
    if (isLoggedIn) {
    	button = <LogoutButton onClick={this.handleLogoutClick} />;
    } else {      
    	button = <LoginButton onClick={this.handleLoginClick} />;    
    }
    
    return (
      <div>
        <Greeting isLoggedIn={isLoggedIn} />
        {button}      
      </div>
    );
  }
}

ReactDOM.render(
  <LoginControl />,
  document.getElementById('root')
);

변수를 선언하고 if문을 사용하는 것은 컴포넌트를 조건적으로 랜더링하는 좋은 방법이긴 하지만, 가끔 더 짧은 문법을 원할 수도 있습니다. 이럴 때는 JSX안에 인라인 조건문을 사용하면 됩니다. 아래의 예제를 살펴보겠습니다.  

 

논리적 && 연산자를 이용한 인라인 if문

JSX안에는 중괄호를 감싼 내포된 수식을 포함할 수 있습니다. 그리고 이것은 자바스크립트의 논리적 &&연산자를 포함할 수 있습니다. 이 방법은 조건적으로 앨리먼트 쉽게 다룰 수 있습니다. 

function Mailbox(props) {
  const unreadMessages = props.unreadMessages;
  return (
    <div>
      <h1>Hello!</h1>
      {
      	unreadMessages.length > 0 
        &&
      	<h2>You have {unreadMessages.length} unread messages.</h2>
      }    
    </div>
  );
}

const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
  <Mailbox unreadMessages={messages} />,
  document.getElementById('root')
);

위 예제의 결과는 아래와 같습니다. 

위 예제는 자바스크립트이기 때문에, true && 수식이면 항상 수식으로 평가됩니다. 그리고 false && 수식이면 항상 false로 평가되죠. 그래서, 위의 if문은 true가 되고 &&수식 바로 뒤의 앨리먼트가 랜더링됩니다. 만약 if문이 false면 리액트는 앨리먼트를 무시할 것입니다.

주의해야할것은 수식이 false 값을 가지는 것은 && 바로뒤의 앨리먼트를 건너뛰게 만들지만, 거짓 수식은 리턴한다는 것입니다. 아래의 예에서 count = 0 이기 때문에 false로 취급되어 <h1> </h1> 수식은 리턴되지 않지만 count는 리턴이 됩니다. 그래서 <div>0</div>가 리턴될 것입니다.

render() {
  const count = 0;  return (
    <div>
      {count && <h1>Messages: {count}</h1>}   
    </div>
  );
}

 

조건연산자를 가진 인라인 if문

조건적으로 앨리먼트를 랜더링하는 다른 메소드는 자바스크립트의 조건연산자 condition ? ture : false 입니다. 아래의 예제는 조건연산자를 작은 텍스트 블록을 조건에 따라 랜더링하는데 사용한 것입니다.

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
    </div>
  );
}

이것은 아래의 예와 같이 좀 불확실해 보이지만, 큰 수식에 사용될 수도 있습니다. 

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      {
        isLoggedIn        
        ? <LogoutButton onClick={this.handleLogoutClick} />
        : <LoginButton onClick={this.handleLoginClick} />      
      }
    </div>  
  );
}

자바스크립트와 마찬가지로, 어떤 스타일을 사용할 지 결정하는 것은 가독성을 고려해서 결정하면 됩니다. 또 조건문은 언제든 너무 복잡해질 수 있기때문에, 그 때가 컴포넌트를 추출할 수 있는 좋은 시기가 됩니다.

 

컴포넌트 랜더링 막기

드물게 컴포넌트가 랜더링 될때, 그 컴포넌트를 숨기길 원하는 상황이 올 수 있습니다. 이 상황을 처리하기 위해 랜더링 할 컴포넌트를 리턴하는 대신에 null을 리턴하면 되니다. 아래는 warn으로 불리는 prop의 값에 따라 <WarningBanner /> 컴포넌트가 랜더링되는 예제입니다. prop의 값이 false이면, 컴포넌트는 랜더링되지 않습니다. 

function WarningBanner(props) {
  if (!props.warn) {    return null;  }
  return (
    <div className="warning">
      Warning!
    </div>
  );
}

class Page extends React.Component {
  constructor(props) {
    super(props);
    this.state = {showWarning: true};
    this.handleToggleClick = this.handleToggleClick.bind(this);
  }

  handleToggleClick() {
    this.setState(state => ({
      showWarning: !state.showWarning
    }));
  }

  render() {
    return (
      <div>
        <WarningBanner warn={this.state.showWarning} />
        <button onClick={this.handleToggleClick}>
          {this.state.showWarning ? 'Hide' : 'Show'}
        </button>
      </div>
    );
  }
}

ReactDOM.render(
  <Page />,
  document.getElementById('root')
);

최초 접속시는 아래와 같이 표시됩니다.

이후 Hide 버튼을 클릭하게 되면 아래와 같이 표시됩니다.

경고창이 없어지고, 버튼명도 'Show'로 바뀝니다.

 

컴포넌트의 render 메소드에서 null이 리턴되는것은 컴포넌트 실행주기 메소드의 실행에 영향을 주지 않습니다. 예를 들면, componentDidUpdate 실행주기 메소드는 여전히 호출됩니다.

 

 

 

 

 

반응형