React에는 여러 디자인 패턴들이 있습니다.
그 중 Custom Hook 패턴을 소개합니다.
React에서 Custom Hook 패턴의 대표적인 강점은 재사용성이 높다는것입니다. custom hook는 일반적으로 기능적인 역할을 수행하고, 다른 컴포넌트에서 사용할 수 있는 로직을 담고 있습니다. 이로써 중복 코드를 방지하고 코드의 재사용성을 높일 수 있습니다.
다음은 useCounter
의 Custom Hook 사용 예제입니다.
function Main() {
const { count, handleIncrement, handleDecrement } = useCounter(0);
return (
<>
<Counter value={count}>
<Counter.Decrement
icon={"minus"}
onClick={handleDecrement}
/>
<Counter.Label>Counter</Counter.Label>
<Counter.Count />
<Counter.Increment
icon={"plus"}
onClick={handleIncrement}
/>
</Counter>
</>
);
}
export default Main;
예제 코드를 확인해보면, custom hook useCounter
를 이용해 상태 변수와 상태 변경 함수를 제공하고 있고, 이를 Counter
컴포넌트의 하위 컴포넌트로 전달하는 모습을 볼 수 있습니다. Counter
컴포넌트는 그 안에 자식 요소들을 가지며, 해당 요소들에 필요한 상태나 이벤트 핸들러 등을 useCounter
커스텀 훅에서 제공받아 사용합니다.
function Counter({ children, value: count, onChange }) {
const firstMounded = useRef(true);
useEffect(() => {
if (!firstMounded.current) {
onChange && onChange(count);
}
firstMounded.current = false;
}, [count, onChange]);
return (
<CounterProvider value={{ count }}>
{children}
</CounterProvider>
);
}
Counter.Count = Count;
Counter.Label = Label;
Counter.Increment = Increment;
Counter.Decrement = Decrement;
export { Counter };
Counter 컴포넌트를 mount하게 되면 useEffect()
를 통해 여러 이벤트 처리합니다. 추가로 Counter.*
으로 자식 컴포넌트 요소를 매칭시켜 확장성을 높였습니다.
추가로, Counter에는 ConterProvider
가 사용 되었는데, 이는 context
를 통해 전역적으로 값을 받을 수 있습니다.
const CounterContext = React.createContext(undefined);
function CounterProvider({ children, value }) {
return (
<CounterContext.Provider value={value}>{children}</CounterContext.Provider>
);
}
function useCounterContext() {
const context = React.useContext(CounterContext);
if (context === undefined) {
throw new Error("useCounterContext must be used within a CounterProvider");
}
return context;
}
export { CounterProvider, useCounterContext };