javascript/React.js

[React.js] #5 조건부 랜더링 & 다중 컴포넌트 생성

탕구리당 2020. 12. 18. 00:38
반응형

 

이번 포스팅에서는 조건부 랜더링과 다중 컴포넌트(?)를 랜더링 하는 방법에 대해서 알아보도록 하겠습니다.

 

조건부 랜더링

React에서 조건부 랜더링은 if 혹은 조건부 연산자를 통해 상태에 따른 엘리먼트를 만들어 낼 수 있습니다.

 

음.. 한가지 예를 들어보자면 어떤 웹 사이트에 로그인을 하려고 칩시다.

로그인을 하지 않은 경우에는 "로그인 창"이 나타나게 구현할 것이고, 로그인 상태에는 "환영합니다!"라는 문구가 출력되도록 구현하고 싶으면 어떻게 해야 할까요?

 

그럼 이제 위에서 예시했던 로그인 창은 아니지만 counter를 구현하고 count 숫자에 따라 1~10까지 나타내는 컴포넌트 노출시켜 주는 페이지를 만들어 보겠습니다.

 

 

우선, 프로젝트를 생성합시다.

 

create-react-app condition

 

그리고 기초가 될 App 컴포넌트를 생성해 줍니다.

 

# App.js

class App extends Component {

  constructor(props) {
    super(props)
    this.state = {
      count: 0,
      isVisible: false,
    }
  }

  countHandle = (e) => {
    
    const { count } = this.state;
    
    if((count+1) % 10 === 0) {
      this.setState({
        count: count+1,
        isVisible: true,
      })
    } else {
      this.setState({
        count: count+1,
        isVisible: false,
      })
    }
  }


  render() {

    const { isVisible, count } = this.state

    return (
      <div className="App">
        <p> { count } </p>
        <button onClick={this.countHandle} > BUTTON </button>
        { isVisible && <Condition count={count} /> }
      </div>
    );
  }
}

export default App;

 

우선, 살펴보아야 할 것은 count와 isVisible입니다. 우리는 count 값에 따라 isVisible 상태를 변경시켜 Condition 컴포넌트의 노출을 조절해 줄 예정입니다.

 

다음은 Condition 컴포넌트입니다.

 

# Condition.js

class Condition extends Component {
  
  render() {

    const { isVisible, count } = this.props
    const list = [1,2,3,4,5,6,7,8,9,10]
    return (
      <div>
        {
          list.map((value) => {
            return (
              <div key={value}> {value * (count /10)} </div>
            )
          })
        }
      </div>
    )
  }
}

export default Condition

 

Condition 컴포넌트에는 오늘 진행해볼 또 하나의 예제인 다중 컴포넌트에 대한 부분이 담겨 있습니다.

list 배열에 담겨있는 개수만큼 <div> 엘리먼트를 생성해 줍니다.

 

 

자세한 동작 방식은 아래와 같습니다.

 

(1) 버튼을 클릭하게 되면 count가 증가합니다.

(2) count가 10으로 나누어 떨어지는 경우에 isVisible => true로 변경합니다.

(3) isVisible이 True인 경우 Condition 컴포넌트를 노출 시킴

(4) Condition 컴포넌트 랜더링 시작

(5) List 담긴 배열 개수만큼 <div> 엘리먼트 생성 후 return

 

 

결과

 

count % 10 !== 0 인 경우 아래와 같이 나타납니다.

 

count % 10 === 0 인 경우 아래와 같이 나타납니다.

 

다른 방식을 통한 조건부 랜더링

 

위의 예제는 &(앤드 연산)을 통한 조건부 랜더링 방법이었습니다.

이번엔 다른 방식을 통한 조건부 랜더링에 대해서도 알아보겠습니다.

 

 

(1) 삼항 연산자를 통한 조건부 랜더링

 

class App extends Component {

  (...)
  
  render() {

      const { isVisible, count } = this.state

      return (
        <div className="App">
          <p> { count } </p>
          <button onClick={this.countHandle} > BUTTON </button>
          {isVisible ? <Condition count={count}/> : null }
        </div>
      );
    }
}

 

(2) if문을 통한 조건부 랜더링

 

class App extends Component {
 
 (...)
 
 render() {

    const { isVisible, count } = this.state
    let comp = null;
    
    if(isVisible) {
      comp = <Condition count={count}/>
    }

    return (
      <div className="App">
        <p> { count } </p>
        <button onClick={this.countHandle} > BUTTON </button>
        { comp }
      </div>
    );
  }
}

 

 

+ 추가 사항

 

** 주의 ** 

 

리액트에서는 엘리먼트 식별을 위해 "key"라는 값을 가지고 있습니다. 위의 코드를 잠깐 살펴봅시다.

 

# Condition.js

class Condition extends Component {
  
  render() {

    const { isVisible, count } = this.props
    const list = [1,2,3,4,5,6,7,8,9,10]
    return (
      <div>
        {
          list.map((value, index) => {
            return (
              <div key={index}> {value * (count /10)} </div>
            )
          })
        }
      </div>
    )
  }
}

export default Condition

 

<div> 엘리먼트를 보면 "key"라는 속성을 가지고 있는 것을 확인할 수 있습니다. key는 리스트 내의 엘리먼트와 중첩되지 않는 고유한 값이어야 합니다. 저의 경우는 처음엔 map의 value 값을 key값으로 사용했었는데 index를 사용하는 것이 좀 더 명확한 식별이 가능할 것 같아 index값을 식별자로 사용하였습니다. 

 

 

리스트 엘리먼트를 컴포넌트로 추출한 경우

 

코드를 조금 수정해 보았습니다.

 

import React, { useState, Component } from 'react';

function Item(props) {
  
  const { value, index, count } = props;
  return (
    <div key={index}> { value * count / 10 } </div>
  )
}


class Condition extends Component {
  
  render() {

    const { isVisible, count } = this.props
    const list = [1,2,3,4,5,6,7,8,9,10]
    return (
      <div>
        {
          list.map((value, index) => {
            return (
              <Item value={value} index={index} count={count} />
            )
          })
        }
      </div>
    )
  }
}

export default Condition

 

리스트 엘리먼트를 구성할 항목을 별도로 추출하여 Item이라는 컴포넌트를 만들었습니다.

그리고 각각의 <div> 엘리먼트 내에 key값을 설정해 주었습니다. 결과를 확인해 봅시다.

 

오류가 발생합니다.

리스트를 구성하는 각각의 child에는 고유의 키가 있어야 한다고 합니다. 우리는 <div> 태그에 key 값을 설정해 주었지만 키는 주변 배열의 context에서만 의미를 가지기 때문에 실제 map()이 돌고 있는 <Item> 컴포넌트에 key값을 설정해주어야 합니다.

 

import React, { Component } from 'react';

function Item(props) {
  const { value, index, count } = props;
  return (
    <div> { value * count / 10 } </div>
  )
}

class Condition extends Component {
  
  render() {

    const { count } = this.props
    const list = [1,2,3,4,5,6,7,8,9,10]
    return (
      <div>
        {
          list.map((value, index) => {
            return (
              <Item key={index} value={value} count={count} />
            )
          })
        }
      </div>
    )
  }
}

export default Condition

 

다음과 같이 변경하면 오류는 더 이상 발생하지 않습니다. 이 외에도 key값은 같은 Level을 가지고 있는 컴포넌트 간에도 독립적인 식별 값을 가져야 하는 부분에 유의하여 주시기 바랍니다.

 

 

이번 포스팅에서는 조건부 랜더링과 다중 컴포넌트를 생성하는 방식에 대해서 알아보았습니다. 글의 내용 중 설명이 모자란 부분이나 잘못된 내용이 있을 수 있음을 양해하여 읽어주시면 감사합니다.

 

 

 

탕빠이!

 

 

 

반응형