글작성과 수정이 겹치는 부분이 많아서 DiaryEditor 컴포넌트를 따로 만들었다
import DiaryEditor from "../components/DiaryEditor"
const New = () => {
return (
<div>
<DiaryEditor />
</div>
)
};
export default New;
그리고 New컴포넌트에서 DiaryEditor를 불러와주었따
헤더 만들기
import { useNavigate } from "react-router-dom";
import MyHeader from "./components/MyHeader"
import MyButton from "./components/MyButton"
const DiaryEditor = () => {
const navigate = useNavigate();
return (
<div>
<MyHeader
headText={"새 일기 쓰기"}
leftChild={<MyButton text={"< 뒤로가기 "} onClick={() => navigate(-1)} />}
/>
</div>
);
};
export default DiaryEditor;
미리 만들어둔 헤더 컴포넌트를 부르고 뒤로가기 왼쪽엔 버튼을 수행할 MyButton 컴포넌트를 가지고온다.
그리고 뒤로가기가 실제로 수행이 되도록 useNavigate함수를 통해 뒤로가기 기능을 넣어주었다
날짜 선택 부분 구현하기
const DiaryEditor = () => {
const [date, setDate] = useState();
const navigate = useNavigate();
return (
<div>
<MyHeader
headText={"새 일기 쓰기"}
leftChild={<MyButton text={"< 뒤로가기 "} onClick={() => navigate(-1)} />}
/>
<div>
<section>
<h4>오늘은 언제인가요?</h4>
<div className="input-box">
<input value={date} onChange={(e) => setDate(e.target.value)} type={"date"} />
</div>
</section>
</div>
</div>
);
};
input 타입을 date로 지정해주면 달력모양 input태그가 생성된다
값을 저장하기위해 상태변화함수 useState를 임포트 해주고 date를 담을 useState함수를 넣어 onChange이벤트를 준다
mount 됐을때 오늘의 날짜로 기본 설정
const getStringDate = (date) => {
let year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
if (month < 10) {
month = `0${month}`;
}
if (day < 10) {
day = `0${day}`;
}
return `${year}-${month}-${day}`;
}
getStringDate 상수를 만들어준 후 useState 함수 안에 넣어 초기값을 주었다
toISOString함수는 날짜를 ISO8601형식의 문자열로 반환해주는 함수
오늘의 날짜가 잘 나타나는것을 확인할 수 있다
본문 전 CSS 추가
/* DiaryEditor */
.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;
cursor: pointer;
font-family: "Nanum Pen Script";
font-size: 20px;
}
본문 감정 이미지 넣기
const env = process.env;
env.PUBLIC_URL = env.PUBLIC_URL || "";
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: '끔찍'
},
]
이미지를 넣기위한 링크객체를 배열로 만들고
const EmotionItem = ({ emotion_id, emotion_img, emotion_descript }) => {
return (
<div className="EmotionItem">
<img src={emotion_img} />
<span>{emotion_descript}</span>
</div>
)
}
export default EmotionItem;
EmotionItem컴포넌트를 만들어 분리시켜준 후
<section>
<h4>오늘의 감정</h4>
<div className="input_box emotion_list_wrapper">
{emotionList.map((it) => (
< EmotionItem key={it.emotion_id}{...it} />
))}
</div>
</section>
컴포넌트 리턴내에 두번째 색션을 만들어주었따
.DiaryEditor .emotion_list_wrapper {
display: grid;
grid-template-columns: repeat(5, auto);
gap: 2%;
}
/* EmotionItem */
.EmotionItem {
cursor: pointer;
border-radius: 5px;
padding: 20px 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.EmotionItem img {
width: 50%;
margin-bottom: 10px;
}
.EmotionItem span {
font-size: 18px;
}
선택된 이미지 효과 넣기
const [emotion, setEmotion] = useState(3);
const handleClickEmote = (emotion) => {
setEmotion(emotion);
}
다이어리 에디터에 이모션을 관리할 수 있는 상태와 hadleClickEmote 상수를 만들어준다.
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 >
)
}
이모션아이템 컴포넌트에 클릭시 변화될 상태props을 추가하고 태그를 넣어주었다
{emotionList.map((it) => (
< EmotionItem
onClick={handleClickEmote}
key={it.emotion_id}
{...it}
isSelected={it.emotion_id === emotion}
/>
))}
다이어리에디터 이모션 리턴부분에 onClick이벤트랑 isSelected 이벤트도 넣어주었다.
.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;
}
그리고 CSS까지 넣으면
클릭했을때 isSelect 속성에 맞추어 태그이름이 변화하고 그에 맞춰 css속성이 들어간다
일기 작성란 만들기
const contentRef = useRef();
const [content, setContent] = useState("");
다이어리 에디터 컴포넌트 내에 컨텐츠 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>
세번째 섹션을 만들어주고
css까지 적용해주면
.DiaryEditor textarea {
font-family: "Nanum Pen Script";
font-size: 20px;
box-sizing: border-box;
width: 100%;
min-height: 200px;
resize: vertical;
border: none;
border-radius: 5px;
background-color: #ececec;
padding: 20px;
}
일기작성 완성
하단버튼
<section>
<div className="control_box">
<MyButton text={"취소하기"} onClick={() => navigate(-1)} />
<MyButton
text={"작성완료"}
type={"positive"}
onClick={handleSubmit} />
</div>
</section>
마지막섹션!
const { onCreate } = useContext(DiaryDispatchContext);
const handleSubmit = () => {
if (content.length < 1) {
contentRef.current.focus();
return;
}
onCreate(date, content, emotion);
navigate("/", { replace: true });
}
값을 확인해보니 Context에만 들어오고 State는 업데이트가 안되고 있어서 엄청찾았는데..
dispatch 에 들어갈 data의 date가....
data로 적혀있었다
하.. 오타조심하자 에러도 안뿜어준다 ㅠㅠㅠㅠㅠㅠ
data안에 들어갈 값을 잘 지정해주니.. 아주 잘들어간다 ;-;
참고 :
- 한 입 크기로 잘라먹는 리액트
'개발 > Inafolio' 카테고리의 다른 글
[혼공단 8기] 5주차 미션 (0) | 2022.08.14 |
---|---|
[React] 미니프로젝트 - 일기장 글 수정 화면 구현하기 (0) | 2022.08.11 |
[React] 미니프로젝트 - 일기장 Home 화면 구현하기 (0) | 2022.08.05 |
[React] 프로젝트 기초공사하기2 - 상태분리, Provider (0) | 2022.08.03 |
[React] 프로젝트 기초공사하기 - 공통 컴포넌트, 폰트, 레이아웃 css 셋팅 (0) | 2022.08.02 |