[React] 페이지 구현 - 일기 수정(‘/edit’)
1️⃣ 몇 번째 아이디의 일기를 수정할지!
~/edit/1 과 같이 아이디를 인식할 수 있도록 링크를 수정해야된다. => App 컴포에서!
// src > App.js
return (
<DiaryStateContext.Provider value={data}>
<DiaryDispatchContext.Provider value=>
<BrowserRouter>
<div className="App">
<Routes>
<Route path="/" element={<Home></Home>}></Route>
<Route path="/new" element={<New></New>}></Route>
<Route path="/edit/:id" element={<Edit></Edit>}></Route>
<Route path="/diary/:id" element={<Diary></Diary>}></Route>
</Routes>
</div>
</BrowserRouter>
</DiaryDispatchContext.Provider>
</DiaryStateContext.Provider>
);
2️⃣ 수정할 다이어리 데이터 불러오기
당연히 useContext를 사용해서 드릴링 없이 바로 불러올 수 있다. 그리고 어떤 아이디값의 데이터를 수정할 것인지도 알아야 하므로 useParams()를 사용한다.
import { useNavigate, useParams } from "react-router-dom";
import { useContext } from "react";
import { DiaryStateContext } from "../App";
const Edit = () => {
const navigate = useNavigate();
const { id } = useParams();
const diaryList = useContext(DiaryStateContext);
return <div></div>;
};
export default Edit;
3️⃣ 수정하고 싶은 id가 존재하지 않을 경우
import { useNavigate, useParams } from "react-router-dom";
import { useContext, useEffect, useState } from "react";
import { DiaryStateContext } from "../App";
import DiaryEditor from "../components/DiaryEditor";
const Edit = () => {
const [originData, setOriginData] = useState();
const navigate = useNavigate();
const { id } = useParams();
const diaryList = useContext(DiaryStateContext);
useEffect(() => {
if (diaryList.length >= 1) {
const targetDiary = diaryList.find(
(it) => parseInt(it.id) === parseInt(id)
);
if (targetDiary) {
setOriginData(targetDiary);
} else {
navigate("/", { replace: true });
}
}
}, [diaryList, id]);
return <div>{originData && <DiaryEditor />}</div>;
};
export default Edit;
4️⃣ 수정하기 버튼 클릭 -> 해당 데이터 불러오기
Edit 페이지에서 DiaryEditor 컴포넌트로 isEdit={true}, 현재 수정하려고 했던 기존 데이터를 전달해준다.
그렇게 되면 DiaryEditor는 isEdit과 originData를 가지고 마운트해주어야 한다.
// src > pages > Edit.js
return (
<div>
{originData && <DiaryEditor isEdit={true} originData={originData} />}
</div>
);
// src > components > DiaryEditor.js
useEffect(() => {
if (isEdit) {
setDate(getStringDate(new Date(parseInt(originData.date))));
setEmotion(originData.emotion);
setContent(originData.content);
}
}, [isEdit, originData]);
5️⃣ 헤더 바꾸기
기존의 DiaryEdior 컴포넌트는 새일기 쓰기라는 헤더가 존재한다. 그 부분에 headText가 “새 일기쓰기” 라고 되어있어서 수정하기를 눌러도 헤더에는 자동으로 새 일기쓰기가 마운트 되는 것이다.
=> 어떻게 수정?
처음에 Edit 페이지에서 프롭을 전달할 때, 일기 수정하기 라는 프롭을 전달해주는 방법을 생각했다 하지만 더 좋은 방법으로는 삼항 연산자를 사용해서 isEdit이 true이면 일기 수정하기를 false이면 새 일기쓰기로 해주면 된다.
// src > components > DiaryEditor.js
return (
<div className="DiaryEditor">
<MyHeader
headText={isEdit ? "일기 수정하기" : "새 일기쓰기"}
leftChild={
<MyButton text={"< 뒤로 가기"} onClick={() => navigate(-1)}></MyButton>
}
></MyHeader>
<div>
<section>
<h4>오늘은 언제인가요?</h4>
<div className="input_box">
<input
className="input_date"
type="date"
value={date}
onChange={(e) => setDate(e.target.value)}
/>
</div>
</section>
<section>
<h4>오늘의 감정</h4>
<div className="input_box emotion_list_wrapper">
{emotionList.map((it) => (
<EmotionItem
key={it.emotion_id}
{...it}
onClick={handleClickRemote}
isSelected={it.emotion_id === emotion}
></EmotionItem>
))}
</div>
</section>
<section>
<h4>오늘의 일기</h4>
<div className="input_box text_wrapper">
<textarea
placeholder="오늘은 어땠나요?"
ref={contentRef}
value={content}
onChange={(e) => setContent(e.target.value)}
></textarea>
</div>
</section>
<section>
<div className="control_box">
<MyButton text={"취소하기"} onClick={() => navigate(-1)}></MyButton>
<MyButton
text={"작성완료"}
type={"positive"}
onClick={handleSubmit}
></MyButton>
</div>
</section>
</div>
</div>
);
6️⃣ 일기 작성 완료 버튼
새 일기 쓰기는 무조건 저장만 하면 되었지만 수정하기 위해서는 수정할 일기의 아이디를 알아야 한다.
기존 App 컴포넌트에서 만들어 두었던 onEdit 함수를 가져와서 사용을 해야되고, isEdit이 true 이면 onEdit 함수를 사용하고, false이면 onCreate 함수를 사용한다.
handleSubmit 함수를 조금 수정해주어야 한다.
...
const {onCreate, onEdit} = useContext
...
const handleSubmit = () => {
if (content.length < 1) {
contentRef.current.focus();
return;
}
if (window.confirm(isEdit ? "일기를 수정하시겠습니까? " : "새로운 일기를 작성하시겠습니까? ")) {
if (!isEdit) {
onCreate(date, content, emotion);
}
else {
onEdit(originData.id, date, content, emotion);
}
}
navigate('/', {replace: true});
}
댓글남기기