Back-End/React.js, 스프링 부트, AWS로 배우는 웹 개발 101

[React.js, 스프링 부트, AWS로 배우는 웹 개발 101][프론트엔트 개발] - 서비스 개발2

얄루몬 2022. 6. 16. 23:42

본 포스팅은 '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. 수정

수정을 하는 경우는 이 프로젝트에서 두 가지의 경우이다.

  1. 체크박스를 체크하는 경우
  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;