본 포스팅은 'React.js, 스프링 부트, AWS로 배우는 웹 개발 101 - 김다정'님의 책을 보고 작성되었습니다.
목차
1. 삭제
2. 수정
1. 삭제
- 삭제 기능은 각 리스트 아이템의 오른쪽에 삭제 아이콘을 추가해주어야 한다.(UI 부분)
- 그 뒤 삭제 버튼을 누르면 아이템이 삭제되는 기능을 추가한다.(이벤트 핸들러 사용 부분)
삭제 아이콘 추가
import React from "react";
import {ListItem, ListItemText, InputBase, Checkbox, ListItemSecondaryAction, IconButton} from '@material-ui/core';
import DeleteOutline from '@material-ui/icons/DeleteOutlined';
class Todo extends React.Component {
constructor(props){
super(props);
this.state={item: props.item};
}
render() {
const item = this.state.item;
return (
<ListItem>
<Checkbox checked={item.done}/>
<ListItemText>
<InputBase
inputProps={{"aria-label":"naked"}}
type = "text"
id = {item.id}
name = {item.id}
value = {item.title}
multiline = {true}
fullWidth = {true}
/>
</ListItemText>
<ListItemSecondaryAction>
<IconButton aria-label="Delete Todo">
<DeleteOutline />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
);
}
}
export default Todo;
App.js에서 delete()함수 작성과 Todo에 delete() 함수 연결
이 역시 앞에 포스팅에서 언급하였듯 관리하는 객체가 상위 컴포넌트에 있기때문에 함수는 App에서 작성한 뒤 사용은 하위 컴포넌트에 props로 넘겨준 뒤 바인딩해서 사용할 수 있게 해야 한다.
import React from 'react';
import Todo from './Todo';
import {Paper, List, Container} from '@material-ui/core';
import "./App.css";
import AddTodo from './AddTodo';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
items:[
{id:"0", title:"Hello world 1", done:true},
{id:"1", title:"Hello world 2", done:false},
],
};
}
// add() 함수 추가
add = (item) => {
const thisItems = this.state.items;
item.id = "ID" + thisItems.length; // key를 위한 id 추가
item.done = false; // done 초기화
thisItems.push(item); // 리스트에 아이템 추가
this.setState({items:thisItems}); //업데이트의 경우엔 반드시 this.setState로 진행
console.log("items: ", this.state.items);
}
delete = (item) => {
const thisItems = this.state.items;
console.log("Before Update Items: ", this.state.items)
const newItems = thisItems.filter(e => e.id !== item.id);
this.setState({items: newItems}, ()=>{
//디버깅 콜백
console.log("Update Items: ", this.state.items)
})
}
render() {
var todoItems = this.state.items.length > 0 && (
<Paper style={{margin:16}}>
<List>
{this.state.items.map((item,idx)=>(
<Todo item ={item} key ={item.id} delete = {this.delete} />
))}
</List>
</Paper>
);
return (
<div className='App'>
<Container maxWidth="md">
<AddTodo add={this.add} />
<div className='TodoList'>{todoItems}</div>
</Container>
</div>
);
}
}
export default App;
delete = (item) => {
const thisItems = this.state.items;
console.log("Before Update Items: ", this.state.items)
const newItems = thisItems.filter(e => e.id !== item.id);
this.setState({items: newItems}, ()=>{
//디버깅 콜백
console.log("Update Items: ", this.state.items)
})
}
<Todo item ={item} key ={item.id} delete = {this.delete} />
Todo.js(하위 컴포넌트)에서 delete() 함수(상위 컴포넌트 함수 props로 받아서) 추가
import React from "react";
import {ListItem, ListItemText, InputBase, Checkbox, ListItemSecondaryAction, IconButton} from '@material-ui/core';
import DeleteOutline from '@material-ui/icons/DeleteOutlined';
class Todo extends React.Component {
constructor(props){
super(props);
this.state={item: props.item};
this.delete = props.delete;
}
deleteEventHandler = () => {
this.delete(this.state.item)
}
render() {
const item = this.state.item;
return (
<ListItem>
<Checkbox checked={item.done}/>
<ListItemText>
<InputBase
inputProps={{"aria-label":"naked"}}
type = "text"
name = {item.id}
value = {item.title}
multiline = {true}
fullWidth = {true}
/>
</ListItemText>
<ListItemSecondaryAction>
<IconButton
aria-label="Delete Todo"
onClick={this.deleteEventHandler}>
<DeleteOutline />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
);
}
}
export default Todo;
this.delete = props.delete;
deleteEventHandler = () => {
this.delete(this.state.item)
}
<IconButton
aria-label="Delete Todo"
onClick={this.deleteEventHandler}>
2. 수정
수정을 하는 경우는 이 프로젝트에서 두 가지의 경우이다.
- 체크박스를 체크하는 경우
- 타이틀을 변경하고 싶은 경우
import React from "react";
import {ListItem, ListItemText, InputBase, Checkbox, ListItemSecondaryAction, IconButton} from '@material-ui/core';
import DeleteOutline from '@material-ui/icons/DeleteOutlined';
class Todo extends React.Component {
constructor(props){
super(props);
this.state={item: props.item, readOnly: true};
this.delete = props.delete;
}
deleteEventHandler = () => {
this.delete(this.state.item)
}
offReadOnlyMode = () => {
console.log("Event!", this.state.item.readOnly)
this.setState({readOnly: false}, ()=>{
console.log("ReadOnly? ", this.state.readOnly)
});
}
enterKeyEventHandler = (e) => {
if(e.key === "Enter"){
this.setState({readOnly: true});
}
};
editEventHandler = (e) => {
const thisItem = this.state.item;
thisItem.title = e.target.value;
this.setState({item: thisItem});
}
checkboxEventHandler = (e) => {
const thisItem = this.state.item;
thisItem.done = !thisItem.done;
this.setState({item:thisItem});
}
render() {
const item = this.state.item;
return (
<ListItem>
<Checkbox checked={item.done} onChange={this.checkboxEventHandler}/>
<ListItemText>
<InputBase
inputProps={{
"aria-label":"naked",
readOnly:this.state.readOnly,
}}
type = "text"
id = {item.id}
name = {item.id}
value = {item.title}
multiline = {true}
fullWidth = {true}
onClick= {this.offReadOnlyMode}
onChange={this.editEventHandler}
onKeyPress = {this.enterKeyEventHandler}
/>
</ListItemText>
<ListItemSecondaryAction>
<IconButton
aria-label="Delete Todo"
onClick={this.deleteEventHandler}>
<DeleteOutline />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
);
}
}
export default Todo;