Custom Selector 만들기

이재진·2023년 10월 3일

모애프로젝트

목록 보기
2/16

Custom Selector

상황

게시판 글 쓰기 페이지 구현 중, 문제가 발견되었다. API요청을 보낼 때,
main, sub 카테고리를 나눠서 보내야하는데, 기존에 <select>를 사용하면, sub카테로리는 불러와지지만, main을 불러올 수 없는 문제가 발생했다. 그래서 직접 구현해 보기로 했다.


👉시작

작업 자체는 간단했다. boolean값으로 state를 주고, 해당 state가 false라면 CSS를 변경하는 코드를 작성하면 되는 것이었다.

해당 정보를 보여주는 콤보박스를 만드는 것이 목표

const boardList = [
    {
      id: 1,
      main: '자유',
      sub: ['잡담', '홍보'],
    },
    {
      id: 2,
      main: '멘토멘티',
      sub: ['공부', '운동', '토익'],
    },
    {
      id: 3,
      main: '만남',
      sub: ['친구', '밥약', '미팅'],
    },
    {
      id: 4,
      main: '장터',
      sub: ['책', '중고', '자취방'],
    },
  ];

state값을 주어서 열리고 닫히게 만들 것이다. 그리고 그 안에 map을 돌려서 값들을 불러와 줄 예정

const [ isCheckShow, setCheckShow ] = useState<boolean>(false);

return (
  <div onClick={()=> setCheckShow(!isCheckShow)}>
    <div>게시판</div>
    <div>
      {boardList.map((list)=>{
      	return (
          <div>
            {list.main}게시판
            {list.sub.map((sub, idx)=>{
            	return <div onClick={}>{sub}</div>
            }}
          </div>
      }}
    </div>
  </div>

onClick이벤트 시 state가 변경되도록 했다. 이제 여기에 CSS만 입히면 끝이다.

<SelectBox onClick={() => setCheckShow(!isCheckShow)}>
  <Label>게시판</Label>
  <SelectOptions show={`${isCheckShow}`}>
    {boardList.map((list) => {
      return (
        <div key={list.id}>
          {list.main}게시판
          {list.sub.map((sub, idx) => {
            return (
              <Option key={idx}>
                {sub}
              </Option>
            );
          })}
        </div>
      );
    })}
  </SelectOptions>

SelectOptions 부분에 show라는 props를 전달해서 state값이 true일 때 콤보박스가 보여지게 만들었다.
CSS는 인터넷 여기저기서 긁으니깐 잘 나왔다ㅎ

/** selectbox container*/
const SelectBox = styled.div`
  position: relative;
  margin-left: auto;
  width: 200px;
  padding: 8px;
  border-radius: 5px;
  background-color: #ffffff;
  align-self: center;
  box-shadow: 0px 5px 15px rgba(0, 0, 0, 25%);
  cursor: pointer;
  z-index: 1;
  &::before {
    content: '⌵';
    position: absolute;
    top: 1px;
    right: 8px;
    font-size: 20px;
  }
`;

/** select title*/
const Label = styled.label`
  font-size: 14px;
  margin-left: 4px;
  text-align: center;
`;

interface SO {
  show: string;
}

/** state가 true라면 보여주게 만들기*/
const SelectOptions = styled.div<SO>`
  position: absolute;
  list-style: none;
  top: 36px;
  left: 0;
  width: 100%;
  overflow: hidden;
  height: auto;
  max-height: ${(props) => (props.show === 'true' ? 'none' : '0')};
  padding: 0;
  border-radius: 8px;
  background-color: #222222;
  color: #fefefe;
`;

const Option = styled.div`
  font-size: 14px;
  padding: 6px 8px;
  transition: background-color 0.2s ease-in;
  &:hover {
    background-color: #595959;
  }
`;

여기저기에서 긁어온 css를 우리 페이지 스타일에 맞게 고쳐주기만 하면 된다!

여기서 끝인줄 알았으나, 외부를 클릭했을 때, 콤보박스가 닫히지 않는 이슈가 생겼다!
어떻게 하면 좋을까 하다가 z-index를 사용해서 외부에 보이지않는 div를 만들어서 누르면 닫히게 만들 예정이다!

{isCheckShow && (
  <DropDown
    onClick={(e: React.MouseEvent) => {
      e.preventDefault();

      if (isCheckShow) {
        handleClose();
      }
    }}></DropDown>
)}

const DropDown = styled.div`
  background-color: rgba(f, f, f, 100%);
  position: fixed;
  z-index: -1;
  left: 0px;
  top: 0px;
  width: 10000px;
  height: 1000px;
  cursor: auto;
`;

해당 코드를 SelectBox내부에 추가해주고, handleClose함수를 만들어서 작동되게 했다.

const handleClose = () => {
 setCheckShow(!isCheckShow);
}

이렇게 하니깐 잘 작동된다!

profile
소통하는 개발자

0개의 댓글