React Compound Component Pattern 을 이용해서 Masonry UI 만들기 [1]

Jaewoong2·2022년 7월 23일
1

Compound Component Pattern

장점
- 재사용성이 좋다
- 직관적인 Component 를 사용한다

단점
- 유연성이 너무 높아, 예기치 않은 오류를 발생 할 수 있다.
- 코드의 양이 많다
- 추상화 단계가 낮아, 해당 방법으로 설계를 안해도 될 경우가 생긴다

들어가기전에,

먼저 버튼을 누르면 숫자가 올라가는 버튼을 만들고 다른 컴포넌트에서 사용 한다고 하였을 때,

<IncreaseButton />

처럼 불러와 사용하게 된다면, 버튼의 스타일과 얼마나 많이 숫자를 증가 시킬지를 고려하기 어려울 것 입니다.

이에 따라 개발자들은

<IncreaseButton 
  size="sm"
  type="primary"
  step={2}
  />

Props 를 통해 재사용성을 높일 수 있습니다. 이렇게 된다면, 스타일을 변경시키며 로직을 변경 시킬 수 있습니다. 하지만, 해당 Props 방법은 컴포넌트를 구현 한 사람이 의도한 대로 반영 되기 때문에, 재활용성이 떨어질 수 있습니다.

또한, Props을 통해서 컴포넌트 사용자가 유연하게 사용 할 수 있으면, 컴포넌트 내의 로직이 복잡하게 될 가능성이 있습니다.

- 거대한 컴포넌트 안의 개별 컴포넌트들에 각각 접근 가능
- 각 컴포넌트들의 UI요소 변경 (마크업 구조를 사용자가 변경 할 수 있게)

를 할 수 있게 된다면, 컴포넌트를 조금더 유연하게 사용 할 수 있을 것 입니다.

버튼을 만들며 Compound Component 설계 하기

CounterButton 구현하기

const CounterButtonContext = createContext(defaultValue)

const CounterButton = ({ children }) => {
  	const [count, setCount] = useState(0)
  
  
  	const value = {
    	count,
      	increase: (step) => setCount(prev => prev + step),
      	decrease: (step) => setCount(prev => prev - step)
    }
  
	return (
    	<CounterButtonContext.Provider value={value}>
        	{children}
    	</CounterButtonContext.Provider>
    )
}

const IncreaseButton = ({ step, children }) => {
	const { increase, count } = useContext(CounterButtonContext)
    
    return <button onClick={() => increase(step)}>{children}</button>
}

const DecreaseButton = ({ step, children }) => {
	const { decrease, count } = useContext(CounterButtonContext)
    
    return <button onClick={() => decrease(step)}>{children}</button>
}

const Count = () => {
	const { count } = useContext(CounterButtonContext)
  
	return count
}

CounterButton.Increase = IncreaseButton
CounterButton.Decrease = DecreaseButton
CounterButton.Count = Count

CounterButton 사용하기

import CounterButton from 'component/CounterButton'

const App = () => {
  
	return (
      <CounterButton>
      	<CounterButton.Increase step={2}>증가</CounterButton.Increase>
      	<CounterButton.Decrease step={1}>감소</CounterButton.Decrease>
      	<CounterButton.Count />
      </CounterButton>
    )
}

해당 컴포넌트의 결과는
증가 버튼 감소 버튼 이 붙어 있고 바로 옆에 Count 값 이 보여지게 된다

import CounterButton from 'component/CounterButton'

const App = () => {
  
	return (
      <CounterButton>
      	<CounterButton.Increase step={2}>증가</CounterButton.Increase>
      	<CounterButton.Count />
        <CounterButton.Decrease step={1}>감소</CounterButton.Decrease>
      </CounterButton>
    )
}

해당 컴포넌트의 결과는
증가 버튼 Count 값 이 붙어 있고 바로 옆에 감소 버튼 이 보여지게 된다.

결론

즉, CounterButton의 하위 컴포넌트는
증가버튼, 감소버튼, count 값을 보여주는 컴포넌트 이렇게 있고, 이를 사용하는 개발자는 이 3가지에 대해서 더욱 재활용을 하고 더욱 직관적인 이름을 가지고 있는 컴포넌트를 사용 할 수 있게 된다.

profile
DFF (Development For Fun)

0개의 댓글