코드가 1탄부터 이어지기 때문에 1탄부터 보고 오셔야 합니다~!
1탄
https://dev-ini.tistory.com/73
2탄
https://dev-ini.tistory.com/75
3탄
https://dev-ini.tistory.com/77
4탄
https://dev-ini.tistory.com/76
5탄
https://dev-ini.tistory.com/78
수정하기 버튼 만들기
DiaryItem.jsx
const DiaryItem = ({ onDelete, author, content, created_date, emotion, id}) => {
return (
<div className="DiaryItem">
<div className="info">
<span>
작성자 : {author} | 감정 점수: {emotion}
</span>
<br />
<span className="date">{new Date(created_date).toLocaleString()}</span>
</div>
<div className="content">{content}</div>
<button onClick={()=>{
console.log(id);
if(window.confirm(`${id}번째 일기를 정말 삭제하시겠습니까?`)){
onDelete(id);
}
}}>
삭제하기</button>
<button>수정하기</button> // 수정하기 버튼 만들기
</div>
);
};
export default DiaryItem;
삭제하기 버튼 onClick 함수 위로 빼서 작성하기
DiaryItem.jsx
const DiaryItem = ({ onEdit, onDelete, author, content, created_date, emotion, id}) => {
const handleDelete= () => {
console.log(id);
if(window.confirm(`${id}번째 일기를 정말 삭제하시겠습니까?`)){
onDelete(id);
}
}
return (
<div className="DiaryItem">
<div className="info">
<span>
작성자 : {author} | 감정 점수: {emotion}
</span>
<br />
<span className="date">{new Date(created_date).toLocaleString()}</span>
</div>
<div className="content">{content}</div>
<button onClick={handleDelete}>
삭제하기</button>
<button>수정하기</button>
</div>
);
};
export default DiaryItem;
수정하기 버튼 눌렀을때 폼 나타나게 할려고 state로 만들기
isEdit 은 true false 불리언값을 갖게되는데
수정중인지 수정중이 아닌지 불리언 상태로 값을 나타냄
isEdit 상태가 true가 되면 수정중으로 간주되고, false면 수정중이 아닌 현상태 유지
DiaryItem.jsx
import { useState } from "react";
const DiaryItem = ({ onDelete, author, content, created_date, emotion, id}) => {
const [isEdit, setIsEdit] = useState(false); // state로 만들고, 기본값은 false로
const handleDelete= () => {
console.log(id);
if(window.confirm(`${id}번째 일기를 정말 삭제하시겠습니까?`)){
onDelete(id);
}
}
return (
<div className="DiaryItem">
<div className="info">
<span>
작성자 : {author} | 감정 점수: {emotion}
</span>
<br />
<span className="date">{new Date(created_date).toLocaleString()}</span>
</div>
<div className="content">{content}</div>
<button onClick={handleDelete}>
삭제하기</button>
<button>수정하기</button>
</div>
);
};
export default DiaryItem;
toggleIsEdit 함수는 호출이 되는 순간 setIsEdit이 호출되면서 원래 isEdit이 갖고있던 값을 반전시킴
DiaryItem.jsx
import { useState } from "react";
const DiaryItem = ({ onDelete, author, content, created_date, emotion, id}) => {
const [isEdit, setIsEdit] = useState(false);
const toggleIsEdit = () => setIsEdit(!isEdit); // toggle 사용
const handleDelete= () => {
console.log(id);
if(window.confirm(`${id}번째 일기를 정말 삭제하시겠습니까?`)){
onDelete(id);
}
}
return (
<div className="DiaryItem">
<div className="info">
<span>
작성자 : {author} | 감정 점수: {emotion}
</span>
<br />
<span className="date">{new Date(created_date).toLocaleString()}</span>
</div>
<div className="content">{content}</div>
<button onClick={handleDelete}>
삭제하기</button>
<button>수정하기</button>
</div>
);
};
export default DiaryItem;
수정하기 버튼을 누르면 toggleIsEdit 함수가 작동하게 만들기
DiaryItem.jsx
import { useState } from "react";
const DiaryItem = ({ onDelete, author, content, created_date, emotion, id}) => {
const [isEdit, setIsEdit] = useState(false);
const toggleIsEdit = () => setIsEdit(!isEdit);
const handleDelete= () => {
console.log(id);
if(window.confirm(`${id}번째 일기를 정말 삭제하시겠습니까?`)){
onDelete(id);
}
}
return (
<div className="DiaryItem">
<div className="info">
<span>
작성자 : {author} | 감정 점수: {emotion}
</span>
<br />
<span className="date">{new Date(created_date).toLocaleString()}</span>
</div>
<div className="content">{content}</div>
<button onClick={handleDelete}>
삭제하기</button>
<button onClick={toggleIsEdit}>수정하기</button> // onCilck 이벤트에 연결
</div>
);
};
export default DiaryItem;
수정폼 띄우게 하기
isEdit의 state가 true값을 갖는다면 수정중이라고 간주해서 콘텐츠 부분에 수정폼을 띄우게 하기
{content}값 지우고 삼항연산자 사용
isEdit이 true면 수정중일때의 값 넣고, false면 수정중 아닐때의 값 넣기
DiaryItem.jsx
import { useState } from "react";
const DiaryItem = ({ onDelete, author, content, created_date, emotion, id}) => {
const [isEdit, setIsEdit] = useState(false);
const toggleIsEdit = () => setIsEdit(!isEdit);
const handleDelete= () => {
console.log(id);
if(window.confirm(`${id}번째 일기를 정말 삭제하시겠습니까?`)){
onDelete(id);
}
}
return (
<div className="DiaryItem">
<div className="info">
<span>
작성자 : {author} | 감정 점수: {emotion}
</span>
<br />
<span className="date">{new Date(created_date).toLocaleString()}</span>
</div>
<div className="content">{isEdit ? <></> : <>{content}</>}</div> // 삼항연산자 사용
<button onClick={handleDelete}>
삭제하기</button>
<button onClick={toggleIsEdit}>수정하기</button>
</div>
);
};
export default DiaryItem;
수정중일때 사용할 textarea 넣기
DiaryItem.jsx
import { useState } from "react";
const DiaryItem = ({
onDelete,
author,
content,
created_date,
emotion,
id,
}) => {
const [isEdit, setIsEdit] = useState(false);
const toggleIsEdit = () => setIsEdit(!isEdit);
const handleDelete = () => {
console.log(id);
if (window.confirm(`${id}번째 일기를 정말 삭제하시겠습니까?`)) {
onDelete(id);
}
};
return (
<div className="DiaryItem">
<div className="info">
<span>
작성자 : {author} | 감정 점수: {emotion}
</span>
<br />
<span className="date">{new Date(created_date).toLocaleString()}</span>
</div>
<div className="content">
{isEdit ? (
<>
<textarea />
</>
) : (
<>{content}</>
)}
</div>
<button onClick={handleDelete}>삭제하기</button>
<button onClick={toggleIsEdit}>수정하기</button>
</div>
);
};
export default DiaryItem;
수정폼에 입력하는 데이터들을 state로 핸들링하게 만들기
DiaryItem.jsx
import { useState } from "react";
const DiaryItem = ({
onDelete,
author,
content,
created_date,
emotion,
id,
}) => {
const [isEdit, setIsEdit] = useState(false);
const toggleIsEdit = () => setIsEdit(!isEdit);
const [localContent, setLocalContent] = useState(""); // state 생성
const handleDelete = () => {
console.log(id);
if (window.confirm(`${id}번째 일기를 정말 삭제하시겠습니까?`)) {
onDelete(id);
}
};
return (
<div className="DiaryItem">
<div className="info">
<span>
작성자 : {author} | 감정 점수: {emotion}
</span>
<br />
<span className="date">{new Date(created_date).toLocaleString()}</span>
</div>
<div className="content">
{isEdit ? (
<>
<textarea />
</>
) : (
<>{content}</>
)}
</div>
<button onClick={handleDelete}>삭제하기</button>
<button onClick={toggleIsEdit}>수정하기</button>
</div>
);
};
export default DiaryItem;
textarea에 value와 onChange 추가
DiaryItem.jsx
import { useState } from "react";
const DiaryItem = ({
onDelete,
author,
content,
created_date,
emotion,
id,
}) => {
const [isEdit, setIsEdit] = useState(false);
const toggleIsEdit = () => setIsEdit(!isEdit);
const [localContent, setLocalContent] = useState("");
const handleDelete = () => {
console.log(id);
if (window.confirm(`${id}번째 일기를 정말 삭제하시겠습니까?`)) {
onDelete(id);
}
};
return (
<div className="DiaryItem">
<div className="info">
<span>
작성자 : {author} | 감정 점수: {emotion}
</span>
<br />
<span className="date">{new Date(created_date).toLocaleString()}</span>
</div>
<div className="content">
{isEdit ? (
<>
<textarea value={localContent} onChange={(e)=>setLocalContent(e.target.value)}/> // 이벤트 추가
</>
) : (
<>{content}</>
)}
</div>
<button onClick={handleDelete}>삭제하기</button>
<button onClick={toggleIsEdit}>수정하기</button>
</div>
);
};
export default DiaryItem;
수정하기 버튼 눌러서 수정중이라면, textarea 만 나타나는게 아니라 아래있는 버튼들도 바뀌게 만들기
DiaryItem.jsx
import { useState } from "react";
const DiaryItem = ({
onDelete,
author,
content,
created_date,
emotion,
id,
}) => {
const [isEdit, setIsEdit] = useState(false);
const toggleIsEdit = () => setIsEdit(!isEdit);
const [localContent, setLocalContent] = useState("");
const handleDelete = () => {
console.log(id);
if (window.confirm(`${id}번째 일기를 정말 삭제하시겠습니까?`)) {
onDelete(id);
}
};
return (
<div className="DiaryItem">
<div className="info">
<span>
작성자 : {author} | 감정 점수: {emotion}
</span>
<br />
<span className="date">{new Date(created_date).toLocaleString()}</span>
</div>
<div className="content">
{isEdit ? (
<>
<textarea
value={localContent}
onChange={(e) => setLocalContent(e.target.value)}
/>
</>
) : (
<>{content}</>
)}
</div>
{isEdit ? (
<>
<button onClick={toggleIsEdit}>수정 취소</button>
<button>수정 완료</button>
</>
) : (
<>
<button onClick={handleDelete}>삭제하기</button>
<button onClick={toggleIsEdit}>수정하기</button>
</>
)}
</div>
);
};
export default DiaryItem;
수정하기를 누르면, 원래 있던 값이 나오게 해야함
const [localContent, setLocalContent] = useState(content); 으로 기본값을 바꿔준다.
DiaryItem.jsx
import { useState } from "react";
const DiaryItem = ({
onDelete,
author,
content,
created_date,
emotion,
id,
}) => {
const [isEdit, setIsEdit] = useState(false);
const toggleIsEdit = () => setIsEdit(!isEdit);
const [localContent, setLocalContent] = useState(content); // 기본값을 content로 바꾸기
const handleDelete = () => {
console.log(id);
if (window.confirm(`${id}번째 일기를 정말 삭제하시겠습니까?`)) {
onDelete(id);
}
};
return (
<div className="DiaryItem">
<div className="info">
<span>
작성자 : {author} | 감정 점수: {emotion}
</span>
<br />
<span className="date">{new Date(created_date).toLocaleString()}</span>
</div>
<div className="content">
{isEdit ? (
<>
<textarea
value={localContent}
onChange={(e) => setLocalContent(e.target.value)}
/>
</>
) : (
<>{content}</>
)}
</div>
{isEdit ? (
<>
<button onClick={toggleIsEdit}>수정 취소</button>
<button>수정 완료</button>
</>
) : (
<>
<button onClick={handleDelete}>삭제하기</button>
<button onClick={toggleIsEdit}>수정하기</button>
</>
)}
</div>
);
};
export default DiaryItem;
수정하기 누르고 글 입력후, 수정취소를 누른다음, 다시 수정하기를 누르면 수정 취소전에 입력한 값이 그대로 남아있는 문제가 생김. 초기화시키는 함수(handleQuitEdit)를 만들어줘야함.
DiaryItem.jsx
import { useState } from "react";
const DiaryItem = ({
onDelete,
author,
content,
created_date,
emotion,
id,
}) => {
const [isEdit, setIsEdit] = useState(false);
const toggleIsEdit = () => setIsEdit(!isEdit);
const [localContent, setLocalContent] = useState(content);
const handleDelete = () => {
console.log(id);
if (window.confirm(`${id}번째 일기를 정말 삭제하시겠습니까?`)) {
onDelete(id);
}
};
const handleQuitEdit = () => { // 수정 상태에서 나간다
setIsEdit(false);
setLocalContent(content);
}
return (
<div className="DiaryItem">
<div className="info">
<span>
작성자 : {author} | 감정 점수: {emotion}
</span>
<br />
<span className="date">{new Date(created_date).toLocaleString()}</span>
</div>
<div className="content">
{isEdit ? (
<>
<textarea
value={localContent}
onChange={(e) => setLocalContent(e.target.value)}
/>
</>
) : (
<>{content}</>
)}
</div>
{isEdit ? (
<>
<button onClick={toggleIsEdit}>수정 취소</button>
<button>수정 완료</button>
</>
) : (
<>
<button onClick={handleDelete}>삭제하기</button>
<button onClick={toggleIsEdit}>수정하기</button>
</>
)}
</div>
);
};
export default DiaryItem;
handleQuitEdit 함수를 수정취소버튼에 달아주기
DiaryItem.jsx
import { useState } from "react";
const DiaryItem = ({
onDelete,
author,
content,
created_date,
emotion,
id,
}) => {
const [isEdit, setIsEdit] = useState(false);
const toggleIsEdit = () => setIsEdit(!isEdit);
const [localContent, setLocalContent] = useState(content);
const handleDelete = () => {
console.log(id);
if (window.confirm(`${id}번째 일기를 정말 삭제하시겠습니까?`)) {
onDelete(id);
}
};
const handleQuitEdit = () => { // 수정 상태에서 나간다
setIsEdit(false);
setLocalContent(content);
}
return (
<div className="DiaryItem">
<div className="info">
<span>
작성자 : {author} | 감정 점수: {emotion}
</span>
<br />
<span className="date">{new Date(created_date).toLocaleString()}</span>
</div>
<div className="content">
{isEdit ? (
<>
<textarea
value={localContent}
onChange={(e) => setLocalContent(e.target.value)}
/>
</>
) : (
<>{content}</>
)}
</div>
{isEdit ? (
<>
<button onClick={handleQuitEdit}>수정 취소</button> // 적용
<button>수정 완료</button>
</>
) : (
<>
<button onClick={handleDelete}>삭제하기</button>
<button onClick={toggleIsEdit}>수정하기</button>
</>
)}
</div>
);
};
export default DiaryItem;
수정하는 함수 만들기
수정완료 이벤트를 DiaryItem에서 App까지 전달하기 위해서는 App에 수정하는 기능을 하는 함수를 만들어서 DiaryItem 까지 보내줘야함
onEdit 함수에 매개변수로 targetId와 newContent를 전달
targetId: 어떤 id를 가진 일기를 수정할건지
newContent: 어떻게 콘텐츠를 변경 시킬건지
setData 함수를 호출해서 데이터의 값을 바꿔줌
데이터에 map을 적용해서 모든 요소를 순회하면서 새로운 배열을 만들어서 setData에 전달
새로운 배열은 순회가 완료된 배열임
각각 모든 요소들이 현재 매개변수로 전달받은 targetId와 일치하는 아이들을 갖는지 검사하는 것
id가 일치하게되면, 원본데이터를 불러오고 콘텐츠(content)를 새로운 콘텐츠(newContent)로 업데이트
id가 일치하지않으면, 수정대상이 아니기 때문에 it(원래 있던 데이터)을 그대로 반환
onEdit 함수를 DiaryItem의 부모인 DiaryList로 전달
App.js
import logo from "./logo.svg";
import "./App.css";
import DiaryEditor from "./DiaryEditor/DiaryEditor";
import DiaryList from "./DiaryList";
import { useRef, useState } from "react";
function App() {
const [data, setData] = useState([]);
const dataId = useRef(0);
const onCreate = (author, content, emotion) => {
const created_date = new Date().getTime();
const newItem = {
author,
content,
emotion,
created_date,
id: dataId.current,
};
dataId.current += 1;
setData([newItem, ...data]);
};
const onDelete = (targetId) => {
console.log(`${targetId}가 삭제되었습니다.`);
const newDiaryList = data.filter((it) => it.id !== targetId);
setData(newDiaryList);
};
const onEdit = (targetId, newContent) =>{ // onEdit 함수 만들기
setData( // setData 호출
data.map((it)=>it.id === targetId ? {...it, content:newContent}: it ) // 일치 여부 확인 후 수정
)
}
return (
<div className="App">
<DiaryEditor onCreate={onCreate} />
<DiaryList onEdit={onEdit} onDelete={onDelete} diaryList={data} />
// onEdit 함수를 DiaryItem의 부모인 DiaryList로 전달
</div>
);
}
export default App;
DiaryList에서 props받아서 DiaryItem한테 내려줘야함
DiaryList.jsx
import DiaryItem from './DiaryItem';
const DiaryList = ({ onEdit, onDelete,diaryList})=> { // props 받아서
return (
<div className="DiaryList">
<h2>일기 리스트</h2>
<h4>{diaryList.length}개의 일기가 있습니다.</h4>
<div>
{diaryList.map((it)=>
(
<DiaryItem key={it.id} {...it} onEdit={onEdit} onDelete={onDelete}/> // DiartItem한테 내려줘야함
))}
</div>
</div>
);
}
DiaryList.defaultProps={
diaryList:[]
}
export default DiaryList;
수정완료 버튼을 눌렀을때 이벤트를 처리할 함수 만들기 (handleEdit)
DiaryItem.jsx
import { useState } from "react";
const DiaryItem = ({
onEdit,
onDelete,
author,
content,
created_date,
emotion,
id,
}) => {
const [isEdit, setIsEdit] = useState(false);
const toggleIsEdit = () => setIsEdit(!isEdit);
const [localContent, setLocalContent] = useState(content);
const handleDelete = () => {
console.log(id);
if (window.confirm(`${id}번째 일기를 정말 삭제하시겠습니까?`)) {
onDelete(id);
}
};
const handleQuitEdit = () => {
setIsEdit(false);
setLocalContent(content);
}
const handleEdit = () =>{ // 수정 완료 버튼 누를때 실행되는 함수
if(localContent.length < 5){ // 5글자 이상 작성하게 만들기
return;
}
onEdit(id, localContent)
}
return (
<div className="DiaryItem">
<div className="info">
<span>
작성자 : {author} | 감정 점수: {emotion}
</span>
<br />
<span className="date">{new Date(created_date).toLocaleString()}</span>
</div>
<div className="content">
{isEdit ? (
<>
<textarea
value={localContent}
onChange={(e) => setLocalContent(e.target.value)}
/>
</>
) : (
<>{content}</>
)}
</div>
{isEdit ? (
<>
<button onClick={handleQuitEdit}>수정 취소</button>
<button onClick={handleEdit}>수정 완료</button>
</>
) : (
<>
<button onClick={handleDelete}>삭제하기</button>
<button onClick={toggleIsEdit}>수정하기</button>
</>
)}
</div>
);
};
export default DiaryItem;
입력 제대로 안되면 focus 되게 만들기
DiaryItem.jsx
import { useRef } from "react";
import { useState } from "react";
const DiaryItem = ({
onEdit,
onDelete,
author,
content,
created_date,
emotion,
id,
}) => {
const [isEdit, setIsEdit] = useState(false);
const toggleIsEdit = () => setIsEdit(!isEdit);
const [localContent, setLocalContent] = useState(content);
const localContentInput = useRef(); // 레퍼런스 객체 만들기
const handleDelete = () => {
console.log(id);
if (window.confirm(`${id}번째 일기를 정말 삭제하시겠습니까?`)) {
onDelete(id);
}
};
const handleQuitEdit = () => {
setIsEdit(false);
setLocalContent(content);
}
const handleEdit = () =>{
if(localContent.length < 5){
localContentInput.current.focus(); // 포커스 명령 넣기
return;
}
onEdit(id, localContent)
}
return (
<div className="DiaryItem">
<div className="info">
<span>
작성자 : {author} | 감정 점수: {emotion}
</span>
<br />
<span className="date">{new Date(created_date).toLocaleString()}</span>
</div>
<div className="content">
{isEdit ? (
<>
<textarea
ref={localContentInput} // textarea에 레퍼런스로 추가
value={localContent}
onChange={(e) => setLocalContent(e.target.value)}
/>
</>
) : (
<>{content}</>
)}
</div>
{isEdit ? (
<>
<button onClick={handleQuitEdit}>수정 취소</button>
<button onClick={handleEdit}>수정 완료</button>
</>
) : (
<>
<button onClick={handleDelete}>삭제하기</button>
<button onClick={toggleIsEdit}>수정하기</button>
</>
)}
</div>
);
};
export default DiaryItem;
alert창 띄우고 수정완료되게 하기
DiaryItem.jsx
import { useRef } from "react";
import { useState } from "react";
const DiaryItem = ({
onEdit,
onDelete,
author,
content,
created_date,
emotion,
id,
}) => {
const [isEdit, setIsEdit] = useState(false);
const toggleIsEdit = () => setIsEdit(!isEdit);
const [localContent, setLocalContent] = useState(content);
const localContentInput = useRef(); // 레퍼런스 객체 만들기
const handleDelete = () => {
console.log(id);
if (window.confirm(`${id}번째 일기를 정말 삭제하시겠습니까?`)) {
onDelete(id);
}
};
const handleQuitEdit = () => {
setIsEdit(false);
setLocalContent(content);
}
const handleEdit = () =>{
if(localContent.length < 5){
localContentInput.current.focus();
return;
}
if(window.confirm(`${id}번 째 일기를 수정하시겠습니까?`)){ // alert창 띄우기
onEdit(id, localContent);
toggleIsEdit(); // 수정폼 닫아주기
}
}
return (
<div className="DiaryItem">
<div className="info">
<span>
작성자 : {author} | 감정 점수: {emotion}
</span>
<br />
<span className="date">{new Date(created_date).toLocaleString()}</span>
</div>
<div className="content">
{isEdit ? (
<>
<textarea
ref={localContentInput}
value={localContent}
onChange={(e) => setLocalContent(e.target.value)}
/>
</>
) : (
<>{content}</>
)}
</div>
{isEdit ? (
<>
<button onClick={handleQuitEdit}>수정 취소</button>
<button onClick={handleEdit}>수정 완료</button>
</>
) : (
<>
<button onClick={handleDelete}>삭제하기</button>
<button onClick={toggleIsEdit}>수정하기</button>
</>
)}
</div>
);
};
export default DiaryItem;
완성본
'Libraries > React' 카테고리의 다른 글
[React] Routing (1) 개념, SPA & CSR (0) | 2023.09.15 |
---|---|
[React] useEffect (0) | 2023.09.13 |
[React] 데이터 삭제하기 (일기장 만들기 5탄) (0) | 2023.09.12 |
[React] 데이터 추가하기, 배열 리스트 만들고 추가하기 (일기장 만들기 4탄) (0) | 2023.09.05 |
[React] 데이터 리스트 렌더링 (조회) (일기장 만들기 3탄) (0) | 2023.09.04 |