-
React 할 일 목록 만들기 ( TodoList ) 추가,수정,삭제,검색Programming/React 2020. 11. 22. 23:52반응형
실습은 npx react-creat-app [projectname] 으로 실습환경 구축
기능은 추가, 수정, 삭제, 검색을 만들도록 하겠습니다.
프로젝트 구조
실습코드
app.js
import React, { Component } from 'react'; import ToDoForm from './component/ToDoForm'; import ToDoList from './component/ToDoList'; import './App.css'; class App extends Component { id = 4; state = { toDoList: [ { id: 1, text: '러닝 뛰기', }, { id: 2, text: '공부하기', }, { id: 3, text: '독서하기', }, ], search: '', }; handleCreate = () => {}; handleUpdate = (id, data) => {}; handleRemove = (id) => {}; render() { const { toDoList } = this.state; return ( <div> <ToDoForm onCreate={this.handleCreate} /> <ToDoList data={toDoList} onUpdate={this.handleUpdate} onRemove={this.handleRemove} /> </div> ); } } export default App;
ToDoForm 컴포넌트는 할일 목록을 입력받아 toDoList 배열에 추가할 props handleCreate를 전달한다.
ToDoList는 할일 목록을 출력해주는 컴포넌트로 props로 toDoList, handleUpdate, handleRemove 를 컴포넌트에 전달한다.
우선 ToDoList 컴포넌트를 작성하여 미리 작성된 배열 오브젝트들을 보여주도록 하겠습니다.
ToDoList.js
import React, { Component } from 'react'; import ToDoInfo from './ToDoInfo'; class ToDoList extends Component { state = { style: { border: '1px solid black', padding: '25px', margin: '15px', }, }; render() { const { data, onUpdate, onRemove } = this.props; return ( <div> <ul> {data.map((data) => ( <li style={this.state.style}> <ToDoInfo data={data} onUpdate={onUpdate} onRemove={onRemove} /> </li> ))} </ul> </div> ); } } export default ToDoList;
props로 전달받은 data를 가져와 map 메소드를 사용하여 li를 출력해주도록 합니다.
여기서 li에 ToDoInfo 컴포넌트를 해준 이유는 map으로 각각의 배열을 출력할 때 해당하는 정보를 ToDoInfo 컴포넌트로 전달하여 보여주기 위함입니다.
ToDoInfo.js
import React, { Component } from 'react'; class ToDoInfo extends Component { render() { const { data, onUpdate, onRemove } = this.props; return ( <div> <span>{data.text}</span> </div> ); } } export default ToDoInfo;
여기까지 작성했다면 아래와 같이 결과가 출력될 것 입니다.
이제 여기서 각각의 ToDoInfo에 수정과 삭제를 위해 버튼을 하나 생성하고 거기에 맞는 핸들 메소드를 작성하도록 하겠습니다.
수정
import React, { Component } from 'react'; class ToDoInfo extends Component { state = { toggle: false, text : '', style : { margin: '10px', }, }; handleChange = ( e ) => { this.setState({ [e.target.name]: e.target.value, }); }; handleToggleChange = () => { const { toggle, text } = this.state; const { data, onUpdate } = this.props; // false -> true if (!toggle) { this.setState({ text : data.text, toggle: true, }); } else { onUpdate(data.id, { text: text }); this.setState({ toggle: false, }); } // ture -> false }; handleRemove = () => {}; render() { const { data } = this.props; const { toggle, text } = this.state; console.log(data.text + ' 렌더링 됐어유'); return ( <div> {toggle ? ( <input style={this.state.style} onChange={this.handleChange} value={text} name="text" ></input> ) : ( <span style={this.state.style}>{data.text}</span> )} <button onClick={this.handleToggleChange}>{toggle ? '적용' : '수정'}</button> <button onClick={this.handleRemove}>삭제</button> </div> ); } } export default ToDoInfo;
toggle 을 만들어 false와 true일 때 handleToggleChange 메소드를 이용하여 각각에 맞는 이벤트들을 처리하도록 했습니다.
handleToggleChange() 메소드에서는 필요한게 두 가지 입니다.
toggle이 false -> true 일 때와 ture -> false일 때 입니다.
false -> ture : 수정 버튼을 눌렀을 경우 input 창 value에 기존에 입력되었던 data.text값을 가져온다
ture => false : 적용 버튼을 누른 경우로 업데이트를 위해 App.js 컴포넌트의 handleUpdate로 보낸다
// App.js 에서의 handleUpdate 부분 handleUpdate = (id, data) => { console.log(id); console.log(data); };
이렇게 바뀐 값들이 handleUpdate 로 넘오오게 된다.
App.js / handleUpdate 부분
handleUpdate = (id, data) => { const { toDoList } = this.state; this.setState({ toDoList: toDoList.map((toDoList) => { console.log(toDoList); if (toDoList.id === id) { console.log(toDoList.id + ' / ' + id); return { id, ...data, }; } return toDoList; }), }); };
map 메소드를 사용하여 id값이 서로 같은 경우 수정하려는 배열이 맞으므로 거기만 새로 받아온 data 를 반환해준다.
삭제
ToDoInfo.js / handleRemove 부분
handleRemove = () => { const { data, onRemove } = this.props; onRemove(data.id); };
App.js / handleRemove 부분
handleRemove = (id) => { const { toDoList } = this.state; this.setState({ toDoList: toDoList.filter((data) => data.id !== id), }); };
삭제는 비교적 간단합니다. id값을 가져와 filter 메소드로 받아온 id값과 틀린 것만 toDoList에 반환시키고 id값이 같을 경우 반환시키지 않으면 됩니다.
추가
ToDoForm.js
import React, { Component } from 'react'; class ToDoForm extends Component { state = { text: '', }; handleChange = (e) => { this.setState({ [e.target.name]: e.target.value, }); }; handleSubmit = (e) => { e.preventDefault(); this.props.onCreate(this.state); this.setState({ text: '', }); }; render() { const { text } = this.state; return ( <div> <form onSubmit={this.handleSubmit}> <input value={text} name="text" placeholder="..입력" onChange={this.handleChange}></input> <button type="submit">추가</button> </form> </div> ); } } export default ToDoForm;
input onChange이벤트로 입력받은 값을 state 에 저장하고 submit 이벤트 발생시 handleSubmit에서는 this.props.onCreate(this.state)로 현재의 state 값을 부모 컴포넌트로 값을 보낸다.
App.js / handleCreate 부분
handleCreate = (data) => { console.log(data); };
리스트에 추가하려는 데이터가 console창에서 확인결과 잘 받아오고 있다.
이제 받아온 값을 기존의 toDoList 배열에 추가만 해주면 된다.
handleCreate = (data) => { const { toDoList } = this.state; this.setState({ toDoList: toDoList.concat({ id: this.id++, ...data, }), }); };
concat을 사용하여 기존에 있던 toDoList배열에 추가하면 끝입니다.
검색
검색은 간단히 indexOf을 사용하여 ToDoList에 해당하는 값만 전달하여 검색하는 방식으로 하면 간단하게 구현할 수 있습니다.
App.js / handleSearch 부분
handleSearch = (e) => { this.setState({ [e.target.name]: e.target.value, }); };
App.js / render 부분
render() { const { toDoList, search } = this.state; return ( <div> <ToDoForm onCreate={this.handleCreate} /> <input value={search} name="search" onChange={this.handleSearch} placeholder=" ..검색" /> <ToDoList data={toDoList.filter((data) => data.text.indexOf(search) !== -1)} onUpdate={this.handleUpdate} onRemove={this.handleRemove} /> </div> ); }
input에 onChange 를 사용해서 state에 있는 search 값을 저장해주도록했습니다.
그리고 ToDoList 컴포넌트에 data props를 전달해 줄 때 filter 메소드를 사용하여 text에 검색하려는 단어가 있을 경우에만 배열을 반환하여 ToDoList 컴포넌트에 전달하도록 했습니다.
'Programming > React' 카테고리의 다른 글
React useEffect 사용 title 변경하기 (2) 2021.04.25 React FadeIn 함수 만들기 (useRef, useEffect) (0) 2021.04.25 React window.confirm 기능 구현 (0) 2020.05.15 React 간단한 tab 만들어보기 (hook 활용) (0) 2020.05.13 React shouldComponentUpdate 컴포넌트 최적화 (0) 2020.05.12