본문 바로가기
프로그래밍/React

[React] state 사용하기 (다중속성)

by 소소로드 2021. 1. 22.

State의 사용방법 (다중 속성의 경우) 

: 앞선 Subject는 겨우 WEB, world wider web! 으로만 이루어져 있는데,
TOC의 경우 ul-li로 감싸진 많은 내용으로 이루어져 있다. 이럴 때는 어떻게 쓸까.

 class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      subject:{title:"WEB" sub:"world wider web!"},
      contents:[
        {id:1, title:'HTML', desc: 'HTML is for information'},
        {id:2, title:'CSS', desc: 'CSS is for design'},
        {id:3, title:'Javascript', desc: 'Javascript is for exciting'}
      ]
    }
  }

  render() {
    return (
      <div className="App">
        <Subject title={this.state.subject.title}
                 sub={this.state.subject.sub}></Subject>
        <TOC data={this.state.contents}></TOC>
        <Content title="HTML" desc="HTML is Markup Language"></Content>
      </div>
   );
  }
 }

 export default App;

contents도 subject와 같은 방법이지만 우선 대괄호인 []를 써주고,
그 안에 각각의 괄호를 통해 다중속성을 제어할 수 있다.
상위 컨포넌트인 App의 TOC에는 data라는 props를 받아서 써주었다.
그럼 아직 건들지 않은 TOC 컨포넌트는 어떻게 처리할까? 

 

src > components > Subject, Content, TOC.js

 // Subject.js
 class Subject extends Component {
    render() {
      return (
        <header>
           <h1>{this.props.title}</h1>
           {this.props.sub}
        </header>
      );
    }
  }

 export default Subject;  
   
 // Content.js  
 class Content extends Component {
    render() {
      return (
        <article>
          <h2>{this.props.title}</h2>
          {this.props.desc}
        </article>
      )
    }
  }
  
 export default Content;  
 
 // TOC.js
 class TOC extends Component {
    render() {
      return (
       <nav>
         <ul>
             <li><a href="1.html"></a>HTML</li>
             <li><a href="2.html"></a>CSS</li>
             <li><a href="3.html"></a>JavaScript</li>
         </ul>
       </nav>
      );
    }
   }

 export default TOC;  

TOC는 아직 컨포넌트 내용을 수정하지 않은 상태이다.



src > components > TOC.js

 import React, { Component } from 'react';

 class TOC extends Component {
    render() {
        var list = [];
        var data = this.props.data
        var i = 0;

        while(i < data.length) {
            list.push(<li><a href={"/content/"+data[i].id}>{data[i].title}</a></li>);
            i = i + 1;
        }
        
      return (
       <nav>
         <ul>
             {list}
         </ul>
       </nav>
      );
    }
   }

 export default TOC;  
   

추가된 부분에 대해 해석을 해보면 이렇다.

 

var list = [];  // list라는 새로운 빈배열을 만든다.
var data = this.props.data // props에서 설명했지만, this.props.data는 state의 contents를 가져온다.
var i = 0;

while(i < data.length) {
   list.push(<li><a href={"/content/"+data[i].id}>{data[i].title}</a></li>);
   i = i + 1;
 }
// 빈 배열에 하나씩 넣어주는데, /content/는 임시 url정도고, 
data를 차례대로 id, title값을 가져와 넣어주게 된다.

<li><a href=/content/"+0}>HTML</a></li>
<li><a href=/content/"+1>CSS</a></li>
<li><a href=/content/"+2>JavaScript</a></li>
이 배열을 {list}로 담는다.

=> 이렇게 쓰는 이유는, 예를 들어 TOC의 수정부분이 생길 때마다 
TOC안에 들어가서 직접적으로 태그를 수정해주는 것보다,
state의 contetns내용을 수정할 수 있기 때문이다. 앞서 설명한 은닉화도 관련이 있다.

그런데 이렇게 여러개의 엘리먼트를 자동생성하는 경우, 에러가 발생한다.
Warning: Each child in a list should have a unique "key" prop.
(list의 자식 항목들은 key라는 props가 필요하다는 뜻)

 list.push(<li key={data[i].id}><a href={"/content/"+data[i].id}>{data[i].title}</a></li>);

key={data[i].id}같은 형식으로 추가해주면 된다.
key값은 무엇이든 상관없고 이런 이름으로 할 것이다. 라고 명시해준다고 이해하면 된다.