오늘은 흔히 dropdown
을 만들어보았습니다. 하지만 dropdown
뿐만이 아니라 유사한 다른 컴포넌트도 구현할 수 있는 재사용성 높은 컴포넌트를 목표로 Selection
이라는 컴포넌트를 만들어 보았습니다.
토스 컨퍼런스 동영상에서 따온 이미지 입니다. 여기는 출처
그림을 보면 왼쪽사진과 오른쪽사진에서 1번 컴포넌트에서 선택한 결과 값이 2번 컴포넌트에 나타나는 공통점을 찾아볼 수 있습니다. 그럼 compound component
의 장점인 내부 컴포넌트를 자유로이 배치할 수 있다는 점을 이용하여 구현 할 수 있을 것 같습니다.
const Selection = () => {
return <SelecionContext.Provider>{children}</SelectionConText.Provider>
}
const OptionList = () => {
return <div>{children}</div>
}
const OptionItem = ({value}) => {
return <div>{value}</div>
}
const Trigger = () => { // 선택된 옵션 아이템에 따른 버튼
return <button>버튼</button>
}
const Content = () => { // 선택된 옵션 아이템에 따른 화면
return <div>{content}</div>
}
// app.js
const App = () => {
return (
<Selection>
<Selection.Trigger />
<Selection.OptionList>
<Selection.OptionItem value={1}/>
<Selection.OptionItem value={2}/>
<Selection.OptionItem value={3}/>
</Selection.OptionList>
</Selection>
)
}
하지만 Selection
에 적절하게 props
를 주어서 적절한 css
가 적용될 수 있도록 하는 작업이 어느정도 필요합니다.
부록
드랍다운에는
OptionList
이외의 element를 클릭하면 드랍다운이 꺼지게끔 설계해야 합니다.
하지만Trigger
가 드랍다운을 켜고 끄는 버튼이라 드랍다운이 켜져있는 상태에서Trigger
를 클릭하면 드랍다운이 켜졌다가 다시 꺼지는 에러가 생겨서 이를 해결해야 했습니다.해결방법
// index.tsx const Context = createContext({trigger : MutablRefObj<HTMLButtonElement | null>(null)} // 다음과 같이 Context를 만들고 // Trigger.tsx const Trigger = () => { const { trigger } = useContext() return <button ref={trigger}>버튼</button> } // OptionList.tsx const OptionList = () => { const { trigger } = useContext() useClickAway(listRef, (event) => { trigger.current !== event.target && close() }) return <div ref={listRef}>{childrent}<div> }
Trigger element
를 저장한 RefObj를OptionList
에 가지고 와서Trigger
와OptionList
가 포함되지 않은 element를 클릭 할때 드랍 다운이 닫히게 끔 구현하였습니다.