다음으로는 새로운 일기를 작성하는 New 페이지 UI를 만들어보자.
컴포넌트 단위로 해당 페이지를 쪼개어보면 다음 이미지와 같다.

1. Header 컴포넌트
헤더 컴포넌트는 미리 만들어진 Header 컴포넌트를 들고와 사용해주자.
적절한
title을 넣고 완성본과 같이 leftChild 속성만 넣어주고버튼 컴포넌트를 들고와주자.
버튼 컴포넌트에 클릭 이벤트는 임시로 콘솔 출력 코드로 넣어주었다.
import Button from "../components/Button";
import Header from "../components/Header";
const New = () => {
return (
<div>
<Header
title={"새 일기 쓰기"}
leftChild={
<Button
text={"< 뒤로가기"}
onClick={() => {
console.log("뒤로가기 버튼 클릭됨");
}}
/>
}
/>
</div>
);
};
export default New;2. Editor 컴포넌트
먼저 에디터 역할을 할 컴포넌트를 jsx 파일로 만들어주고
css도 같이 만들어주도록 하자.
기본적인 컴포넌트 구조를 만들고 네 개의 섹션을 만들어
각각의 className을 할당했다.
import "./Editor.css";
const Editor = () => {
return (
<div className="Editor">
<section className="date_section"></section>
<section className="emotion_section"></section>
<section className="content_section"></section>
<section className="button_section"></section>
</div>
);
};
export default Editor;1. date_section
먼저 날짜를 선택하는 섹션을 구현하자.
1. UI
<section className="date_section">
<h4>오늘의 날짜</h4>
<input type="date" />
</section>;2. 스타일
.Editor section h4 {
font-size: 22px;
font-weight: bold;
}
.Editor section input {
background-color: rgb(236, 236, 236);
border: none;
border-radius: 5px;
font-size: 20px;
padding: 10px 20px;
}2. emotion_section
다음으로 이모션을 선택하는 영역을 구현해보자.
1. UI
이모션을 선택하는 영역을 보면 같은 디자인이 다섯 번
반복되는 것을 확인할 수 있다.
우리는 이걸 컴포넌트로 만들어 렌더링 할 것이다.
import "./EmotionItem.css";
import { getEmotionImage } from "../util/get-emotion-image";
const EmotionItem = () => {
return (
<div className="EmotionItem">이모션 아이템</div>
);
};
export default EmotionItem;그리고 Editor 컴포넌트 내부에서 다섯 번 뿌리자.
첫 번째 아이템에 props를 전달해서 해당 컴포넌트에서
변경되는 값을 전달해주도록 하자.
<section className="emotion_section">
<h4>오늘의 감정</h4>
<div className="emotion_list_wrapper">
<EmotionItem emotionId={1} emotionName={"완전 좋음"} />
<EmotionItem />
<EmotionItem />
<EmotionItem />
<EmotionItem />
</div>
</section>;다시 이모션아이템 컴포넌트로 돌아와서 props를
객체 형태로 받아 이미지와 텍스트가 들어갈 자리에
넣어주자.
이미지를 불러오는 방식은 미리 만들어두었던 함수를 사용하자.
해당 함수를 호출해서 인수로 emotionId를 받으면 알맞은
이미지가 들어가게끔 되어있으니 참고하자.
import "./EmotionItem.css";
import { getEmotionImage } from "../util/get-emotion-image";
const EmotionItem = ({ emotionId, emotionName }) => {
return (
<div className="EmotionItem">
<img className="emotion_img" src={getEmotionImage(emotionId)} alt="" />
<div className="emotion_name">{emotionName}</div>
</div>
);
};
export default EmotionItem;하지만 이런 방식으로 에디터 컴포넌트에서 매번 props로
일일히 전달하는 방식은 좋지 않다.
실무라고 가정한다면 props의 이름이 바뀌거나
새로운 props가 추가된다고 하면 매번 모든 컴포넌트를
수정해야 할 일이 생기기 때문이다.
그래서 이러한 정보들을 미리 배열로 만들어놓고
map 메서드를 활용해 편하게 뿌려주는 형태로 바꿨다.
먼저, 에디터 컴포넌트의 외부에 props로 전달되는
값들을 배열 안에 객체 형태로 넣어 emotionList이라는
변수에 할당해주자.
const emotionList = [
{ emotionId: 1, emotionName: "완전 좋음" },
{ emotionId: 2, emotionName: "좋음" },
{ emotionId: 3, emotionName: "그럭저럭" },
{ emotionId: 4, emotionName: "나쁨" },
{ emotionId: 5, emotionName: "끔찍함" },
];그리고 기존에 다섯 번 넣었던 이모션아이템 컴포넌트를
모두 삭제하고 만들어두었던 배열을 map메서드로 돌려
각각의 값을 해당 컴포넌의 key와 props 자리에 넣어주었다.
<section className="emotion_section">
<h4>오늘의 감정</h4>
<div className="emotion_list_wrapper">
{emotionList.map((item) => (
<EmotionItem key={item.emotionId} {...item} />
))}
</div>
</section>;알아서 렌더링이 잘 된다!
추후에 수정이 필요할 땐 map 메서드 내부나
만들어둔 배열만 수정하면 되기 때문에 편리하다!

2. 스타일
Editor.css
.Editor .emotion_section .emotion_list_wrapper {
display: flex;
justify-content: space-around;
gap: 2%;
}EmotionItem.css
.EmotionItem {
background-color: rgb(236, 236, 236);
padding: 20px;
border-radius: 5px;
cursor: pointer;
text-align: center;
}
.EmotionItem .emotion_img {
width: 50%;
margin-bottom: 10px;
}
3. 클릭된 감정요소 스타일 추가
상태 관리는 나중에 기능을 개발할 때 하겠지만
클릭 된 감정 요소의 스타일을 변경하는 로직만
미리 만들어놓자.
먼저 에디터 컴포넌트 내부에 임시의 이모션아이디 값을
만들어주도록 하자.
const emotionId = 1;다음으로 이모션아이템 컴포넌트에 isSeleted라는
props를 만들고 item의 이모션 아이디와 같은지
비교하여 true / false를 전달할 수 있도록 하자.
<div className="emotion_list_wrapper">
{emotionList.map((item) => (
<EmotionItem
key={item.emotionId}
{...item}
isSeleted={item.emotionId === emotionId}
/>
))}
</div>;그럼 현재 임시로 저장해둔 이모션아이디 1과 일치하는
첫 번째 요소에 true 값이 전달 되는 걸 개발자 도구를 통해
확인할 수 있다.

이제 이모션아이템 컴포넌트에서 이 props를 받아
className에 활용해주자.

리터럴 문법을 사용하여 isSelected가 true일 때
EmotionItem_on_${emotionId} 라는 이름을 추가하고그렇지 않을 땐 빈 문자열을 넣어주자.
<div
className={`EmotionItem ${isSelected ? `EmotionItem_on_${emotionId}` : ""}`}
>
<img className="emotion_img" src={getEmotionImage(emotionId)} alt="" />
<div className="emotion_name">{emotionName}</div>
</div>;현재 임시로 넣어둔 이모션아이디가 1이기 때문에
첫 번째 요소에 className이 추가 된 걸 개발자도구의
elememt 탭에서 확인할 수 있다.

그리고 각각의 스타일을 추가해주자.
.EmotionItem_on_1 {
color: white;
background-color: rgb(100, 201, 100);
}
.EmotionItem_on_2 {
color: white;
background-color: rgb(157, 215, 114);
}
.EmotionItem_on_3 {
color: white;
background-color: rgb(253, 206, 23);
}
.EmotionItem_on_4 {
color: white;
background-color: rgb(253, 132, 70);
}
.EmotionItem_on_5 {
color: white;
background-color: rgb(253, 86, 95);
}
3. content_section
1. UI
<section className="content_section">
<h4>오늘의 일기</h4>
<textarea placeholder="오늘은 어땠나요?"></textarea>
</section>;2. 스타일
기존의 input 스타일에 낑가넣고
더 필요한 스타일은 별도로 추가했다.
.Editor section input,
textarea {
background-color: rgb(236, 236, 236);
border: none;
border-radius: 5px;
font-size: 20px;
padding: 10px 20px;
}
.Editor section textarea {
padding: 20px;
width: 100%;
min-height: 200px;
resize: vertical;
box-sizing: border-box;
}
4. button_section
1. UI
<section className="button_section">
<Button text={"취소하기"} />
<Button text={"작성 완료"} type={"POSITIVE"} />
</section>;2. 스타일
.Editor section {
margin-bottom: 40px;
}
.Editor .button_section {
display: flex;
justify-content: space-between;
}일기를 작성하는 New 페이지의 UI 구현이 끝났다.
다음은 기능 구현을 해보자.

Share article