

재사용 가능한 UI Component를 한 눈에 확인 가능한 프리뷰 페이지입니다.

이번 과제는 컴포넌트 재사용에 초점이 맞춰져있다고 판단하였다. 그래서 각자 UI요소를 2개씩 맡아서 작업하고, 서로가 만든 UI컴포넌트를 사용해보기로 하였다.
문제에 봉착하면 어떤 방법이 더 재사용에 이로운지를 고민하며 작업했다.
이전까지는 git으로 팀 작업을 할 기회가 많지 않았다. 마지막 실전가서 문제가 터지기 전에 브랜치를 나눠 작업하고 합치는 연습을 하자는 의지로 git merge 작업을 했다.
코드를 작성하는 시간과 git으로 고통받는 시간이 1:1일 정도로 많이 헤맸다. 로컬과 원격 저장소가 다르다는 것도 처음 알게되었다.
어쩌다가 내가 dev 브랜치를 만들어서 최종 전까지 git merge를 많이 해볼 수 있었다. 적어도 다른 사람 작업을 합치는 건 괜찮게 하는 듯 하다.
매우 작은 프로젝트이지만 merge과정 중에 충돌을 최대한 피하고자 각자 작업 영역을 확실하게 나눴다. 먼저 공통 레이아웃을 잡고 프로젝트를 진행했다. 좌우로 레이아웃을 나누고 나는 left에서 페어분은 right에서 작업했다. 그래서 merge과정에 충돌하는 일이 확실하게 거의 없었다.
이전에 페어를 맺었던 민승님께서 컬러 에셋을 배열로 저장해서 불러오는 방식을 살짝 보여주셨는데 바로 이걸 써보기로 했다. 그레이쉬 컬러와 푸른색이 도는 컬러 2개로 나눠서 배열로 저장하였다. 순서는 0으로 갈수록 어두운 컬러를 넣었다.
생각보다 편했다. 이것저것 컬러를 찾으러 돌아다니지 않고 배열의 인덱스를 바꾸면서 적절한 명도를 찾아넣기가 좋았다. 채도별로 배열을 나누고 명도별로 정렬하니 사용감이 쾌적하다.
저장한 배열의 인덱스가 최대 4까지였는데 좀 더 세분화 해서 저장했으면 좋았을 것 같다. 헥사코드로 저장을 했는데 다음에는 RGB형식을 고려해야겠다. 헥사코드는 RGBA로 투명도를 조절할 수 없다는 난점이 있다.
예제 사이트에서 제시한 버튼은 6가지로, 컬러 2종과 사이즈 3개, 아이콘을 선택적으로 넣을 수 있었다. 나는 스타일가이드를 찾아보면서 만들 버튼의 변화를 생각을 했다. Primary button, Secondary button 2가지 색상 변화를 갖고 아이콘만 들어간 버튼까지 하여 총 8가지 베리에이션을 한 스타일가이드를 참고하여 작업하였다.
PrimaryButton
const PrimaryButton = ({ children, ...restProps }) => {
return (
<ButtonStyle
{...restProps}
$bc={blueColor[1]}
$hover_color={blueColor[2]}
$font_color={blueColor[4]}
$hover_font_color={blueColor[0]}
>
{children}
</ButtonStyle>
);
};
버튼에 들어가는 텍스트는 children으로 받는다.
처음엔 아이콘+텍스트 / 텍스트 / 아이콘 으로 버튼을 나눌 생각이었는데
버튼을 사용할 때 아이콘을 선택적으로 넣을 수 있도록 하였다. 하나를 넣든 양쪽에 넣든 space-between으로 정렬해준다.
...restProps를 사용하면 나머지 props들을 스프레드로 들고온다.
PrimaryButton 사용
<Button.Primary width="250px" onClick={() => prompt('입력받기', '')}>
<Icon.Heart />
ui components
<Icon.Heart />
</Button.Primary>
만들어진 버튼은 3가지 버전이 있다. Button.버전으로 쓰면 해당 스타일의 버튼을 사용할 수 있다.
그 외에 width값을 주지 않아서 안에 들어간 텍스트를 기준으로 넓이를 잡는데 그것보다 좌우로 크게 쓰고 싶을 때를 위해 width와 center는 props로 받을 수 있게 하였다.
시작은 어렵지 않게 했는데 이번에는 transform이 문제다.
export const Selecter = () => {
const selectOption = [
{ value: '리액트', text: '리액트' },
{ value: '자바', text: '자바' },
{ value: '스프링', text: '스프링' },
{ value: '리액트 네이티브', text: '리액트 네이티브' },
];
const [selectBox, setSelectBox] = useState(false);
const [selectBtnText, setSelectBtnText] = useState(selectOption[0].text);
const SelectClick = () => {
setSelectBox(!selectBox);
};
const OptionClick = (option) => {
setSelectBtnText(option);
setSelectBox(!selectBox);
};
return (
<>
<Button.Secondary width="250px" onClick={SelectClick}>
{selectBtnText}
<Icon.CaretDown />
</Button.Secondary>
{selectBox && (
<SelectItemNonHidden>
<SelectList>
{selectOption.map((option, idx) => {
return (
<SelectItem
key={idx}
value={option.value}
onClick={() => OptionClick(option.value)}
>
{option.text}
</SelectItem>
);
})}
</SelectList>
</SelectItemNonHidden>
)}
</>
);
};
미해결 문제
이쁘게 하고 싶다고 UI 카드에 transform을 사용한 hover 애니메이션을 넣었는데 이게 화근이다. SelectList 부분에 absolute을 넣고 z-index를 넣어도 부모 요소 hidden에 가려진다. 리액트 포탈을 쓰자니 hover애니메이션에 따라 UI위치가 움직이는데 리액트 포탈로 만든 SelectList는 고정되어 있어서 어색하다. 😥
문제를 찾다가 transform을 적용한 요소에 가려진다는 걸 알게되었다. 검색을 해봐도 transform과 absolute는 상관관계가 없다고 한다. 임시방편으로 가려지면 안되는 select의 Uibox만 transform:none을 걸어놨다. 이건 다음에 기술매니저님을 만나면 물어보려고 한다.
사실 페어로 작업하기 전에 먼저 한 번 만들어봤다. 그래서 작업이 더 빨랐던 것 같다. select는 혼자 작업했을 때보다 코드가 심플해졌는데 코드가 좋아졌다는건 아니고 뭔가 기능이 많이 빠졌나보다. 걱정되네 ㅎㅎㅎ
1차, 2차 모범답안들을 보면서 많이 참고를 하고 있다. icons.js를 만들어서 icon을 일괄적으로 불러온다거나, childen 사용법, 리액트 포탈, export하는 여러 방법들 등등 작지만 여러가지 시도를 해본 것 같다. 마지막에 폴더 구조 정리하면서 저번보다는 만족스럽다고 생각한다.
예제 사이트도 뜯어보고, 시험으로 내주는 코드도 보고, 강의 자료로 제공하는 코드도 보고. 이론만 찾아보는 것 보다 다른사람 작업물을 보는게 많이 도움이 되고있다. 이쪽 공부방법이 더 잘 맞는지도 모른다.