해당 게시물은 인프런의 Velopert님의 유료 강의를 듣고 개인적으로 정리한 내용을 담고 있습니다👩💻
데이터 삭제하기
기존의 배열 데이터를 건들이지 않으면서 데이터를 제거하기 위해서는, 여러가지 방법이 있을 수 있다. 먼저 자바스크립트 배열을 가지고 연습해보자.
const arr = [1, 2, 3, 4, 5];
arr 배열에서 3을 제거해보자. 기존의 배열은 그대로 유지하고 새 배열을 만들어서 3을 제외시키겠다. 첫번째 방법은 slice와 concat을 이용하는 것이다. 3을 기준으로 좌측의 배열과 우측의 배열을 서로 합쳐주는 것이다.
array.slice(0,2).concat(array.slice(3,5)) //[1, 2, 4, 5]
배열 전개 연산자(...)를 사용하면 다음과 같이 구현할 수도 있다.
[ ...array.slice(0,2), ...array.slice(3,5) ];
하지만 이것보다 훨씬 간단한 방법도 가능하다. 배열에는 filter라는 내장함수가 있는데, 이 함수는 특정 조건에 부합되는 원소들만 뽑아서 새 배열을 만들어준다. 따라서 3을 제외한 배열을 만들기 위해서는 이러한 코드를 작성할 수 있다.
array.filter(num => num !== 3); //[1, 2, 4, 5]
이렇게 하면, 3이 아닌 것들만 필터링되어 새 배열을 만들어준다.
동일한 방식으로, 전화번호 정보를 데이터에서 제외시키는 기능을 구현해보자. id를 파라미터로 받아오는 hadleRemove 함수를 만들고, PhoneInfoList로 전달하자.
//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 })
})
}
handleRemove = (id) => {
const { information } = this.state;
this.setState({
information: information.filter(info => info.id !== id)
})
}
render() {
const { information } = this.state;
return (
<div>
<PhoneForm
onCreate={this.handleCreate}
/>
<PhoneInfoList
data={information}
onRemove={this.handleRemove}
/>
</div>
);
}
}
export default App;
PhoneInfoList에서는 props로 전달받은 onRemove를 그대로 전달해주겠다. 이 함수가 전달되지 않았을 경우를 대비하여 해당 props를 위한 defaultProps를 설정할 것이다. (항상 크래시 예방을 해줘야하나보다..!)
//src/components/PhoneInfoList.js
import React, { Component } from 'react';
import PhoneInfo from './PhoneInfo';
class PhoneInfoList extends Component {
static defaultProps = {
list: [],
onRemove: () => console.warn('onRemove not defined'),
}
render() {
const { data, onRemove } = this.props;
const list = data.map(
info => (
<PhoneInfo
key={info.id}
info={info}
onRemove={onRemove}
/>)
);
return (
<div>
{list}
</div>
);
}
}
export default PhoneInfoList;
그 다음에는 PhoneInfo 쪽에서 삭제 기능을 구현해준다. 삭제 버튼을 만들어서 해당 버튼에 이벤트를 설정하겠다.
//src/components/PhoneInfo.js
import React, { Component } from 'react';
class PhoneInfo extends Component {
static defaultProps = {
info: {
name: '이름',
phone: '010-0000-0000',
id: 0
},
}
handleRemove = () => {
// 삭제 버튼이 클릭되면 onRemove 에 id 넣어서 호출
const { info, onRemove } = this.props;
onRemove(info.id);
}
render() {
const style = {
border: '1px solid black',
padding: '8px',
margin: '8px'
};
const {
name, phone
} = this.props.info;
return (
<div style={style}>
<div><b>{name}</b></div>
<div>{phone}</div>
<button onClick={this.handleRemove}>삭제</button>
</div>
);
}
}
export default PhoneInfo;
데이터 수정하기
수정할때도 마찬가지로 불변성을 지켜줘야한다. 기존의 배열과, 그 내부에 있는 객체를 절대로 직접적으로 수정하면 안된다.
예를 들어서 다음과 같은 객체로 이루어진 배열이 있다고 가정해보자.
const array = [
{ id: 0, text: 'hello', tag: 'a' },
{ id: 1, text: 'world' , tag: 'b' },
{ id: 2, text: 'bye', tag: 'c' }
];
여기서 기존의 값은 건들이지 않고, id가 1인 객체의 text값을 'Korea'라는 값으로 바꾼 새로운 배열을 만들어보겠다.
const modifiedArray = array.map(item => item.id === 1
? ({ ...item,. text: 'Korea' }) // id 가 일치하면 새 객체를 만들고, 기존의 내용을 집어넣고 원하는 값 덮어쓰기
: item) // 바꿀 필요 없는것들은 그냥 기존 값 사용
같은 원리로 handleUpdate라는 함수를 만들어 전화번호 정보를 수정해보자. 이 함수는 id와 data라는 파라미터를 받아와서 필요한 정보를 업데이트 해준다. 이 handleUpdate는 PhoneInfoList와 onUpdate로 전달해준다.
//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 })
})
}
handleRemove = (id) => {
const { information } = this.state;
this.setState({
information: information.filter(info => info.id !== id)
})
}
handleUpdate = (id, data) => {
const { information } = this.state;
this.setState({
information: information.map(
info => id === info.id
? { ...info, ...data } // 새 객체를 만들어서 기존의 값과 전달받은 data 을 덮어씀
: info // 기존의 값을 그대로 유지
)
})
}
render() {
const { information } = this.state;
return (
<div>
<PhoneForm
onCreate={this.handleCreate}
/>
<PhoneInfoList
data={information}
onRemove={this.handleRemove}
onUpdate={this.handleUpdate}
/>
</div>
);
}
}
export default App;
이제 PhoneInfoList 컴포넌트를 업데이트 해준다.
//src/components/PhoneInfoList.js
import React, { Component } from 'react';
import PhoneInfo from './PhoneInfo';
class PhoneInfoList extends Component {
static defaultProps = {
data: [],
onRemove: () => console.warn('onRemove not defined'),
onUpdate: () => console.warn('onUpdate not defined'),
}
render() {
const { data, onRemove, onUpdate } = this.props;
const list = data.map(
info => (
<PhoneInfo
key={info.id}
info={info}
onRemove={onRemove}
onUpdate={onUpdate}
/>)
);
return (
<div>
{list}
</div>
);
}
}
export default PhoneInfoList;
그리고 데이터를 컴포넌트로 렌더링하는 과정에서 PhoneInfo에 onUpdate를 그대로 전달해주었다. 이제 PhoneInfo 컴포넌트를 업데이트 할 차례이다. 이번에 수정할 코드는 꽤 많은데, 주석을 읽어가면서 코드를 작성하자.
//src/components/PhoneInfo.js
import React, { Component } from 'react';
class PhoneInfo extends Component {
static defaultProps = {
info: {
name: '이름',
phone: '010-0000-0000',
id: 0
},
}
state = {
// 우리는 수정 버튼을 눌렀을 떄 editing 값을 true 로 설정해줄것입니다.
// 이 값이 true 일 때에는, 기존에 텍스트 형태로 보여주던 값들을
// input 형태로 보여주게 됩니다.
editing: false,
// input 의 값은 유동적이겠지요? input 값을 담기 위해서 각 필드를 위한 값도
// 설정합니다
name: '',
phone: '',
}
handleRemove = () => {
// 삭제 버튼이 클릭되면 onRemove 에 id 넣어서 호출
const { info, onRemove } = this.props;
onRemove(info.id);
}
// editing 값을 반전시키는 함수입니다
// true -> false, false -> true
handleToggleEdit = () => {
const { editing } = this.state;
this.setState({ editing: !editing });
}
// input 에서 onChange 이벤트가 발생 될 때
// 호출되는 함수입니다
handleChange = (e) => {
const { name, value } = e.target;
this.setState({
[name]: value
});
}
componentDidUpdate(prevProps, prevState) {
// 여기서는, editing 값이 바뀔 때 처리 할 로직이 적혀있습니다.
// 수정을 눌렀을땐, 기존의 값이 input에 나타나고,
// 수정을 적용할땐, input 의 값들을 부모한테 전달해줍니다.
const { info, onUpdate } = this.props;
if(!prevState.editing && this.state.editing) {
// editing 값이 false -> true 로 전환 될 때
// info 의 값을 state 에 넣어준다
this.setState({
name: info.name,
phone: info.phone
})
}
if (prevState.editing && !this.state.editing) {
// editing 값이 true -> false 로 전환 될 때
onUpdate(info.id, {
name: this.state.name,
phone: this.state.phone
});
}
}
render() {
const style = {
border: '1px solid black',
padding: '8px',
margin: '8px'
};
const { editing } = this.state;
if (editing) { // 수정모드
return (
<div style={style}>
<div>
<input
value={this.state.name}
name="name"
placeholder="이름"
onChange={this.handleChange}
/>
</div>
<div>
<input
value={this.state.phone}
name="phone"
placeholder="전화번호"
onChange={this.handleChange}
/>
</div>
<button onClick={this.handleToggleEdit}>적용</button>
<button onClick={this.handleRemove}>삭제</button>
</div>
);
}
// 일반모드
const {
name, phone
} = this.props.info;
return (
<div style={style}>
<div><b>{name}</b></div>
<div>{phone}</div>
<button onClick={this.handleToggleEdit}>수정</button>
<button onClick={this.handleRemove}>삭제</button>
</div>
);
}
}
export default PhoneInfo;
코드를 다 작성하였다면 다음과 같은 화면에 수정이 성공적으로 작동할 것이다.
'React' 카테고리의 다른 글
[React] 함수형 컴포넌트의 라이프 사이클(hook) (0) | 2021.05.07 |
---|---|
[React] 클래스형 컴포넌트와 함수형 컴포넌트를 알아보자 - (1) props, state (4) | 2021.05.06 |
리액트(ReactJS) 전화번호부 만들기 (2) (0) | 2021.05.04 |
리액트(ReactJS) 전화번호부 만들기 (1) (0) | 2021.05.04 |