
이전 게시글에서 다뤘듯이, 디자인 패턴이란 소프트웨어를 개발하는 과정에서의 설계 패턴을 정의한 것이다.
프론트엔드에서도 시대가 흐르면서, 복잡한 화면 작업, React, Vue 등의 프레임워크의 도입으로
새로운 패턴 형성 및 기존 패턴의 구체적 구조화가 필요해졌다.
특히, 이러한 과정에서 어떻게 컴포넌트를 구성/활용할 것인가에 대한 고민이 깊어지고 이것이 발전해 React 디자인 패턴이 되었다.
React 디자인 패턴은
에 초점을 둔다.
이를 통해
을 이뤄낸다.
Container와 데이터를 출력하는 Presentation을 분리해 구현Presentation 컴포넌트의 재사용 가능hooks 도입 이후, 로직 분리가 이전 대비 쉬워지며 추천하지 않는 패턴이 됨즉, UI만을 구성하는 jsx와 로직을 핸들링하는 jsx를 따로 구성한다.
import {useState, useEffect} from 'react';
// Custom Hook 정의
const useFetch = (url) => {
	const [data, setData] = useState(null);
  
  	useEffect(() => {
    	fetch(url)
      		.then((res) => res.json())
      		.then((data) => {
				setData(data);
			});
	}, [url]);
  	
  	return {data}
}
// 컴포넌트에서 사용
export default function App() {
	const {data} = useFetch(`...`);
    ...
}
Presentation 로직과 Business 로직을 명확히 구분import React from 'react';
// HOC 함수 정의
const withLogger = (WrappedComponent) => {
	return function EnhancedComponent(props) {
    	return <WrappedComponent {...props} />;
    }
}
// 일반 컴포넌트
const NormalComponent = ({name}) => {
	return <h2>HI {name}!</h2>;
}
// HOC 사용 컴포넌트
const HOCLogger = withLogger(NormalComponent);
// 활용
export default function App() {
	return <HOCLogger name = "Minsu" />;
}
구조
Button, Input, Lable ... )LoginInput, LoginToggle 등)LoginComponent 등)Header + Title + LoginComponent = LoginTemplate)Props Drilling발생 가능@media, MediaQuery등 반응형  UI 구축에 어려움state)와 컨텍스트(Context) 공유import React, { createContext, useContext, useState } from 'react';
const TabsContext = createContext();
const Tabs = ({children}) => {
	const [activeIdx, setActiveIdx] = useState(0);
  return(
  	<TabsContext.Provider value={{activeIdx, setActiveIdx}}>
    	{children}
	</TabsContext.Provider>
  );
}
const TabList = ({ children }) => {
  return <div>{children}</div>;
}
const Tab = ({ idx, children }) => {
  const { activeIdx, setActiveIdx } = useContext(TabsContext);
  return (
    <button
      onClick={() => setActiveIdx(idx)}
      style={{ fontWeight: activeIdx === idx ? 'bold' : 'normal' }}
    >
      {children}
    </button>
  );
}
export default function App() {
  return (
    <Tabs>
      <TabList>
        <Tab index={0}>Tab 1</Tab>
        <Tab index={1}>Tab 2</Tab>
      </TabList>
    </Tabs>
  );
}
props로 전달해, 컴포넌트 내부에서 원하는 대로 렌더링할 수 있게 해줌Props로 제공된 함수에 위임하여 재사용성, 유연성 제공Presentation과 Business 로직을 분리 구성React와 Props에 대한 깊은 이해 필요Counter.jsx : Render Props 구현import React, { useState } from 'react';
export const Counter = ({render}) => {
  const [count, setCount] = useState(0);
  const increment = () => setCount(count + 1);
  const decrement = () => setCount(count - 1);
  return (
    <div>
      {render({ count, increment, decrement })}
    </div>
  );
}
App.jsx : 사용...
import Counter from './Counter';
export default const App = () => {
  return (
    <div>
      <h1>Render Props Example</h1>
      
      {/* 첫 번째 예시: 기본 카운터 */}
      <Counter
        render={({ count, increment, decrement }) => (
          <div>
            <h2>Basic Counter</h2>
            <p>Count: {count}</p>
            <button onClick={increment}>Increment</button>
            <button onClick={decrement}>Decrement</button>
          </div>
        )}
      />
      <hr />
      {/* 두 번째 예시: 스타일이 다른 카운터 */}
      <Counter
        render={({ count, increment, decrement }) => (
          <div>
            <h2>Styled Counter</h2>
            <p style={{ fontWeight: 'bold' }}>Count: {count}</p>
            <button onClick={increment}>➕ Add</button>
            <button onClick={decrement}>➖ Subtract</button>
          </div>
        )}
      />
    </div>
  );
}
props를 통해서만 제어, 스스로의 상태를 관리하거나 변경하지 않음(stateless)Presentation 컴포넌트, UI 렌더링btnClick 등)View - Action 연결MVC 패턴과 유사Props로만 데이터 흐름을 제어하기 때문에 Props Drilling을 야기할 수 있고, 코드가 복잡해질 수 있음단순히 이러한 디자인 패턴을 인지하는 것을 넘어,
직면한 프로젝트에 어떤 패턴이 알맞을 지를 고민하는 것이 중요하다.
예를 들어, UI의 높은 재사용성과 일관된 디자인을 위해 Atomic Design을 도입하자! 라고 할 때, props관리의 복잡성을 당연히 먼저 고려해야 한다는 것이다.
따라서 필요시엔 여러 디자인 패턴을 효율적으로 함께 사용하고,
환경에 맞는 규칙을 새롭게 만들어 적용해야한다.
또한 당연하게도 어떤 디자인 패턴을 적용하느냐에 따라
파일 구조 및 테스팅 적용이 달라지기 때문에 패키지 구조 설정 단계 ~ 테스트 단계까지 높은 관심과 고민이 필요하다.
[참고자료]