New Page 구현하기
UI 구현하기
- 컴포넌트 구조는
- Header 컴포넌트
- Editor 컴포넌트
- EmotionItem 컴포넌트
New.jsx
import Header from "../components/Header";
import Button from "../components/Button";
import Editor from "../components/Editor";
const New = () => {
return (
<div>
<Header
title={"새 일기 쓰기"}
leftChild={<Button text={"< 뒤로 가기"} />}
/>
<Editor />
</div>
);
};
export default New;
Editor.jsx
import "./Editor.css";
import EmotionItem from "./EmotionItem";
import Button from "./Button";
const emotionList = [
{
emotionId: 1,
emotionName: "완전 좋음",
},
{
emotionId: 2,
emotionName: "좋음",
},
{
emotionId: 3,
emotionName: "그럭저럭",
},
{
emotionId: 4,
emotionName: "나쁨",
},
{
emotionId: 5,
emotionName: "끔찍함",
},
];
const Editor = () => {
const emotionId = 1;
return (
<div className="Editor">
<section className="date_section">
<h4>오늘의 날짜</h4>
<input type="date" />
</section>
<section className="emotion_section">
<h4>오늘의 감정</h4>
<div className="emotion_list_wrapper">
{emotionList.map((item) => (
<EmotionItem
key={item.emotionId}
{...item}
isSelected={item.emotionId === emotionId}
/>
))}
</div>
</section>
<section className="content_section">
<h4>오늘의 일기</h4>
<textarea placeholder="오늘은 어땠나요?" />
</section>
<section className="button_section">
<Button text={"취소하기"} />
<Button text={"작성완료"} type={"POSITIVE"} />
</section>
</div>
);
};
export default Editor;
- emotionList : emotionId 와 emotionName을 반복해서 컴포넌트에 넣을 수 있지만 그렇게 하면 유지 보수가 어렵고 좋지 않은 코드이기 때문에 배열로 만들어서 map 함수로 코드를 간결하게 하였다.
EmotionItem.jsx
import "./EmotionItem.css";
import { getEmotionImage } from "../utill/get-emotion-image";
const EmotionItem = ({ emotionId, emotionName, isSelected }) => {
return (
<div
className={`EmotionItem ${
isSelected ? `EmotionItem_on_${emotionId}` : ""
}`}
>
<img className="emotion_img" src={getEmotionImage(emotionId)} />
<div className="emotion_name">{emotionName}</div>
</div>
);
};
export default EmotionItem;
- emotionId에 따라 배경색이 달라지도록 구현하기
기능 구현하기
New.jsx
import Header from "../components/Header";
import Button from "../components/Button";
import Editor from "../components/Editor";
import { useNavigate } from "react-router-dom";
import { useContext } from "react";
import { DiaryDispatchContext } from "../App";
const New = () => {
const { onCreate } = useContext(DiaryDispatchContext);
const nav = useNavigate();
const onSubmit = (input) => {
onCreate(input.createdDate.getTime(), input.emotionId, input.content);
nav("/", { replace: true });
};
return (
<div>
<Header
title={"새 일기 쓰기"}
leftChild={<Button onClick={() => nav(-1)} text={"< 뒤로 가기"} />}
/>
<Editor onSubmit={onSubmit} />
</div>
);
};
export default New;
- nav("/", { replace: true }); 는 새 글 작성이 완료되면 목록 페이지로 가게 하고, 뒤로가기를 방지한다.
Editor.jsx
import "./Editor.css";
import EmotionItem from "./EmotionItem";
import Button from "./Button";
import { useState } from "react";
import { useNavigate } from "react-router-dom";
const emotionList = [
...생략
];
const getStringedDate = (targetDate) => {
...생략
};
const Editor = ({ onSubmit }) => {
const [input, setInput] = useState({
createdDate: new Date(),
emotionId: 3,
content: "",
});
const nav = useNavigate();
const onChangeInput = (e) => {
//console.log(e.target.name); // 어떤 요소에 입력이 들어온건지?
//console.log(e.target.value); // 입력된 값이 무엇인지?
let name = e.target.name;
let value = e.target.value;
if (name === "createdDate") {
value = new Date(value);
}
setInput({
...input,
[name]: value,
});
};
const onClickSubmitButton = () => {
onSubmit(input);
};
return (
<div className="Editor">
<section className="date_section">
<h4>오늘의 날짜</h4>
<input
name="createdDate"
onChange={onChangeInput}
value={getStringedDate(input.createdDate)}
type="date"
/>
</section>
<section className="emotion_section">
<h4>오늘의 감정</h4>
<div className="emotion_list_wrapper">
{emotionList.map((item) => (
<EmotionItem
onClick={() =>
onChangeInput({
target: {
name: "emotionId",
value: item.emotionId,
},
})
}
key={item.emotionId}
{...item}
isSelected={item.emotionId === input.emotionId}
/>
))}
</div>
</section>
<section className="content_section">
<h4>오늘의 일기</h4>
<textarea
name="content"
value={input.content}
onChange={onChangeInput}
placeholder="오늘은 어땠나요?"
/>
</section>
<section className="button_section">
<Button onClick={() => nav(-1)} text={"취소하기"} />
<Button
onClick={onClickSubmitButton}
text={"작성완료"}
type={"POSITIVE"}
/>
</section>
</div>
);
};
export default Editor;
- 작성완료 버튼을 눌렀을 때 바로 onCreate가 실행되지 않도록 onClickSubmitButton로 설정한다. (edit에서도 Editor를 사용해야하기 때문에)
EmotionItem.jsx
import "./EmotionItem.css";
import { getEmotionImage } from "../utill/get-emotion-image";
const EmotionItem = ({ emotionId, emotionName, isSelected, onClick }) => {
return (
<div
onClick={onClick}
className={`EmotionItem ${
isSelected ? `EmotionItem_on_${emotionId}` : ""
}`}
>
<img className="emotion_img" src={getEmotionImage(emotionId)} />
<div className="emotion_name">{emotionName}</div>
</div>
);
};
export default EmotionItem;
- 완성
출처 : 한입 크기로 잘라먹는 리액트
'Language > React.js' 카테고리의 다른 글
[React] 감정일기장 프로젝트 : DiaryPage 구현하기 (0) | 2024.10.29 |
---|---|
[React] 감정일기장 프로젝트 : EditPage 구현하기 (0) | 2024.10.29 |
[React] 감정일기장 프로젝트 : HomePage 구현하기 (0) | 2024.10.23 |
[React] 감정일기장 프로젝트 : 일기 관리 기능 구현하기 (0) | 2024.10.23 |
[React] 감정일기장 프로젝트 : 공통 컴포넌트 구현하기 (0) | 2024.10.23 |