React 배열
데이터 추가
리액트에서는 this.state.array.push('some value');
와 같이 state 내부의 값을 직접적으로 수정하면 절대 안됨!
이를 불변성 유지라고 하는데 push, splice, unshift, pop 같은 내장함수는 배열자체를 직접 수정하게 되므로 적합하지 않음
그 대신 기존의 배열에 기반하여 새 배열을 만들어내는 함수인 concat, slice, map, filter 같은 함수를 사용해야함
리액트에서 불변성 유지가 중요한 이유는 불변성을 유지해야, 리액트에서 모든것들이 필요한 상황에 리렌더링 되도록 설계할 수 있기 때문
그렇게 해야 나중에 성능도 최적화 할 수 있기 때문
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)}
</div>
);
}
}
export default App;
- render함수에서 JSON.stringify를 활용해 information 값을 문자열로 변환
데이터 렌더링
- 자바스크립트 배열의 내장함수인 map을 사용하여 위 배열을 컴포넌트로 변환해서 바꿔줌
map 함수 알아보기
1. forEach, push 함수 사용
const a = [1,2,3,4,5];
const b = [];
b.forEach(number => b.push(number * 2));
2. map 함수 사용
const a = [1,2,3,4,5];
const b = a.map(number => number * 2);
컴포넌트 만들기
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 일 때에는 비구조화 할당을 통해 내부의 값을 받아올 수 없기 때문
- 그렇기 때문에 defaultProps를 통해 info의 기본값을 설정해줌
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 는 리액트에서 배열을 렌더링을 할 때 꼭 필요한 값. 리액트는 배열을 렌더링 할 때 값을 통하여 업데이트 성능을 최적화
예시
<div>A</div>
<div>B</div>
<div>C</div>
<div>D</div>
- 만약에 key 를 부여하지 않으면, 배열의 index 값이 자동으로 key 로 설정
<div key={0}>A</div>
<div key={1}>B</div>
<div key={2}>C</div>
<div key={3}>D</div>
- 여기서 B와 C 사이에 X를 집어넣는다고 가정. key가 배열의 인덱스로 설정
- 배열의 인덱스가 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> [새로 생성됨]
- key를 배열의 index값으로 사용하는게 아니라, 우리가 데이터를 추가할 때마다 고정적인 고유 값을 부여해주면, 리액트가 변화를 감지해내고 업데이트를 할 때 효율적이게 처리
<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는 고유값으로 설정
데이터 제거
- 배열에서 3을 제거
- slice와 concat 사용
array.slice(0,2).concat(array.slice(3,5)) // [1, 2, 4, 5]
- 전개연산자 사용하여 slice, concat 사용
[ ...array.slice(0,2), ...array.slice(3,5) ];
- filter 내장함수 사용
array.filter(num => num !== 3); // [1, 2, 4, 5]
데이터 수정
- 수정할때도 마찬가지로 불변성을 지켜야함. 기존의 배열과 그 내부에 있는 객체를 직접적으로 수정하면 안됨
const array = [
{ id: 0, text: 'hello', tag: 'a' },
{ id: 1, text: 'world' , tag: 'b' },
{ id: 2, text: 'bye', tag: 'c' }
];
const modifiedArray = array.map(item => item.id === 1
? ({ ...item, text: 'Korea' }) // id 가 일치하면 새 객체를 만들고, 기존의 내용을 집어넣고 원하는 값 덮어쓰기
: item // 바꿀 필요 없는것들은 그냥 기존 값 사용
Comments