[React] 16.customSelect 만들기

송우든·2022년 2월 9일
6

React

목록 보기
15/23
post-thumbnail

리액트 프로젝트를 진행하면서 기본적으로 제공되는 요소들을 커스텀해야할 때가 많이 있는데요!
오늘은 SELECT 를 직접 커스텀하여 제작하는 방법을 정리하려고 합니다!

** 저는 styled-component를 사용해서 꾸며주었어요!

💎 CustomSelect 파일 생성하기

저는 components/아래에 CustomSelect.js를 하나 만들어주었어요!

import React from "react";

const CustomSelect = () => {
  return <div>custom select</div>;
};

export default CustomSelect;

💎 구조 만들기

저는 아래와 같이 구조를 만들었어요!

  • <label>를 사용하여 현재 선택된 값을 보여줄 거에요!
  • <ul><li>를 사용하여 <option>과 같은 구조를 만들어줄거에요!
const CustomSelect = () => {
  return (
    <div>
      <label>currentValue</label>
      <ul>
        <li>option1</li>
        <li>option2</li>
        <li>option3</li>
      </ul>
    </div>
  );
};

💎 디자인 추가하기

저는 아래 화면과 같이 만들어주었어요!

스타일 코드 전체 보기
  
  const SelectBox = styled.div`
  position: relative;
  width: 200px;
  padding: 8px;
  border-radius: 12px;
  background-color: #ffffff;
  align-self: center;
  box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
  cursor: pointer;
  &::before {
    content: "⌵";
    position: absolute;
    top: 1px;
    right: 8px;
    color: #49c181;
    font-size: 20px;
  }
`;
const Label = styled.label`
  font-size: 14px;
  margin-left: 4px;
  text-align: center;
`;
const SelectOptions = styled.ul`
  position: absolute;
  list-style: none;
  top: 18px;
  left: 0;
  width: 100%;
  overflow: hidden;
  height: 90px;
  max-height: ${(props) => (props.show ? "none" : "0")};
  padding: 0;
  border-radius: 8px;
  background-color: #222222;
  color: #fefefe;
`;
const Option = styled.li`
  font-size: 14px;
  padding: 6px 8px;
  transition: background-color 0.2s ease-in;
  &:hover {
    background-color: #595959;
  }
`;
  
  

💎 기능 만들기

마지막으로 hooks 중 useState를 사용하여 select에 아래와 같은 기능을 만들어주려고 합니다.

  • select 선택시, option이 나타나게 하기
  • 선택된 option으로 현재값을 변경하기

1. select 선택시, option이 나타나게 하기

select의 options들의 visible 여부를 useState를 이용하여 설정할 거에요! 먼저, <SelectBox/>이 눌릴 때마다 isShowOptions의 상태를 변경할 수 있도록 설정해주세요!

그리고 만들어준 <SelectOptions/>show라는 이름의 props를 설정하여 줍니다.

const CustomSelect = () => {
  const [isShowOptions, setShowOptions] = useState(false);

  return (
    <SelectBox onClick={() => setShowOptions((prev) => !prev)}>
      <Label>CurrentValue</Label>
      <SelectOptions show={isShowOptions}>
        <Option>option1</Option>
        <Option>option2</Option>
        <Option>option3</Option>
      </SelectOptions>
    </SelectBox>
  );
};

그리고 <SelectOptions/>가 props에 상태에 따라 다르게 보일 수 있도록 max-height: ${(props) => (props.show ? "none" : "0")};을 추가하여 줍니다.

그래서 isShowOptionstrue라면 max-height 설정이 없어지면서 설정된 height이 적용이 됩니다. 반대로 false일 경우에는 max-height0이 되어 SelectOptions이 보이지 않게 됩니다.


2. 선택된 option으로 현재값을 변경하기
마지막으로 선택된 값으로 변경되도록 구현을 해볼게요.useState를 사용하여 초기값을 지정하여주고, <Option/>이 클릭될 때마다 currentValue를 바꾸어주도록 함수를 만들어서 설정해주었습니다.

const CustomSelect = () => {
  const [currentValue, setCurrentValue] = useState("1학년");
  const [showOptions, setShowOptions] = useState(false);

  const handleOnChangeSelectValue = (e) => {
    const { innerText } = e.target;
    setCurrentValue(innerText);
  };

  return (
    <SelectBox onClick={() => setShowOptions((prev) => !prev)}>
      <Label>{currentValue}</Label>
      <SelectOptions show={showOptions}>
        <Option onClick={handleOnChangeSelectValue}>1학년</Option>
        <Option onClick={handleOnChangeSelectValue}>2학년</Option>
        <Option onClick={handleOnChangeSelectValue}>3학년</Option>
        <Option onClick={handleOnChangeSelectValue}>4학년</Option>
      </SelectOptions>
    </SelectBox>
  );
};

💎 CustomSelect 완성하기

페이지에 여러개의 select가 있을 경우 혹은 options이 많아질 경우, 위의 방법으로 만들어준 <CustomSelect/>는 재사용에 어려움이 있는데요! 이를 해결하기 위해서 아래와 같이 수정할 수 있어요!

OptionsData를 <CustomSelect/>의 props로 받아와서 적용해줌으로써 만들어준 컴포넌트를 재사용할 수 있고, options의 요소들이 많아진다해도 map함수를 통하여 해결할 수 있습니다!


const CustomSelect = (optionData) => {
  const [currentValue, setCurrentValue] = useState(Grade[0].value);
  const [showOptions, setShowOptions] = useState(false);

  const handleOnChangeSelectValue = (e) => {
	setCurrentValue(e.target.getAttribute("value"));
  };

  return (
    <SelectBox onClick={() => setShowOptions((prev) => !prev)}>
      <Label>{currentValue}</Label>
      <SelectOptions show={showOptions}>
        {optionData.map((data) => (
          <Option
            key={data.key}
            value={data.value}
            onClick={handleOnChangeSelectValue}
          >
            {data.value}
          </Option>
        ))}
      </SelectOptions>
    </SelectBox>
  );
};

💎 느낀점

직접 select를 만들어보기전에는 어떻게 동작하고 있는지에 대해선 따로 고민해본 적이 없던 것 같아요! 이렇게 프로젝트를 통해 새롭게 만들어보면서 어떤 구조로 이루어져 있는지 어떻게 동작하는지에 대해 이해하고 정리해볼 수 있는 시간이 되었습니다.

profile
개발 기록💻

1개의 댓글

comment-user-thumbnail
2023년 3월 13일

너무 도움이 되었습니다!!! 감사합니다!

답글 달기