코딩 노트
React04 - todoList CRUD / 백엔드 연결 본문
리엑트 CRUD 복습 예제
demo04 project 생성
cmd에 npx create-react-app demo04 --skip-git 해서 프로젝트를 생성한다.
bootstrap을 가져오기 위해 cmd에서
cd demo04로 생성한 프로젝트를 경로로 설정한 뒤
npm i bootstrap
npm i bootswatch
을 해서 설치한다.
index.css, App.css에 내용을 다 지운 뒤,
index.js에 구문을 추가한다. (demo03 거를 가져온다.)
import React from 'react';
import ReactDOM from 'react-dom/client';
//link 대신 import를 통해 설치한 라이브러리 CSS를 불러오도록 처리
//- node_modules에 설치한 요소들은 바로 이름을 사용하여 접근 가능
import 'bootstrap/dist/css/bootstrap.min.css';
//이곳에 bootswatch css파일을 불러오는 구문을 작성
import 'bootswatch/dist/lumen/bootstrap.min.css';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
demo04 > src > components 폴더 생성 후 js 파일을 만든다.
props => 태그를 창조하는 느낌
Jumbotron이라는 컴포넌트를 만들고 props로 태그를 줘서 다른 컴포넌트에서 부를 수 있다. (어느 화면에서나 나오게)
Jumbotron.js 생성
//컴포넌트 함수의 매개변수에 props를 적으면 전달되는 속성을 읽을 수 있다.
//- 이를 통해 상위 화면에서 전달되는 데이터를 이용한 프로그래밍이 가능
const Jumbotron = (props)=>{
return (
<div className="p-4 text-light bg-info rounded">
<h1>{props.title}</h1>
<p>{props.content}</p>
</div>
);
};
export default Jumbotron;
App.js에 구문을 추가한다.
import { useState } from "react";
import { FaXmark } from "react-icons/fa6";
import Jumbotron from "./components/Jumbotron";
function App() {
const [todoList, setTodoList] = useState([
{no:1, title:"학원가기", type:"공부"},
{no:2, title:"영어단어외우기", type:"공부"},
{no:3, title:"헬스장가기", type:"운동"},
{no:4, title:"친구만나기", type:"일상"}
]);
return (
<div className="container-fluid my-5">
<div className="row">
<div className="col-md-8 offset-md-2">
{/* 점보트론을 만들면서 제목과 내용을 전달 */}
<Jumbotron title="todoList" content="일정 관리 프로그램"/>
{/* 입력 화면 */}
{/* 출력 화면 */}
<div className="row mt-4">
{todoList.map(todo=>(
<div className="col-12 fs-4 mb-2">
<span className="badge bg-primary me-2">
{todo.type}
</span>
{todo.title}
<FaXmark className="text-danger"/>
</div>
))}
</div>
</div>
</div>
</div>
);
}
export default App;
cd demo04 (알맞은 프로젝트 경로로 들어간 후)
npm install react-icons --save (아이콘을 쓰기 위해 라이브러리 설치)
(npm version이 5가 넘으면 --save를 안 써도 된다.) (npm --version 을 치면 버전이 나온다.)
설치 후 임포트를 하고
import Jumbotron from "./components/Jumbotron";
이런 식으로 작성한다.
<FaXmark className="text-danger"/>
연결 시킬 때는 value, onChange, value까지 있어야 편하다.
등록, 삭제, 수정까지 구현한 App.js
import { useState } from "react";
import { FaXmark } from "react-icons/fa6";
import { FaRegEdit } from "react-icons/fa";
import { AiOutlinePlus } from "react-icons/ai";
import Jumbotron from "./components/Jumbotron";
function App() {
//목록을 위한 state (초기 data)
const [todoList, setTodoList] = useState([
{no:1, title:"학원가기", type:"공부"},
{no:2, title:"영어단어외우기", type:"공부"},
{no:3, title:"헬스장가기", type:"운동"},
{no:4, title:"친구만나기", type:"일상"}
]);
//1 등록을 위한 state
const [data, setData] = useState({title:"", type:""}); //사용자가 입력하는 데이터를 state로 만듬, 목록과 같아야함
//3 수정을 위한 state
const [editData, setEditData] = useState({title:"", type:""});
//1 e로 target을 꺼내고 name과 value를 꺼내서 data를 바꾸는 것이다.
const changeData = (e)=>{
setData({
...data,
[e.target.name] : e.target.value //[e.target.name]은 필드명이 변수일 때
});
};
//1 입력한 데이터를 추가하는 함수
const addTodoList = ()=>{
//data의 내용을 todoList에 추가 후 data를 초기화하는 것이 목표
//내용 검사 코드 추가 if(마음에 안 들면) return;
if(data.title.length === 0 || data.type.length === 0) return; //칸이 비어있으면
//백엔드 가면 시퀀스가 대체하는 부분 (번호 추가하는 부분)
const last = todoList.length-1;
const no = todoList.length === 0 ? 1 : todoList[last].no + 1;
setTodoList([
...todoList, //todoList에 있는 건 다 유지를 시키고
{
...data,
no:no //추가적으로 한 개만...
}
]);
setData({title:"", type:""}); //데이터 초기화
};
//2 todo 항목 삭제
const deleteTodoList = (todo) => {
const newTodoList = todoList.filter(t => t.no !== todo.no); //다른 것만 추려라
setTodoList(newTodoList);
};
//3 todo 수정을 위한 선택
const editTodoList = (todo) => {
// setEditData(todo); //안 되는 코드(얕은 복사, shallow copy)
setEditData({...todo}); //가능한 코드(깊은 복사, deep copy)
};
//3
const changeEditData = e=>{
setEditData({
...editData,
[e.target.name] : e.target.value
});
};
return (
<div className="container-fluid my-5">
<div className="row">
<div className="col-md-8 offset-md-2">
{/* 점보트론을 만들면서 제목과 내용을 전달 */}
<Jumbotron title="todoList" content="일정 관리 프로그램"/>
{/* 입력 화면 */}
<div className="row mt-4">
<div className="col-6">
<input className="form-control" name="title" value={data.title}
onChange={changeData}/>
</div>
<div className="col-3">
<select className="form-select" name="type" value={data.type}
onChange={changeData}>
<option value="">선택하세요.</option>
<option>일상</option>
<option>약속</option>
<option>취미</option>
<option>공부</option>
<option>운동</option>
</select>
</div>
<div className="col-3">
<button className="btn btn-success" onClick={addTodoList}> {/* e를 써도 전달할 내용이 없음 */}
<AiOutlinePlus/>
추가
</button>
</div>
</div>
<hr/>
{/* 수정 화면 */}
<div className="row mt-4">
<div className="col-6">
<input type="text" name="title" value={editData.title} onChange={changeEditData}/>
</div>
<div className="col-3">
<select name="type" value={editData.type} onChange={changeEditData}>
<option>일상</option>
<option>약속</option>
<option>취미</option>
<option>공부</option>
<option>운동</option>
</select>
</div>
</div>
{/* 출력 화면 */}
<div className="row mt-4">
{todoList.map(todo=>(
<div className="col-12 fs-4 mb-2">
<span className="badge bg-primary me-2">
{todo.type}
</span>
{todo.title}
{/* 수정버튼 */}
<FaRegEdit className="text-warning ms-1" onClick={e=>editTodoList(todo)}></FaRegEdit>
{/* 삭제버튼 */}
<FaXmark className="text-danger" onClick={e=>deleteTodoList(todo)}/>
</div>
))}
</div>
</div>
</div>
</div>
);
}
export default App;
괄호 잘 보이는 폰트 : Verdana, Consolas
App.js todoList.js CRUD 완성
import { useState, useRef } from "react";
import { FaXmark } from "react-icons/fa6";
import { FaRegEdit } from "react-icons/fa";
import { AiOutlinePlus } from "react-icons/ai";
import Jumbotron from "./components/Jumbotron";
import { Modal } from "bootstrap";
function App() {
// 목록을 위한 state (초기 data)
const [todoList, setTodoList] = useState([
{ no: 1, title: "학원가기", type: "공부" },
{ no: 2, title: "영어단어외우기", type: "공부" },
{ no: 3, title: "헬스장가기", type: "운동" },
{ no: 4, title: "친구만나기", type: "일상" },
]);
// 1 등록을 위한 state
const [data, setData] = useState({ title: "", type: "" }); // 사용자가 입력하는 데이터를 state로 만듬, 목록과 같아야함
// 3 수정을 위한 state
const [editData, setEditData] = useState({ title: "", type: "" });
// 4 모달
const bsModal = useRef();
// 1 e로 target을 꺼내고 name과 value를 꺼내서 data를 바꾸는 것이다.
const changeData = (e) => {
setData({
...data,
[e.target.name]: e.target.value, // [e.target.name]은 필드명이 변수일 때
});
};
// 1 입력한 데이터를 추가하는 함수
const addTodoList = () => {
// data의 내용을 todoList에 추가 후 data를 초기화하는 것이 목표
// 내용 검사 코드 추가 if(마음에 안 들면) return;
if (data.title.length === 0 || data.type.length === 0) return; // 칸이 비어있으면
// 백엔드 가면 시퀀스가 대체하는 부분 (번호 추가하는 부분)
const last = todoList.length - 1;
const no = todoList.length === 0 ? 1 : todoList[last].no + 1;
setTodoList([
...todoList, // todoList에 있는 건 다 유지를 시키고
{
...data,
no: no, // 추가적으로 한 개만...
},
]);
setData({ title: "", type: "" }); // 데이터 초기화
};
// 2 todo 항목 삭제
const deleteTodoList = (todo) => {
const newTodoList = todoList.filter((t) => t.no !== todo.no); // 다른 것만 추려라
setTodoList(newTodoList);
};
// 3 todo 수정을 위한 선택
const editTodoList = (todo) => {
// setEditData(todo); // 안 되는 코드(얕은 복사, shallow copy)
setEditData({ ...todo }); // 가능한 코드(깊은 복사, deep copy)
openModal(); // 모달 열어라
};
// 3
const changeEditData = (e) => {
setEditData({
...editData,
[e.target.name]: e.target.value,
});
};
// 3 취소 버튼 눌렀을 때
const clearEditData = () => {
setEditData({ title: "", type: "" });
closeModal(); // 모달 닫아라
};
// 3 저장 버튼 눌렀을 때
const saveTodoList = () => {
// editData의 내용을 todoList에 반영하고 초기화
const newTodoList = todoList.map((t) => {
if (t.no === editData.no) {
return { ...editData }; // 수정했던 데이터를 반환하고
}
return t; // 원래 데이터를 반환해라
});
setTodoList(newTodoList); // 결과를 반영해라
clearEditData(); // 바꾸고 초기화해라
closeModal(); // 모달 닫아라
};
// 4 Modal 제어 함수
const openModal = () => {
const modal = new Modal(bsModal.current);
modal.show();
};
const closeModal = () => {
const modal = Modal.getInstance(bsModal.current);
modal.hide();
};
return (
<div className="container-fluid my-5">
<div className="row">
<div className="col-md-8 offset-md-2">
{/* 점보트론을 만들면서 제목과 내용을 전달 */}
<Jumbotron title="todoList" content="일정 관리 프로그램" />
{/* 입력 화면 */}
<div className="row mt-4">
<div className="col-6">
<input
className="form-control"
name="title"
value={data.title}
onChange={changeData}
/>
</div>
<div className="col-3">
<select
className="form-select"
name="type"
value={data.type}
onChange={changeData}
>
<option value="">선택하세요.</option>
<option>일상</option>
<option>약속</option>
<option>취미</option>
<option>공부</option>
<option>운동</option>
</select>
</div>
<div className="col-3">
<button className="btn btn-success" onClick={addTodoList}>
<AiOutlinePlus />
추가
</button>
</div>
</div>
<hr />
{/* 출력 화면 */}
<div className="row mt-4">
{todoList.map((todo) => (
<div className="col-12 fs-4 mb-2" key={todo.no}>
<span className="badge bg-primary me-2">{todo.type}</span>
{todo.title}
{/* 수정버튼 */}
<FaRegEdit
className="text-warning ms-1"
onClick={() => editTodoList(todo)}
></FaRegEdit>
{/* 삭제버튼 */}
<FaXmark
className="text-danger"
onClick={() => deleteTodoList(todo)}
/>
</div>
))}
</div>
</div>
</div>
{/* Modal */}
<div
className="modal fade"
ref={bsModal}
id="exampleModal"
tabIndex="-1"
role="dialog"
aria-labelledby="exampleModalLabel"
aria-hidden="true"
data-bs-backdrop="static"
>
<div className="modal-dialog" role="document">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title" id="exampleModalLabel">
일정 변경
</h5>
<button
type="button"
className="btn btn-danger close"
data-bs-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
</div>
<div className="modal-body">
{/* 수정 화면 */}
<div className="row">
<div className="col">
<label className="form-label">할일</label>
<input
type="text"
name="title"
value={editData.title}
className="form-control"
onChange={changeEditData}
/>
</div>
</div>
<div className="row mt-4">
<div className="col">
<label className="form-label">종류</label>
<select
name="type"
value={editData.type}
onChange={changeEditData}
className="form-select"
>
<option>일상</option>
<option>약속</option>
<option>취미</option>
<option>공부</option>
</select>
</div>
</div>
</div>
<div className="modal-footer">
<button className="btn btn-secondary" onClick={clearEditData}>
취소
</button>
<button className="btn btn-success" onClick={saveTodoList}>
저장
</button>
</div>
</div>
</div>
</div>
</div>
);
}
export default App;
'React' 카테고리의 다른 글
React06 - Rest API2(insert, delete, selectOne, update) (0) | 2023.11.03 |
---|---|
React05 - Rest API (0) | 2023.11.02 |
React03 - item CRUD / 모달 (0) | 2023.11.01 |
React02 - 글자수과제 / 상태변수 객체 / 리엑트 정리 (0) | 2023.10.31 |
React01 - React 기초 (0) | 2023.10.30 |