이 패턴은 불필요한 prop drilling 없이 Expressive(표현적 풍부한) 하고 Declarative(선언적)한 컴포넌트를 만들 수 있게 도와줍니다. 만약 좀 더 customizable(사용자 정의화) 하고 관심사를 분리하도록 하고 싶다면 이 패턴을 고려해보아야 합니다.
import React from "react";
import { Counter } from "./Counter";
function Usage() {
const handleChangeCounter = (count) => {
console.log("count", count);
};
return (
<Counter onChange={handleChangeCounter}>
<Counter.Decrement icon="minus" />
<Counter.Label>Counter</Counter.Label>
<Counter.Count max={10} />
<Counter.Increment icon="plus" />
</Counter>
);
}
export { Usage };
API 복잡도가 낮다.
하나의 거대한 부모 컴포넌트에 모든 props를 때려 넣고 자식 컴포넌트에 꽂아주는 방법보다 각각의 prop가 각각의 서브 컴포넌트에 붙어있는 방법이 더 좋다.
// 이렇게 쓰는 것보다
return (
<Counter
label="label"
max={10}
iconDecrement="minus"
iconIncrement="plus"
onChange={handleChangeCounter}
/>
);
// 이렇게 쓰는게 낫다!
return (
<Counter onChange={handleChangeCounter}>
<Counter.Decrement icon={"minus"} />
<Counter.Label>Counter</Counter.Label>
<Counter.Count max={10} />
<Counter.Increment icon={"plus"} />
</Counter>
);
유연한 마크업 구조
아래 해당 그림처럼 유연한 마크업 구조를 갖게 할 수 있다. 즉 컴포넌트가 엄청난 자유도를 갖는다.
관심사의 분리
대부분의 로직은 Counter Component에 포함되며, Context API를 통해 state와 handlers를 Children 컴포넌트간에 공유한다.
너무 UI 자유도가 크다.
이렇게 큰 자유도는 예상치 못한 행동을 유발할 수도 있다. 사용자 개발자가 어떻게 이 컴포넌트를 사용하는지에 의존한다면, 이렇게 큰 자유도를 주면 안된다.
JSX가 너무 무겁다.
이 패턴을 적용하게 되면 JSX의 길이를 너무 늘릴 수 있다. 특히 EsLint나 Prettier를 사용한다면 말이다.
이건 작은 컴포넌트에서는 큰 문제가 아닌 것처럼 보이지만 무거운 컴포넌트를 보게된다면 엄청난 차이를 느낄 수 있을 것이다.