const SelectBox = ({ options }) => {
const [selectedItem, setSelectedItem] = useState<string | null>(null);
const [open, setOpen] = useState(false);
const toggleOpen = () => {
setOpen((prev) => !prev);
};
const select = (e: MouseEvent<HTMLDivElement>) => {
const target = e.target as HTMLDivElement;
setSelectedItem(target.textContent);
toggleOpen();
};
return (
<section>
<button>{selectedItem ?? "open me!"}</button>
{open && (
<section>
{options.map((option, idx) => {
return (
<div
key={idx}
onClick={select}
className={`optionItem ${
selectedItem === option && "selected"
}`}
>
{option}
</div>
);
})}
</section>
)}
</section>
);
};
export default SelectBox;
const App = () => {
const options = ["red","black","blue"]
return <SelectBox options={options}/>
}
const App = () => {
const options = ["red","black","blue"]
const triggerLabel = "열어주세요!"
return <SelectBox options={options} triggerLabel={triggerLabel} />
}
const App = () => {
const options = ["red","black","blue"]
const triggerLabel = "열어주세요!"
return <SelectBox options={options} triggerLabel={triggerLabel} buttonPosition="bottom" />
}
const App = () => {
const options = ["red","black","blue"]
const triggerLabel = "열어주세요!"
return (
<Select>
<Select.Trigger triggerLabel={triggerLabel} />
<section>
{options.map(item => {
return <Select.Option optionItem={item} />
})}
<section>
</Select>
)
}
const App = () => {
const options = ["red","black","blue"]
const [selectedItem, setSelectedItem] = useState<string|null>(null)
const [open, setOpen] = useState(false);
const toggleBox = () => {
setOpen((prev) => !prev);
};
const select = (e: MouseEvent<HTMLDivElement>) => {
const target = e.target as HTMLDivElement;
setSelectedItem(target.textContent);
toggleBox();
};
return (
<ControlledSelect
options={options}
selectedItem={selectedItem}
open={open}
select={select}
toggleBox={toggleBox}
>
)
}
const App = () => {
const options = ["red","black","blue"]
const { selectedItem, open, toggleBox, select } = useSelect();
function alertSelectItem(target: string){
alert(`${target}을 선택했습니다.`)
}
function handleClick(e: MouseEvent<HTMLDiveElement>){
const target = e.target as HTMLDivElement;
if (target.textContext === null) return;
select(e);
alertSelectItem(target.textContext);
}
return (
<ControlledSelect
options={options}
selectedItem={selectedItem}
open={open}
handleClick={handleClick}
toggleBox={toggleBox}
>
)
}
const App = () => {
const options = ["red","black","blue"]
const { open, getToggleProps, getSelectProps } = useGetterSelect();
function alertButton(){
alert("이거 눌러도 닫히지롱!")
}
return (
<PropsGetteredSelect>
<button {...getToggleProps({ onClick: alertButton })}>
strange button
<button>
<PropsGetteredSelect.Trigger {...getToggleProps()} />
{open && (
<section className="selectContainer">
{options.map(item => {
return <PropsGetteredSelect.Option {...getSelectProps()} />
})}
<section>
)}
</PropsGetteredSelect>
)
}
const getToggleProps = ({ onClick, ...otherProps }): any = {}) => ({
onClick: callFnsInSquence(toggleBox, onClick),
open,
...otherProps,
})
const getSelectProps = ({ onClick, ...otherProps }): any = {}) => ({
onClick: callFnsInSquence(select, onClick),
selectedItem,
...otherProps,
})
저번 글에서 다뤘던 합성 컴포넌트 패턴과 이어지는 부분이 많은 영상이라 이해하기 쉬웠습니다. 기존에 정의되어 있는 기능이 아니라 추가적인 기능을 구현하고 싶을 때 어떻게 할 것인지를 설명하는 부분이 상당히 인상적인데요. 하지만 props 자체를 반환하는 것이 아니라 getter 함수를 반환함으로써 로직을 추가하는 걸 더 편하게 만든 것은 고민이 되는 부분 같습니다. 커스텀 훅의 메인 로직이 겉에서 들어나지 않는다는 부분이 저번 토스 컨퍼런스에서 배웠던 커스텀 훅의 안티 패턴과 비슷하게 느껴지기 때문인데요. 지나친 추상화는 오히려 독이된다는 데 주니어인 제 입장에서는 판단하기가 쉽지 않네요..