일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 무한 스크롤
- CI/CD
- 태그된 유니온
- React
- app router
- recoil
- Cypress
- async/await
- TS
- map
- 공변성
- Promise
- RTK Query
- 리터럴 타입
- 투포인터
- 인터섹션
- 호이스팅
- 반공변성
- Jest
- autosize
- 타입 좁히기
- webpack
- SSR
- dfs
- ESlint
- 이분 검색
- 결정 알고리즘
- CORS
- tailwind
- useAppDispatch
- Today
- Total
짧은코딩
일기 쓰기 구현 본문
헤더 및 오늘 날짜
-new.js
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import MyHeader from "./../components/MyHeader";
import MyButton from "./../components/MyButton";
// 처음부터 오늘의 날짜가 오게 해주기 위한 기능
const getStringDate = (date) => {
// 0~9까지 잘라준다.
return date.toISOString().slice(0, 10);
};
const New = () => {
const [date, setDate] = useState(getStringDate(new Date()));
const navigate = useNavigate();
return (
<div>
{/* 헤더 */}
<MyHeader
headText={"새 일기쓰기"}
leftchild={
<MyButton text={"< 뒤로가기"} onClick={() => navigate(-1)} />
}
/>
{/* 오늘 날짜 */}
<div>
<section>
<h4>오늘은 언제인가요?</h4>
<div className="input-box">
<input
className="input-date"
value={date}
onChange={(e) => setDate(e.target.value)}
type="date"
/>
</div>
</section>
</div>
</div>
);
};
export default New;
여기까지 이렇게 구현했는데 이 부분은 일기 쓰기 부분이지만 일기 수정할 때도 유사하게 페이지를 사용한다. 따라서 컴포넌트화 시켜준다.
-DiaryEditor.js
따라서 DiaryEditor.js를 만들고 New.js에서 옮기는 작업을 한다. 이때 import부터 옮기는 것이 좋다. 그리고 경로을 잘 수정해야한다.
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import MyHeader from "./MyHeader";
import MyButton from "./MyButton";
// 처음부터 오늘의 날짜가 오게 해주기 위한 기능
const getStringDate = (date) => {
// 0~9까지 잘라준다.
return date.toISOString().slice(0, 10);
};
const DiaryEditor = () => {
const [date, setDate] = useState(getStringDate(new Date()));
const navigate = useNavigate();
return (
<div className="DiaryEditor">
{/* 헤더 */}
<MyHeader
headText={"새 일기쓰기"}
leftchild={
<MyButton text={"< 뒤로가기"} onClick={() => navigate(-1)} />
}
/>
{/* 오늘 날짜 */}
<div>
<section>
<h4>오늘은 언제인가요?</h4>
<div className="input_box">
<input
className="input_date"
value={date}
onChange={(e) => setDate(e.target.value)}
type="date"
/>
</div>
</section>
</div>
</div>
);
};
export default DiaryEditor;
따라서 이렇게 옮겨주고 New.js는 비워준다.
-New.js
import DiaryEditor from "../components/DiaryEditor";
const New = () => {
return (
<div>
<DiaryEditor />
</div>
);
};
export default New;
이렇게 만들어주면 다시 위 사진과 똑같은 화면이 나오게된다.
-App.css
.DiaryEditor section {
margin-bottom: 40px;
}
.DiaryEditor h4 {
font-size: 22px;
font-weight: bold;
}
.DiaryEditor .input_date {
border: none;
border-radius: 5px;
background-color: #ececec;
padding: 10px 20px 10px 20px;
cursor: pointer;
font-family: "Nanum Pen Script";
font-size: 20px;
}
이렇게 완성이 된다.
오늘의 감정
-감정 리스트
// 감정 리스트
const emotionList = [
{
emotion_id: 1,
emotion_img: process.env.PUBLIC_URL + `/assets/emotion1.png`,
emotion_descript: "완전 좋음",
},
{
emotion_id: 2,
emotion_img: process.env.PUBLIC_URL + `/assets/emotion2.png`,
emotion_descript: "좋음",
},
{
emotion_id: 3,
emotion_img: process.env.PUBLIC_URL + `/assets/emotion3.png`,
emotion_descript: "그럭저럭",
},
{
emotion_id: 4,
emotion_img: process.env.PUBLIC_URL + `/assets/emotion4.png`,
emotion_descript: "나쁨",
},
{
emotion_id: 5,
emotion_img: process.env.PUBLIC_URL + `/assets/emotion5.png`,
emotion_descript: "끔찍함",
},
];
우선 감정 리스트를 만들어준다.
그리고 클릭하면 어떤 감정을 선택했는지 저장해야되는 컴포넌트 EmotionItem.js를 만들어준다.
-EmotionItem.js
const EmotionItem = ({ emotion_id, emotion_img, emotion_descript }) => {
return (
<div className="EmotionItem">
<img src={emotion_img} />
<span>{emotion_descript}</span>
</div>
);
};
export default EmotionItem;
-DiaryEditor.js
{/* 오늘의 감정 */}
<section>
<h4>오늘의 감정</h4>
<div className="input_box emotion_list_wrapper">
{emotionList.map((it) => (
<EmotionItem key={it.emotion_id} {...it} />
))}
</div>
</section>
-App.css
.DiaryEditor .emotion_list_wrapper {
/* grid는 격자를 만드는 것 */
display: grid;
/* 5개를 둘건데 크기는 작아지든 커지든 알아서 놓으라는 의미 */
grid-template-columns: repeat(5, auto);
/* gap는 아이템 사이의 거리 */
gap: 2%;
}
/* EMOTION ITEM */
.EmotionItem {
cursor: pointer;
border-radius: 5px;
padding-top: 20px;
padding-bottom: 20px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.EmotionItem img {
width: 50%;
margin-bottom: 10px;
}
.EmotionItem sapn {
font-size: 18px;
}
이렇게 나오게 된다. 이제는 감정을 누르기 전에 회색 배경으로 있고 선택된 감정은 배경 색을 다르게 해줘야 한다.
-감정 선택
-DiaryEditor.js
// 어떤 감정이 선택되었는지 체크해주는 state
const [emotion, setEmotion] = useState(3);
//감정 클릭시 발생하는 기능
const handleClickEmote = (emotion) => {
setEmotion(emotion);
};
이렇게 감정을 저장해줄 state를 만들고 기본 감정은 3으로 해준다. 그리고 감정 클릭시 감정의 번호를 전달해준다.
<section>
<h4>오늘의 감정</h4>
<div className="input_box emotion_list_wrapper">
{emotionList.map((it) => (
<EmotionItem
key={it.emotion_id}
{...it}
onClick={handleClickEmote}
// 자신이 선택된 감정인지 아닌지 알기 위한 prop
// 선택된 emotion의 값과 같다면 true 전달
isSelected={it.emotion_id === emotion}
/>
))}
</div>
</section>
그리고 onClick에서 handleClickEmote로 전달해준다. isSelected는 선택된 감정이면 True, 아니면 False 전달
-EmotionItem.js
const EmotionItem = ({
emotion_id,
emotion_img,
emotion_descript,
onClick,
}) => {
return (
<div onClick={() => onClick(emotion_id)} className="EmotionItem">
<img src={emotion_img} />
<span>{emotion_descript}</span>
</div>
);
};
export default EmotionItem;
EmotionEditor에서 onClick로 감정을 전달 받으면 된다.
그리고 개발자 도구 DiaryEditor에서 감정들을 눌러보면 state 번호가 바뀌는 것을 알 수 있다.
게다가 선택된 2번 감정은 isSelected가 true로 나온다.
이제 감정이 선택되었냐 안되었냐에 따라 다르게 나오도록 해야한다.
-EmotionItem.js
const EmotionItem = ({
emotion_id,
emotion_img,
emotion_descript,
onClick,
isSelected,
}) => {
return (
<div
onClick={() => onClick(emotion_id)}
className={[
"EmotionItem",
isSelected ? `EmotionItem_on_${emotion_id}` : `EmotionItem_off`,
].join(" ")}
>
<img src={emotion_img} />
<span>{emotion_descript}</span>
</div>
);
};
export default EmotionItem;
isSelected를 받고 True이면 EmotionItem_on이고 아니면 EmotionItem_off로 클래스 네임을 갖게 했다.
-App.css
.EmotionItem_off {
background-color: #ececec;
}
.EmotionItem_on_1 {
background-color: #64c964;
color: white;
}
.EmotionItem_on_2 {
background-color: #9dd772;
color: white;
}
.EmotionItem_on_3 {
background-color: #fdce17;
color: white;
}
.EmotionItem_on_4 {
background-color: #fd8446;
color: white;
}
.EmotionItem_on_5 {
background-color: #fd565f;
color: white;
}
off와 on으로 차이를 주고 on은 각각 색에 맞춰서 바꿔주면 완성이다.
오늘의 일기
-DiaryEditor.js
// 오늘의 일기 state
const [content, setContent] = useState("");
// 오늘의 일기에서 focus 기능에 사용 할 useRef
const contentRef = useRef();
일기 내용에 사용할 state 생성하고 useRef도 만든다.
<section>
<h4>오늘의 일기</h4>
<div className="input_box text_wrapper">
<textarea
placeholder="오늘은 어땠나요"
ref={contentRef}
value={content}
onChange={(e) => setContent(e.target.value)}
/>
</div>
</section>
그리고 textarea를 통해 만들어준다.
-App.css
.DiaryEditor textarea {
font-family: "Nanum Pen Script";
font-size: 20px;
box-sizing: border-box;
width: 100%;
min-height: 200px;
/* vertical로 안주면 가로로 움직인다. 이걸 주면 세로로만 움직인다. */
resize: vertical;
border: none;
border-radius: 5px;
background-color: #ececec;
padding: 20px;
}
오늘의 일기까지 완성되었다.
취소하기, 완료하기 버튼
-DiaryEditor.js
// onCreate 가져오기
const { onCreate } = useContext(DiaryDispatchContext);
// 작성 완료 기능
const handleSubmit = () => {
if (content.length < 1) {
contentRef.current.focus();
return;
}
onCreate(date, content, emotion);
// 일기 데이터 저장하면 홈으로 돌아간다.
// 그래서 일기 작성하는 페이지를 뒤로가게해서 못도록하게 한다.
navigate("/", { replace: true });
};
App.js에서 만든 onCreate를 가져오고 작성 완료 버튼을 처리 해줄 수 있는 기능을 만든다.
<section>
<div className="control_box">
<MyButton text={"취소하기"} onClick={() => navigate(-1)} />
<MyButton text={"작성완료"} type={"positive"} onClick={() => {}} />
</div>
</section>
취소하기, 작성완료 버튼을 만들었다. 취소하기 버튼은 뒤로 갈 수 있도록 했고 작성완료 버튼은 일기를 저장하고 다시 홈으로 돌아간다.
-App.css
.DiaryEditor .control_box {
display: flex;
justify-content: space-between;
align-items: center;
}
이렇게 새로운 일기를 작성할 수 있다.
'인프런, 유데미 > 한입 크기로 잘라 먹는 리액트' 카테고리의 다른 글
DAIRY 구현 (0) | 2022.06.23 |
---|---|
EDIT 구현 (0) | 2022.06.23 |
HOME 구현하기 (0) | 2022.06.21 |
프로젝트 기초 공사 2 (0) | 2022.06.20 |
프로젝트 기초 공사 1 (0) | 2022.06.19 |