재사용하기 쉬운 컴포넌트 (2)

엄강우·2022년 6월 16일
0

You don't know React

목록 보기
4/9

Selection 만들어 보기

오늘은 흔히 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에 가지고 와서 TriggerOptionList가 포함되지 않은 element를 클릭 할때 드랍 다운이 닫히게 끔 구현하였습니다.

profile
안녕하세요 프론트엔드 개발자를 꿈꾸는 엄강우입니다.

0개의 댓글