티스토리 뷰

 React에서는 기존에 javascript에서 배열을 다루듯이 하면 안됩니다. state의 내부의 값을 직접적으로 변경해서는 안되기 때문입니다. 이를 불변성 유지라고 합니다. push, splice, unshift, pop 같은 내장 함수는 배열자체를 직접 수정하게 되므로 적합하지 않고, concat, slice, map, filter와 같이 기존 배열을 기반으로 새로운 배열을 만드는 함수를 사용해야 합니다. 불변성을 유지해야 필요한 상황에 맞게 리렌더링이 되도록 설계할 수 있고, 성능도 최적화 할 수 있기 때문입니다.


데이터 추가


 기존에 만든 AccountBookForm에서 추가한 데이터를 실제 배열에 추가해 보겠습니다. App에서 제어하도록 하겠습니다.


 App.js 파일을 다음과 같이 수정해주세요.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// App.js
import React, { Component } from "react";
import "./App.css";
 
import AccountBookForm from "./components/AccountBookForm";
 
class App extends Component {
  // field
  currentId = 1;
 
  state = {
    list: [
      {
        id: 0,
        type: "지출",
        price: 3800,
        usage: "점심 식비",
        date: "2019. 1. 16 오후 1:12:33"
      },
      {
        id: 1,
        type: "수입",
        price: 20000,
        usage: "중고책 판매",
        date: "2019. 1. 18 오전 10:17:21"
      }
    ]
  };
 
  add = data => {
    const { list } = this.state;
    this.setState({
      list: list.concat({ id: ++this.currentId, ...data })
    });
  };
 
  render() {
    const { list } = this.state;
    return (
      <React.Fragment>
        <AccountBookForm onAdd={this.add} />
        {JSON.stringify(list)}
      </React.Fragment>
    );
  }
}
 
export default App;
cs


 새로운 내용을 추가할 때마다 id를 정해주기 위해 클래스 필드로 id를 지정했습니다. state는 보통 렌더링과 관련된 값들을 넣기 때문에 id를 state로 지정하지는 않았습니다. 위의 2개의 데이터에 추가로 새로운 내용을 넣어 보겠습니다. 결과는?



 새로운 데이터의 id와 함께 내용이 추가된 것을 확인할 수 있습니다.


컴포넌트 추가 - AccountBookInfo


 src/components/AccountBookInfo.js 파일을 생성해 주세요. 각 가계부 정보를 보여주는 컴포넌트입니다. 


 components/AccountBookInfo.js 파일을 다음과 같이 작성합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// components/AccountBookInfo.js
import React, { Component } from "react";
 
class AccountBookInfo extends Component {
  static defaultProps = {
    data: {
      id: 0,
      type: "분류",
      price: 0,
      usage: "-",
      date: "-"
    }
  };
 
  render() {
    const style = {
      border: "1px solid black",
      padding: "5px",
      margin: "5px"
    };
 
    const { type, price, usage, date } = this.props.data;
 
    return (
      <div style={style}>
        <div>{type}</div>
        <div>{price}</div>
        <div>{usage}</div>
        <div>{date}</div>
      </div>
    );
  }
}
 
export default AccountBookInfo;
cs


 data가 undefined일 경우 비구조화 할당을 사용할 수 없기 때문에 defaultProps로 기본값을 넣어 주었습니다.


컴포넌트 추가 - AccountBookInfoList


 src/components/AccountBookInfoList.js 파일을 생성해 주세요. 여러 개의 AccountBookInfo를 보여주는 컴포넌트입니다.


 components/AccountBookInfoList.js 파일을 다음과 같이 작성합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// components/AccountBookInfoList.js
import React, { Component } from "react";
import AccountBookInfo from "./AccountBookInfo";
 
class AccountBookInfoList extends Component {
  static defaultProps = {
    list: []
  };
 
  render() {
    const { list } = this.props;
    const infoList = list.map(info => (
      <AccountBookInfo key={info.key} data={info} />
    ));
 
    return <React.Fragment>{infoList}</React.Fragment>;
  }
}
 
export default AccountBookInfoList;
cs


 이 컴포넌트에서 map 함수를 통해 list의 배열 값을 infoList라는 JSX로 변환해 주었습니다. 이 과정에서 AccountBookInfo에 key라는 값을 전달해 주었습니다. 이 부분은 배열 렌더링에서 꼭 필요한 값입니다. 이 key를 부여하지 않으면 자동으로 배열의 index로 key가 할당됩니다. 이 부분이 무엇이 문제가 될 수 있는가 하면, 예를 들어 총 3개짜리 배열에 1번째 index(배열의 index는 0부터 시작)를 key로 가지고 있다고 가정해 봅시다. 여기서 1번째 index에 새로운 값이 추가되었다고 하면, 기존의 1번째 index는 한 칸 뒤로 밀려 2번째 index가 되고 마찬가지로 2번째 index도 한 칸 밀려 3번째 index가 됩니다. 우리는 중간에 새로운 값 하나를 집어 넣기만 하면 되는데 이 과정에서 다른 값들의 index까지 변하게 되므로 상당히 비효율적입니다. 그래서 우리는 index외에 별도로 고유 key 값을 설정하여 이 문제를 해결합니다. 이를 통해, 값의 업데이트가 최소화되어 최적화 또한 이루어집니다. 따라서 값이 추가될 때, 새로운 DOM 하나만 추가되고 나머지는 유지됩니다. 실제 서비스에서 데이터베이스에서 값을 가져온다고 하면 해당 데이터를 가르키는 고유의 id가 있을 것입니다. 그 값을 고유의 key 값으로 사용하면 됩니다. 위의 예제에서는 기존에 App.js에서 사용하고 있던 id를 그냥 key 값으로 사용했습니다. 결과는?



References


[Velopert 블로그 배열 다루기(1) 생성과 렌더링] https://velopert.com/3636


댓글