일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- js
- 사기
- REACT
- 정규식
- webpack.config.js
- 해외여행
- Webpack
- 삼성무선청소기제트
- 유효성검사
- plugin
- 자동완성
- 네이버페이사기
- 마사지
- 특수문자
- 여행
- 스노쿨링
- 중고거래사기
- 맛사지
- 정직하게사세요
- Hooks
- 세부
- 중고나라
- ES6
- JavaScript
- 스쿠버다이빙
- autocomplate
- 중고나라사기
- 막탄
- 구분
- Today
- Total
Ryu.log
[ React-Tutorial-07 ] 배열다루기1 생성과 랜더링 본문
이번에는 리엑트 프로젝트에서 배열을 다루는 방법을 알아보자. 리엑트에서는 배열을 다룰 때 평상시에 하던것 처럼 하면 안된다.
데이터 추가의 경우, 자바스크립트에서 배열을 다뤄본 사람이라면 그냥 배열에 데이터를 추가할 때,
push를 사용하니까 this.state.array.push('some value'); 이런식으로 하면 되겠지? 라고 생각할 수 있다.
리엑트에서는 state 내부의 값을 직접적으로 수정하면 절대로 안된다. 이를 불변성 유지라고 하는데,
push, splice, unshift, pop 같은 내장함수는 배열 자체를 직접 수정하게 되므로 적합하지 않다.
그 대신에, 기존의 배열에 기반하여 새 배열을 만들어내는 함수인 concat, clice, map, filter 같은 함수를 사용해야 한다.
리엑트에서 불변성 유지가 중요한 이유는 불변성을 유지해야, 리엑트에서 모든것들이 필요한 상황에 리렌더링 되도록 설계 할 수 있고,
그렇게 해야 나중에 성능도 최적화 할 수 있기 때문이다.
01. 데이터 추가
// file: src/App.js import React, { Component } from 'react'; import PhoneForm from './components/PhoneForm'; class App extends Component { id = 2 state = { information: [ { id: 0, name: '유준호', phone: '010-0000-0000' }, { id: 1, name: '한승훈', phone: '010-0000-0001' } ] } handleCreate = (data) => { const { information } = this.state; this.setState({ information: information.concat({ id: this.id++, ...data }) }) } render() { const { information } = this.state; return ( <div> <phoneform oncreate="{this.handleCreate}"> {JSON.stringify(information)} </phoneform> </div> ); } } export default App;
information 배열안에 id 값은 각 데이터를 식별하기 위한 값이다. 그리고 이값은 데이터를 추가할 때마다 숫자를 1씩 더해준다.
그리고 상단 (state바로 위) id 값의 경우에는 컴포넌트 일반 클래스 내부 변수로서 선언해주었다. 컴포넌트 내부에서 필요한 값 중에서,
렌더링 되는것과 상관이 없는 것들은 굳이 state에 넣어줄 필요가 없다.
render 함수에서는 information 값을 문자열로 변환하여 보여주었다. 잠시 후에는 이 데이터를 컴포넌트 형태로 렌더링 해볼것이다.
일단 코드를 저장하고 새로운 데이터를 입력해보면
위와 같은 결과가 확인된다.
02. 데이터 렌더링
- PhoneInfo : 각 전화번호 정보를 보여주는 컴포넌트
- PhoneInfoList : 여러개의 PhoneInfo 컴포넌트를 보여주는 컴포넌트
일단 PhoneInfo 부터 만들어보자.
// file: src/components/PhoneInfo.js import React, { Component } from 'react'; class PhoneInfo extends Component { static defaultProps = { info: { name: '이름', phone: '010-0000-0000', id: 0 } } render() { const style = { border: '1px solid black', padding: '8px', margin: '8px' }; const { name, phone, id } = this.props.info; return ( <div style={style}> <div><b>{name}</b></div> <div>{phone}</div> </div> ); } } export default PhoneInfo;
우리는 info라는 객체를 props로 받아와서 렌더링 해줄것이다. 혹시라도, info값을 전달해주는 것을 까먹게 된다면 컴포넌트가 크래쉬 될것이다.
info가 undefined일 때는 비구조화 할당을 통해 내부의 값을 받아올수 없기 때문이다.
그렇기 때문에 defultProps를 통하여 info의 기본값을 설정해 주었다.
그 다음에는, PhoneInfoList 컴포넌트를 만들어보자.
// src/components/PhoneInfoList.js import React, { Component } from 'react'; import PhoneInfo from './PhoneInfo'; class PhoneInfoList extends Component { static defaultProps = { data: [] } render() { const { data } = this.props; const list = data.map( info => (<PhoneInfo key={info.id} info={info}/>) ); return ( <div> {list} </div> ); } } export default PhoneInfoList;
이 컴포넌트에서는 data라는 배열을 가져와서 map을 통하여 JSX로 변환을 해준다. 이 과정에서, key라는 값도 설정이 되었는데, 여기서 key는,
리엑트에서 배열을 렌더링 할 때 꼭 필요한 값이다. 리엑트는 배열을 렌더링 할 때 값을 통하여 업데이트 성능을 최적화 하는데, 한번 아래 예시를 살펴보자.
<div>A</div> <div>B</div> <div>C</div> <div>D</div>
만약에 key를 부여하지 않으면, 배열의 index 값이 자동으로 key로 설정이 되는데, 이 때 여기서 B와 C 사이에 X를 집어넣는다고 가정해보자.
key가 배열의 인덱스로 설정된다면 아래와 같이 된다.
<div key={0}>A</div> <div key={1}>B</div> <div key={2}>C</div> <div key={3}>D</div>
배열의 인덱스가 Key 값으로 사용되었다.
<div key={0}>A</div> <div key={1}>B</div> <div key={2}>X</div> [C -> X] <div key={3}>D -> C</div> [D -> C] <div key={4}>D</div> [새로 생성됨]
보면, 굉장히 비효율적이다. 사실상 중간에 끼워넣기만 하면 되는건데, 배열의 index를 key로 사용하게 되어 중간에 값이 들어가면 index도 함께 바뀌어 버리게 되니, X 아래로는 값이 전부 바뀌어 버리게 된다.
key를 배열의 index값으로 사용하는게 아니라, 우리가 데이터를 추가 할 때마다 고정적인 고유값을 부여해주면,
리엑트가 변화를 감지해내고 업데이트를 하게 될 때 조금 더 똑똑하게 처리 할 수 있게된다.
<div key={0}>A</div> <div key={1}>B</div> <div key={2}>C</div> <div key={3}>D</div>
이 번에, 다시 B와 C 사이에 다시 X를 넣어보았다. 이번에는 key값은 고정된 고유값이다.
<div key={0}>A</div> <div key={1}>B</div> <div key={5}>X</div> [새로 생성됨] <div key={2}>C</div> [유지됨] <div key={3}>D</div> [유지됨]
결국 새로운 DOM은 하나만 생성되고, 나머지는 그대로 유지된다.
그 이유로 key값은 언제나 고유해야 한다.
실제 프로젝트를 예로 들자면, 우리가 데이터베이스에 데이터를 추가하면 주로 해당 데이터를 가르키는 고유id가 있다.
그러한 데이터를 리엑트에서 렌더링하게 된다면 그 고유 id를 가지고 key로 사용하면 된다.
현재 우리의 경우엔 전화번호 정보에서 id 값을 key값으로 사용해 주었다.
이제 PhoneInfoList 컴포넌트를 App에 렌더링 해보자. 그리고 data값을 props로 전달해보자.
// file: src/App.js import React, { Component } from 'react'; import PhoneForm from './components/PhoneForm'; import PhoneInfoList from './components/PhoneInfoList'; class App extends Component { id = 2 state = { information: [ { id: 0, name: '김민준', phone: '010-0000-0000' }, { id: 1, name: '홍길동', phone: '010-0000-0001' } ] } handleCreate = (data) => { const { information } = this.state; this.setState({ information: information.concat({ id: this.id++, ...data }) }) } render() { return ( <div> <PhoneForm onCreate={this.handleCreate} /> <PhoneInfoList data={this.state.information}/> </div> ); } } export default App;
코드를 저장하고, 전화번호 정보들이 잘 나타나는지 확인해보자. 그리고 새로운 데이터도 등록해보자.
잘 작동했다면 위와같은 화면이 출력될 것이다.
가끔씩은, 데이터에 고유 값이 없을 수 도 있다. 그럴 때에는 만약에 key 값을 빼먹으면 렌더링이 되긴 하지만 개발자도구 콘솔에서 경고창이 뜨게된다.
만약에 그 경고가 보고싶지 않다면 아래와 같이 작업할 수 있다.
const list = data.map( (info, index) => (<PhoneInfo key={index} info={info}/>) );
하지만, 꼭 기억하자! 위처럼 처리하면 단순히 경고만 감출뿐이고 성능상으로는 key가 없는것과 동일하다.
우리는 이번에 데이터를 배열에 어떻게 등록을 해야 할 지, 그리고 등록한 데이터를 어떻게 보여줄 지 배웠다. 꼭! 기억해야할 것은
배열을 렌더링 하게 될 때에는 꼭 고유값을 key로 사용해야 한다는 것이다. 그리고, 불변성 유지를 위하여 데이터를 조작 할 때에는 기존의 배열을 건들이지 않는
방식으로 해야하는데, 이 불변성 유지에 대해서는 나중에 더 자세히 알아보자.
이 글은 Velopert님의 블로그에서 React 포스팅을보며 실습하며 공부한 자료입니다.
'Prev-content' 카테고리의 다른 글
[ React-Tutorial-09 ] 불변성을 지키는 이유와 업데이트 최적화 (0) | 2018.06.05 |
---|---|
[ React-Tutorial-08 ] 배열다루기2 제거와 수정 (0) | 2018.06.05 |
[ React-Tutorial-06 ] input 상태관리 (0) | 2018.05.30 |
[ React-Tutorial-05 ] LifeCycle API (0) | 2018.05.28 |
[ React-Tutorial-04 ] props와 state (0) | 2018.05.25 |