코로 넘어져도 헤딩만 하면 그만
장보기 todo-List 만들기3(emotion 학습) 본문
🚩Emotion
1) 조금 더 깔끔하게 쓰기 위하여(≠styled-component 방식)
import React from "react";
import { listState } from "./atoms/listState";
import { useRecoilState } from "recoil";
import { MdDelete } from "react-icons/md";
import { FaPenToSquare } from "react-icons/fa6";
/** @jsxImportSource @emotion/react */
import { css } from "@emotion/react";
function TodoItem({item}) {
const [todo, setTodo] = useRecoilState(listState);
const handleDeleteItemClick = (itemId)=>{
const newTodoItemList = todo.filter((item )=> item.id !== itemId);
setTodo(newTodoItemList);
}
return (
<div css={css({display:"flex", justifyContent:"left", margin:"20px"})}>
<div><input type="checkbox" css={css({zoom:"1.4", cursor:"pointer"})}/></div>
<span css={css({fontSize:"20px", fontWeight:"700", marginLeft:"10px",
marginRight:"10px"})}>{item.content}</span>
<div>
<button css={css({cursor:"pointer", marginRight:"5px", borderRadius:"5px"})}>
<FaPenToSquare /></button>
<button css={css({cursor:"pointer", borderRadius:"5px"})}
onClick={()=> handleDeleteItemClick(item.id)}><MdDelete/></button>
</div>
</div>
);
}
export default TodoItem;
지난 주에는 급한대로 기능을 하나하나 추가하며 처음부터 공부했다. 따라서 emotion를 위와 같이 사용하는 방식으로 레이아웃을 마무리하는 수밖에 없었다. 하지만 여유가 생기고 나자 이 코드는 볼수록 가독성이 떨어지고 지저분하게 느껴졌다. 따라서 이번주는 상단 emotion의 코드부터 리펙토링하기로 하였다.(암만 생각해도 이렇게 쓸 것 같진 않았다...)
사실 emotion은 내가 선택한 방식인 @emotion/react가 아닌 @emotion/styled로 사용하면 기존까지 styled-component를 쓰던 구조 그대로 사용할 수 있다. 그러나 이 방식을 사용하면 styled-componet를 사용할 때에도 해결하지 못한 문제, 즉 어떤 html 태그를 사용하였는지 직관적으로 알아볼 수 없다는 문제에 봉착한다.
간단한 예를 들어 아래와 같은 코드를 보자.
<List>이 태그는 무엇일까요?</List>
const List = styled.section`
color: blue;
`
잠깐 이전까지 프로젝트에서 자주 쓰던 방식인 styled-component로 넘어와보자.
위와 같은 방식은 일견 간결하고 보기 좋지만, 필요할 때는 직접 <List/>를 정의한 코드까지 이동해서 확인해야 해당 태그가 section 태그로 구성되었음을 알 수 있다. 전체 코드 양이 적다면 어렵지 않은 작업이나 코드가 복잡하고 스타일이 정의된 태그가 다수일경우 일일이 확인하는 과정에서 상당한 에너지와 시간이 소모된다. 심지어 스타일 정의하는 부분을 완전히 다른 파일로 분리한 뒤 불러와 사용할 경우(이쪽이 대개 선호된다.) 태그 하나를 찾기 위해 해당 파일을 열어서 보는 부가 노력이 필요했다. 이는 기존까지 내가 styled-component를 사용할 때마다 강하게 느낀 문제였다.
따라서 emotion을 사용할 때는 기존과는 다른 방식을 써보고 싶어서 아래와 같이 코드를 수정했다.
styled-component에서 사용하던 것처럼 styled 부분은 하단에 따로 분리해서 정의한다. 그러나 html 태그는 남겨두고 각 태그의 css에만 원하는 styled을 준다. 아래의 코드는 리펙토링 하기 전보다 보기 좋으면서, styled-component 처럼 사용하는 것과 달리 사용된 태그를 즉시 알아볼 수 있다.
function TodoItem({item}) {
const [todo, setTodo] = useRecoilState(listState);
const handleDeleteItemClick = (itemId)=>{
const newTodoItemList = todo.filter((item )=> item.id !== itemId);
setTodo(newTodoItemList);
}
return (
<div css={todoItemContainer}>
<input type="checkbox" css={isDoneCheckbox}/>
<span css={itemContent}>{item.content}</span>
<div css={css({minWidth:"70px"})}>
<button css={[itemBtn, btnMargin]}><FaPenToSquare /></button>
<button css={itemBtn} onClick={()=> handleDeleteItemClick(item.id)}><MdDelete/></button>
</div>
</div>
);
}
export default TodoItem;
const todoItemContainer = css`
display: flex;
justify-content: left;
margin: 20px;
`
const isDoneCheckbox = css`
zoom: 1.4;
cursor: pointer;
`
const itemContent = css`
font-size: 20px;
font-weight: 700;
margin:0 10px;
text-align: start;
`
const itemBtn = css`
cursor: pointer;
border-radius: 5px;
`
const btnMargin = css`
margin-right: 5px;
`
검색해볼수록 emotion을 사용하는 코드 스타일은 다양해서 무엇이 옳다 단언하기 어렵게 느껴졌다. 아마 개발자나 회사 별로 선호 스타일이 다를 것이다. 그러나 현재로서는 내가 느낀 불편함에 미루어볼 때 이렇게 쓰는 emotion의 장점이 꽤 크게 있어 보인다. 따라서 나는 추후 emotion을 또 쓰게 된다면 이 방식으로 사용하는 걸 우선으로 고려해볼 것 같다.(물론 프로젝트에 따라 다르겠지만 말이다!)
2) Emotion 사용할 때 다양한 스타일 혼합하기

위와 같이 모달 창의 기본 디자인을 만들고 전체삭제에 대해 Yes/No로 의사를 묻는 버튼을 각각 만들어두었다.
두 버튼은 유사 디자인을 가진 버튼이라는 동일 속성을 지니고 있지만 background와 color에 차이를 갖는다. 그렇다면 어떤 식으로 공통된 속성 스타일과 상이한 속성 스타일을 넘겨줄 수 있을까. 여러모로 고민하며 찾던 중, 하단에 코드와 같이 css함수 부분에 다중의 스타일을 배열로 넘길 수 있음을 알게 되었다.
물론 아직은 공부 단계라서 이것이 최적의 emotion 사용법인지는 잘 모르겠지만…
아래처럼 modalBtn로는 공유되는 스타일, yesBtn-noBtn로 서로 다른 스타일을 각각에게 적용할 수 있었다.
<div css={modalBtnsContainer}>
<button onClick={deleteItemList} css={[modalBtn, yesBtnStyle]}>예</button>
<button css={[modalBtn, noBtnStyle]} onClick={setModalStateDefault}>아니오</button>
</div>
const modalBtn = css`
width: 150px;
height: 40px;
border-radius: 80px;
margin: 0 5px;
cursor: pointer;
font-family: 'seolleimcool-SemiBold';
font-weight: 800;
font-size: 16px;
outline: none;
border: 1px solid #eb7473;
`
const yesBtnStyle = css`
background-color: #eb7473;
color: white;
&:hover{
background-color: #f75a55;
}
&:active {
background: #b31d1a;
}
`;
const noBtnStyle = css`
background-color: #fff;
color: #333;
&:hover{
background-color: #eee;
}
&:active {
background: #e0e0e0;
}
`;
부가적으로…
🚩Header의 적절한 css 고려하기..... (fixed와 투명도 사용)
만약에 todo 리스트가 아주 길어진다면?
…이라는 문제점에서 시작한 고민이다. 목록 리스트가 아주 길어진 경우..... 가령 50가지의 장보기 목록이 생성된 경우를 가정해보자. 이때 스크롤을 한참 내리다가 검색을 하기 위해 다시 맨 위로 돌아오는 것은 번거로운 일이다. 따라서 고민 끝에 헤더가 상단에 고정되어 스크롤을 내려도 위에 존재하도록 position: fixed를 주기로 했다. 또한 너무 화면 비율이 좁아져서 위쪽이 답답해보일 것 같아 rgba로 투명도를 주었다.
결론적으로 아래와 같이 조금 더 보기 시원스러운 헤더가 완성되었다.

const header = css`
height: 120px;
position: fixed;
background-color: rgb(255,255,255,0.9);
top: 0;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
font-size: 29px;
font-weight: 600;
border-bottom: 3px solid #ccc;
font-family: 'seolleimcool-SemiBold';
`
만약 추가적인 기능을 좀더 넣는다면 아래와 같은 요소가 있겠다.
- 타입 스크립트로 마이그레이션
- checkbox 체크 시 줄 긋기
- 다크모드. 버튼도 만들어뒀는데 구현은 하질 못했다. recoil을 사용하면 될 것 같다.
- item 수정하기
- 체크된-비체크된 항목만 따로 보여주기(문제: 보여주는 부분의 조건이 점점 복잡해진다…)
- emotion의 label 사용해보기
'Etc' 카테고리의 다른 글
Error: Cannot find module 'semver' (0) | 2024.03.13 |
---|---|
장보기 todoList 만들기 4 emotion의 label (0) | 2024.01.18 |
장보기 todo-List 만들기2(recoil 학습) (0) | 2024.01.16 |
[AutoSet]오토셋 이용해서 공통 헤더-푸터 파일 분리하기 (0) | 2022.11.03 |
[Git]깃허브에 새 프로젝트 저장하는 법 (0) | 2022.10.21 |