(검색값 역할을 하는 썸네일 및 모달 버튼)
내가 구상한 프로젝트에서는 별도의 입력창은 존재하지 않는다.
썸네일을 클릭하면 썸네일의 카테고리 값이 state에 보관되고, 지역모달창이 렌더링되며, 지역모달창을 클릭시 마찬가지로 지역값이 state에 보관된다.
지역은 지역1의 대분류와 지역2의 소분류로 나뉘며, 지역1을 클릭시 지역2가 렌더링된다. 지역2의 경우는 값을 배열로 가지며, 재클릭시 배열에서 삭제된다.
쌈네일외의 카테고리를 보기 위해선, 더보기를 클릭하여 썸네일 외의 것이 등록되잇는 카테고리모달을 띄울수있다.
css도 중요하지만, 구현에 있어 상태관리를 어떻게 할지 고민해보았다.
컨테이너에서 useState를 사용할지, 리덕스를 사용할지 생각을 해보았고, 초기에는 컨테이너에서 useState를 사용하였다.
하지만 이후에 카테고리와 지역 state는 다른 컨테이너에서도 필요로 하기때문에 관리가 어려워, 별도로 리덕스로 빼게 되었다.
const onClick = (item) => {
const key = Object.keys(item).toString();
setSearchParam({
...searchParam,
[key]: item[key],
region_2: [],
});
};
(카테고리 모달과 지역 모달 클릭시 사용되는 함수)
item은 ({ region_1: item }) 와 같이 키와 값이 있는 객체형태로 전달된다.
사용되는 컴포넌트에 따라서 키를 다르게 하여 재활용이 가능하게 하였다.
const onClickReg2 = (Reg_2) => {
if (searchParam.region_2.includes(Reg_2))
setSearchParam({
...searchParam,
region_2: searchParam.region_2.filter((item) => item !== Reg_2),
});
else
setSearchParam({
...searchParam,
region_2: [...searchParam.region_2, Reg_2],
});
};
(모달의 지역2를 클릭시 사용되는 함수)
값이 이미 존재하는경우 filter를 사용하여 값을 제거하였고, 없는경우 스프레드 연산자를 사용하여 값을 복사하였다.
지역2의 전체 버튼은 기본 적용이며, 클릭시 지역2 state를 비어잇는 배열 []로 초기화 하도록 하였다. 또한 지역2의 배열이 []이면 자동으로 액티브 상태로 변환되도록 하였다.
카테고리 모달의 경우 값을 8개까지만 보여주었고, 카테고리값이 더 있을경우 마지막으로 ...태그 버튼을 생성하여 클릭시 더 노출될수있게 하였다.
modal의 경우 컴포넌트에 있을경우 보이진 않더라도 html 구조상에 렌더링 될 수있다. 때문에 react의 potal이라는 기능을 사용하였는데, 이것을 사용하면 react에서 사용하는 html의 root div의 아래에 렌더링 되는게아닌, 호출이 될때에만 지정된 root바깥쪽의 요소에서 렌더링 되기 때문에 보이지 않는 모달을 렌더링 하지 않기때문에 모달의 렌더링 비용을 줄일수있다.
//index.html의 root 바깥에 포탈에 사용될 엘리먼트 생성
<div id="root"></div>
<div id="modalPotal"></div>
// portal 컴포넌트
const ModalPortal = ({ children }) => {
const globalPortal = document.getElementById('modalPotal');
return ReactDOM.createPortal(children, globalPortal);
};
export default ModalPortal;
//실제 사용
<ModalPortal>
<CatTagModal title={'카테고리를 선택해주세요'}/>
</ModalPortal>
4주차에는 js코드의 작성보단 css 작성에 더 많은 시간을 소모하였던것 같다. react 구현은 render부분에서 약간의 로직을 제외하면 크게 문제가 됐던 부분은 없었던것 같다.
카테고리 모달과 썸네일은 직접 css를 작성해서 구현하였고, 지역 모달과 버튼은 antd를 사용하였다.
antd를 사용한 css구현에서 antd는 분명 편리하지만 실제 내가 원하는형태로 사용하기에는 조금 번거롭고 힘들다는것을 느끼게 되었다.
antd에서 제공하는건 레이아웃적으로 여러개로 나뉘어져있고, 각 설정이 있으며, 버튼같은경우에는 :focus와 같은, 내가 원하지 않는 기능까지 모두 다 들어가있다.
예를 들어 모달의 경우에는 modal에서 사용하는 타이틀 설정을 하단에서 다시 사용하고 싶은데, 이런건 지원하지 않기때문에 별도로 같은 설정을 가진 레이아웃을 만들어야 한다. 그런데 타이틀밑의 레이아웃은 별도의 마진,패딩, width,height 값과 같은게 정해진 상태일때가 많다. 때문에 커스텀해야 하는 경우 이것저것 손을 봐야 하는 경우가 많았다.
버튼의 경우에도 자동적으로 focus 상태일때는 액티브가 되는데, 나는 지역2에서 재클릭시에는 액티브가 해제되기를 바랬는데, 내부에 설정된 옵션때문에 별도로 css 재설정을 해주어야했다.
:focus {
color: rgba(0, 0, 0, 0.85);
border-color: #d9d9d9;
}
${(props) =>
props.checked &&
css`
color: #40a9ff;
border-color: #40a9ff;
background: white;
:focus {
color: #40a9ff;
border-color: #40a9ff;
}
`}
(focus부분 재정의, 한번만 클릭하였을때(checked가 true일때)는 focus가 작동해야 하고, 아닐때는 antd의 focus옵션이 발동하지 않아야한다.)
지역모달에서 지역2 버튼이 렌더링 되면 크기가 너무 커질수 있기 때문에, height는 고정으로 하되, 스크롤 기능이 있긴하지만, 스크롤은 안보이는 형태로 구현하고 싶었다.
<div class="1">
<div class="2">
</div>
</div>
이 기능을 구현하기 위해서 위와 구조에서 "1"의 overflow는 hidden으로 하고, "2"의 overflow는 auto로 하여 스크롤 기능을 사용하되, width의 값을 1보다 크게 하여 스크롤이 위치하는곳이 1의 바깥쪽에 위치하게하여 "1"의 hidden값으로 안보이게 설정하였다.
모달의 경우는 디자인을 받지 못했다. 때문에 디자인 구상까지 모두 내몫이 됐는데, 카테고리 모달의 경우는 직접 구현하였지만 심미학적으로 좀 많은 문제가 있다는것을 느꼈다.. 반면에 antd로 구현한 모달은 그나마 괜찮은 모양세였다. 때문에 디자이너의 소중함이라던가, 심미학적으로는 크게 문제가 없는 antd의 소중함을 느꼇다..
그래도 antd는 가능하면 지양하는게 좋은것 같다. 많은 기능을 제공해주지만 동시에 그게 단점이 되어서 나도 모르는 기능이 있게되고, 이게 의존성을 띄게 되어 생각치않은 버그가 나타날수 있다 생각한다. 또한 antd에서 제공하는것엔 이미 추상화가 꽤나 되어있어서 원래라면 꼭 작성해야 하는 함수까지도 내부에서 처리해주기도 한다. 그리고 내부의 레이아웃도 자동으로 해주기때문에 내가 원하는 레이아웃을 구현하려면 번거로울수있는 수정작업도 거쳐야한다. 물론 뛰어난 개발자분들이 만든것이긴 하겠지만, 그래도 가능하면 외부 라이브러리에 의존하지 않는 코드를 짜고 싶다.