리액트 프로젝트를 진행하면서 기본적으로 제공되는 요소들을 커스텀해야할 때가 많이 있는데요!
오늘은 SELECT 를 직접 커스텀하여 제작하는 방법을 정리하려고 합니다!
** 저는 styled-component
를 사용해서 꾸며주었어요!
저는 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")};
을 추가하여 줍니다.
그래서 isShowOptions
이 true
라면 max-height
설정이 없어지면서 설정된 height
이 적용이 됩니다. 반대로 false
일 경우에는 max-height
이 0이 되어 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>
);
};
페이지에 여러개의 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를 만들어보기전에는 어떻게 동작하고 있는지에 대해선 따로 고민해본 적이 없던 것 같아요! 이렇게 프로젝트를 통해 새롭게 만들어보면서 어떤 구조로 이루어져 있는지 어떻게 동작하는지에 대해 이해하고 정리해볼 수 있는 시간이 되었습니다.
너무 도움이 되었습니다!!! 감사합니다!