복합 구성요소 패턴(Compound Components Pattern) 이란?
프롭 드릴링(prop drilling) 없이 하나의 컴포넌트를 구성하는 State를 공유하도록 작성하는 컴포넌트 패턴이다. view를 구성하는 코드에 커스터마이징이 용이하다는 장점이 생긴다.
import React, { useState } from "react";
const Test = () => {
const [_value, _setValue] = useState("value2");
const optionChangeValue = (event) => {
_setValue(event.target.value);
};
return (
<div>
<h3>{_value}</h3>
<select value={_value} onChange={optionChangeValue}>
<option value="value1">Label1</option>
<option value="value2">Label2</option>
<option value="value3">Label3</option>
</select>
</div>
);
};
export default Test;
이처럼 서로 상태를 공유하며 내부적인 결합이 되어 있는 컴포넌트를 의미한다고 한다.
components
// components/count.jsx
import React from "react";
import { useCounterContext } from "../useCounterContext";
const Count = ({ max }) => {
const { count } = useCounterContext();
const MaximemCount = max <= count ? max : count;
return <div>{MaximemCount}</div>;
};
export { Count };
// components/button.jsx
import React from "react";
import { useCounterContext } from "../useCounterContext";
const Button = ({ value }) => {
const { handleDecrement, handleIncrement } = useCounterContext();
const isClickChange = value === "-" ? handleDecrement : handleIncrement;
return <button onClick={isClickChange}>{value}</button>;
};
export { Button };
// components/index.jsx
export * from "./button";
export * from "./count";
Counter.jsx
//Counter.jsx
import React, { useEffect, useRef, useState } from "react";
import { CounterProvider } from "./useCounterContext";
import { Button, Count } from "./components";
const Counter = ({ children, onChange, initialValue = 0 }) => {
const [count, setCount] = useState(initialValue);
const firstMounded = useRef(true);
useEffect(() => {
if (!firstMounded.current) {
onChange && onChange(count);
}
firstMounded.current = false;
}, [count, onChange]);
const handleIncrement = () => {
setCount(count + 1);
};
const handleDecrement = () => {
setCount(Math.max(0, count - 1));
};
const styles = {
display: "flex",
borderRadius: "0.25rem",
gap: "5px",
height: "20px",
alignItems: "center",
justifyContent: "center"
};
return (
<CounterProvider value={{ count, handleIncrement, handleDecrement }}>
<div style={styles}>{children}</div>
</CounterProvider>
);
}
Counter.Button = Button;
Counter.Count = Count;
export { Counter };
Usage.jsx
//Usage.jsx
import React from "react";
import { Counter } from "./Counter";
const Usage = () => {
const handleChangeCounter = (count) => {
console.log("count", count);
};
return (
<Counter onChange={handleChangeCounter}>
<p>Count</p>
<Counter.Count max={10} />
<Counter.Button value={"+"} />
<Counter.Button value={"-"} />
</Counter>
);
};
export default Usage;
컴포넌트 layout 변경
<Counter onChange={handleChangeCounter}>\\
<Counter.Button value={"+"} />
<p>Count</p>
<Counter.Count max={10} />
<Counter.Button value={"-"} />
</Counter>
장점
- 컴포넌트의 복잡도를 낮출 수 있고, 매우 직관적으로 사용이 쉽다.
하나의 컴포넌트 안에서 State를 공유하여 사용하는 형태로, 단순한 구조를 만들 수 있다.
- 컴포넌트의 각 역할마다 명확한 분리를 할 수 있어서 재 사용성이 높아 유지보수가 수월하다.
- 하위 컴포넌트의 위치나 정렬에 있어 커스터마이징을 할 수 있는 유연성을 가질 수 있다.
단점
[참고자료]
프롭 드릴링(prop drilling)
프로퍼티 내리꽂기(또는 나사 구멍 내기)는 리액트 의 컴포넌트 트리에서 데이터를 전달하기 위해,
상위 컴포넌트 에서 필요한 컴포넌트 로 값을 계속 내리는 것을 의미한다.
728x90
'STUDY > REACT' 카테고리의 다른 글
React useState Hook의 반환 값이 객체가 아닌 배열인 이유 (0) | 2023.07.04 |
---|---|
속성 제어 패턴 (Control Props Pattern) | 리액트 디자인 패턴 (0) | 2022.12.31 |
[Study] nextJS 입문 - 노마드코더 강의 정리 복습 (0) | 2022.11.29 |
[React] ReactHook (0) | 2022.11.25 |
[React] 컴포넌트 특징 (0) | 2022.11.25 |
댓글