2023. 6. 8. 14:28ㆍGithub 프로젝트/todolist반응형웹앱
지난시간 CRUD의 읽기, 쓰기의 대해서 다뤄봤습니다.
(4) Todo List 기본 기능 CRUD 추가 - 1 (읽기, 쓰기) : https://berkley.tistory.com/8
(4) Todo List 기본 기능 CRUD 추가 - 1 (읽기, 쓰기)
지난 시간 반응형 웹&앱 UI 작성편을 이어서 기능 추가를 진행하였습니다. 이 글을 보기 전, 아래의 링크를 먼저 수행 하신 후 다음 단계로 넘어가시면 되겠습니다. (3) 반응형 Todolist UI 작업 진행
berkley.tistory.com
이번 시간에는 갱신의 대해서 다뤄보겠습니다.
1. Todo List CRUD 중 갱신
기존의 state 변수 todoList에 필드 "title, contents" 만 설정 되어있다.
여기서 file에 isTitleUpdate 에 boolean 타입의 객체를 활용해 줍니다. (샘플로 이용시)
useEffect(() => {
setTodoList([
{
title: "Redux 학습하기",
contents: [
"로그인/로그아웃 가능 여부 확인",
"localstorage/sessionstorage 학습",
],
isTitleUpdate:false,
},
{
title: "SpringBoot 학습하기",
contents: ["Spring Security 구현", "Spring MVC 패턴 익히기"],
isTitleUpdate:false,
},
{
title: "JWT 인증 처리",
contents: ["JWT 개념 익히기"],
isTitleUpdate:false,
},
]);
}, []);
※ 이전에 사용했던 생성부분에 isTitleUpdate 객체도 추가해줍니다. (생성 후 갱신기능 사용시 반드시 수정해줄것)
/**
* 입력시 Todolist 추가하는 기능
*/
const createTitleButton = () => {
let to = [];
to.push(...todoList);
to.push({
title: createInputTitle?.title,
contents: [],
isTitleUpdate:false,
});
setTodoList(to);
};
다음으로는 수정 모드 진입 시 Input 모드로 변환해주고 onChange용 state문이랑 메서드를 작성해줍니다.
TodoList에서는 state값이 배열로 지정되기 때문에 배열별로 각각 저장해줘야 합니다.
// Todolist title 수정용 state
const [changeTitle, setChangeTitle] = useState();
// 수정용 onChange
const updateTitlOnChange = (e,index) => {
const { name, value } = e.target;
setChangeTitle({[index]:{[name]:value}});
console.log(changeTitle);
}
이후, 현재 읽기 전용으로 수정된 map안에 수정모드를 반영 시킵니다.
<수정전>
{
// 다음은 각각 데이터를 불려올 때 map을 주로 사용합니다.
// todoList에 저장된 state 값을
// 유사 forEach문처럼 todo를 이용하여 출력하고,
// 상위 div에 key값을 설정하기 위해 index 값을 집어 넣어야 합니다.
todoList?.map((todo, index) => (
<div key={index} className="todoContainer">
{/* 이부분 수정 전 시작*/}
<div className="todoTitle">
{todo?.title} <PlusCircle />
</div>
{/* 이부분 수정 전 끝*/}
{todo?.contents?.map((tc, tcIndex) => (
<div key={tcIndex} className="todoContents">
- {tc} <Trash3 />
</div>
))}
</div>
))
}
<수정 후>
{
// 다음은 각각 데이터를 불려올 때 map을 주로 사용합니다.
// todoList에 저장된 state 값을
// 유사 forEach문처럼 todo를 이용하여 출력하고,
// 상위 div에 key값을 설정하기 위해 index 값을 집어 넣어야 합니다.
todoList?.map((todo, index) => (
<div key={index} className="todoContainer">
<div className="todoTitle">
{/* 수정 후 시작*/}
{isTitleUpdate ? (
<Input name="title" defaultValue={todo?.title} onChange={(e) => updateTitlOnChange(e,index)} />
<Button>todolist수정</Button>
<Button onClick={() => setIsTitleUpdate(!isTitleUpdate)}>취소</Button>
) : (
<div>
{todo?.title}
<Button onClick={() => setIsTitleUpdate(!isTitleUpdate)}>수정</Button> <PlusCircle />
</div>
)}
{/* 수정 후 끝*/}
</div>
{todo?.contents?.map((tc, tcIndex) => (
<div key={tcIndex} className="todoContents">
- {tc} <Trash3 />
</div>
))}
</div>
))
}
여기서부터는 1200px 기준으로 결과물을 도출하겠습니다.
현재는 퍼블리셔 영역이 아닌 프론트엔드 React 개발자로써 진행을 하는 것이니 UI부분은 차후 진행을 할 것입니다.
이에 참고하며, 디자인 부분은 차후에 진행하도록 하겠습니다.
이에 따른 아래와 같이 결과물은 다음과 같습니다.
차후, 수정 버튼 누르면 전체 수정 모드로 진행 됩니다.
차후, 분리 작업을 통해 해당 부분 수정 클릭 시 해당부분만 수정하도록 Refactoring 하면서 진행 하도록 하겠습니다.
<갱신 작업 전>

<갱신 작업 후>

==> console.log 로 확인하시면, 입력값이 변환하는 것을 확인 할 수 있습니다.
다음은 입력 후 갱신 확정하는 기능을 수행하겠습니다.
먼저, 사전 작업으로 npm 패키지에서 immutability-helper 설치하겠습니다.
powershell을 열고 npm install immutability-helper --save 로 이용하여 설치하겠습니다.

아래와 같이 설치가 끝난 이후 모습

설치가 끝난 후 본론으로 들어와 아래와 같이 import 해줍니다.
import update from "immutability-helper";
이후, 아래와 같이 불변성을 유지하면서 update() 메서드를 활용하여 filed : { $set : value } 기능으로 state값으로 변경해줍니다.
// 입력 후 갱신 메서드
const updateTitle = (index) => {
setTodoList(
update(todoList, {
[index]: {
title: { $set: changeTitle[index].title },
},
})
);
};
렌더링 부분을 수정 을 합니다.
<div className="todo">
{
// 다음은 각각 데이터를 불려올 때 map을 주로 사용합니다.
// todoList에 저장된 state 값을
// 유사 forEach문처럼 todo를 이용하여 출력하고,
// 상위 div에 key값을 설정하기 위해 index 값을 집어 넣어야 합니다.
todoList?.map((todo, index) => (
<div key={index} className="todoContainer">
<div className="todoTitle">
{isTitleUpdate ? (
<div>
<Input
name="title"
defaultValue={todo?.title}
onChange={(e) => updateTitlOnChange(e, index)}
/>
/* 이부분 수정 시작 */
<Button onClick={() => updateTitle(index)}>
todolist수정
</Button>
/* 이부분 수정 끝 */
<Button
onClick={() => setIsTitleUpdate(!isTitleUpdate)}
>
취소
</Button>
</div>
) : (
<div>
{todo?.title}
<Button
onClick={() => setIsTitleUpdate(!isTitleUpdate)}
>
수정
</Button>{" "}
<PlusCircle />
</div>
)}
</div>
{todo?.contents?.map((tc, tcIndex) => (
<div key={tcIndex} className="todoContents">
- {tc} <Trash3 />
</div>
))}
</div>
))
}
</div>
다음과 같이 업데이트를 수행해봅니다.
(1) 메인 화면

(2) 수정 모드 돌입

(3) 입력 후 수정

(4) 돌아가기 (취소 버튼)

2. 완성된 코드
import {
Button,
ButtonGroup,
Card,
CardBody,
CardHeader,
CardTitle,
Form,
Input,
} from "reactstrap";
import "./App.css";
import { PlusCircle, Trash3 } from "react-bootstrap-icons";
import { useEffect, useState } from "react";
import update from "immutability-helper";
function App() {
/**
* 필요 key:value값
* title, contents
* 이 값은
*/
const [todoList, setTodoList] = useState([]);
const [createInputTitle, setCreateInputTitle] = useState();
useEffect(() => {
setTodoList([
{
title: "Redux 학습하기",
contents: [
"로그인/로그아웃 가능 여부 확인",
"localstorage/sessionstorage 학습",
],
},
{
title: "SpringBoot 학습하기",
contents: ["Spring Security 구현", "Spring MVC 패턴 익히기"],
},
{
title: "JWT 인증 처리",
contents: ["JWT 개념 익히기"],
},
]);
}, []);
/**
* 다음은 TodoList 입력용 이벤트 함수
*/
const createTitleOnchange = (e) => {
const { name, value } = e.target;
setCreateInputTitle({
...createInputTitle,
[name]: value,
});
};
/**
* 입력시 Todolist 추가하는 기능
*/
const createTitleButton = () => {
let to = [];
to.push(...todoList);
to.push({
title: createInputTitle?.title,
contents: [],
});
setTodoList(to);
};
// 갱신모드 설정
const [isTitleUpdate, setIsTitleUpdate] = useState(false);
// Todolist title 수정용 state
const [changeTitle, setChangeTitle] = useState();
const updateTitlOnChange = (e, index) => {
const { name, value } = e.target;
setChangeTitle({ [index]: { [name]: value } });
console.log(changeTitle);
};
// 입력 후 갱신 메서드
const updateTitle = (index) => {
setTodoList(
update(todoList, {
[index]: {
title: { $set: changeTitle[index].title },
},
})
);
};
return (
<div className="my-2 background-container">
<Card className="my-2 container">
<CardHeader className="header-container">
To-do list 반응형 웹 개발
</CardHeader>
<CardBody>
<CardTitle tag="h2">To-do list</CardTitle>
<div className="todo">
{
// 다음은 각각 데이터를 불려올 때 map을 주로 사용합니다.
// todoList에 저장된 state 값을
// 유사 forEach문처럼 todo를 이용하여 출력하고,
// 상위 div에 key값을 설정하기 위해 index 값을 집어 넣어야 합니다.
todoList?.map((todo, index) => (
<div key={index} className="todoContainer">
<div className="todoTitle">
{isTitleUpdate ? (
<div>
<Input
name="title"
defaultValue={todo?.title}
onChange={(e) => updateTitlOnChange(e, index)}
/>
<Button onClick={() => updateTitle(index)}>
todolist수정
</Button>
<Button
onClick={() => setIsTitleUpdate(!isTitleUpdate)}
>
취소
</Button>
</div>
) : (
<div>
{todo?.title}
<Button
onClick={() => setIsTitleUpdate(!isTitleUpdate)}
>
수정
</Button>{" "}
<PlusCircle />
</div>
)}
</div>
{todo?.contents?.map((tc, tcIndex) => (
<div key={tcIndex} className="todoContents">
- {tc} <Trash3 />
</div>
))}
</div>
))
}
</div>
{/**
*
*/}
<Form className="addGroup">
<Input
className="addInput"
name="title"
defaultValue={createInputTitle}
onChange={createTitleOnchange}
/>
<Button className="addButton" onClick={createTitleButton}>
추가
</Button>
</Form>
</CardBody>
</Card>
</div>
);
}
다음 시간에는 삭제 버튼 기능을 구현해보겠습니다.
(6) TodoList CRUD 삭제 : https://berkley.tistory.com/10
(6) Todo List 기본 기능 CRUD 추가 - 3 (삭제)
지난시간에는 갱신의 대해서 다뤄봤습니다. 갱신 부터 진행 후 다음은 삭제에 대해 다루겠습니다. (5) Todo List 기본 기능 CRUD 추가 - 2 (갱신) : https://berkley.tistory.com/9 (5) Todo List 기본 기능 CRUD 추가
berkley.tistory.com
'Github 프로젝트 > todolist반응형웹앱' 카테고리의 다른 글
(7) Todo List Redux - Local Storage로 state 리팩토링 (0) | 2023.06.09 |
---|---|
(6) Todo List 기본 기능 CRUD 추가 - 3 (삭제) (0) | 2023.06.08 |
(4) Todo List 기본 기능 CRUD 추가 - 1 (읽기, 쓰기) (0) | 2023.06.07 |
(3) 반응형 Todolist UI 작업 진행 (0) | 2023.06.06 |
(2) Todolist 작업 전 반응 형 웹&앱 설정 (0) | 2023.06.06 |