본문 바로가기
React

React에서 컴포넌트의 재사용성을 높이는 방법

by 굿센스굿 2024. 12. 11.
반응형

 

React는 컴포넌트 기반 구조를 활용하여 개발 생산성을 극대화할 수 있는 프레임워크입니다. 하지만 단순히 컴포넌트를 작성하는 것만으로는 충분하지 않습니다. 유지보수성과 재사용성이 높은 컴포넌트를 작성하려면 특정한 원칙과 패턴을 이해하고 적용해야 합니다. 이 글에서는 React 컴포넌트의 재사용성을 높이는 다양한 방법과 실제 예제를 통해 이를 구현하는 방법을 살펴보겠습니다.


1. 재사용 가능한 컴포넌트를 작성하는 기본 원칙

1-1. 단일 책임 원칙(Single Responsibility Principle)

컴포넌트는 단일 책임 원칙을 따라야 합니다. 즉, 하나의 컴포넌트는 하나의 명확한 기능만 수행해야 합니다. 이렇게 하면 컴포넌트를 테스트하거나 재사용할 때 더 쉽게 관리할 수 있습니다.

예시:

// Bad Example
function UserProfile({ user }) {
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
      <button onClick={user.logout}>Logout</button>
    </div>
  );
}

// Good Example
function UserInfo({ name, email }) {
  return (
    <div>
      <h1>{name}</h1>
      <p>{email}</p>
    </div>
  );
}

function LogoutButton({ onLogout }) {
  return <button onClick={onLogout}>Logout</button>;
}

function UserProfile({ user, onLogout }) {
  return (
    <div>
      <UserInfo name={user.name} email={user.email} />
      <LogoutButton onLogout={onLogout} />
    </div>
  );
}

1-2. Props와 State 분리

Props는 컴포넌트 간 데이터를 전달하는 데 사용하고, State는 내부 상태를 관리하는 데 사용해야 합니다. 두 개념을 명확히 분리하면 컴포넌트를 더 효율적으로 재사용할 수 있습니다.

예시:

function Counter({ initialCount }) {
  const [count, setCount] = React.useState(initialCount);

  const increment = () => setCount(count + 1);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

2. 고차 컴포넌트(Higher-Order Components, HOC)

HOC는 컴포넌트를 인수로 받아 새 컴포넌트를 반환하는 함수입니다. 이를 통해 공통 로직을 추출하여 재사용성을 높일 수 있습니다.

예시:

function withLoading(Component) {
  return function WithLoadingComponent({ isLoading, ...props }) {
    if (isLoading) return <p>Loading...</p>;
    return <Component {...props} />;
  };
}

function UserList({ users }) {
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

const UserListWithLoading = withLoading(UserList);

3. Render Props

Render Props 패턴은 컴포넌트의 자식으로 함수를 전달하여 재사용 가능한 로직을 구현하는 방법입니다.

예시:

function DataFetcher({ fetchData, children }) {
  const [data, setData] = React.useState(null);

  React.useEffect(() => {
    fetchData().then(response => setData(response));
  }, [fetchData]);

  return children(data);
}

function UserList() {
  const fetchUsers = () => fetch('/api/users').then(res => res.json());

  return (
    <DataFetcher fetchData={fetchUsers}>
      {users => (
        <ul>
          {users ? users.map(user => <li key={user.id}>{user.name}</li>) : 'Loading...'}
        </ul>
      )}
    </DataFetcher>
  );
}

4. Custom Hooks

Custom Hooks를 활용하면 상태와 로직을 분리하여 재사용성을 높일 수 있습니다. React Hooks는 함수형 컴포넌트에서 로직을 재사용할 수 있는 강력한 도구입니다.

예시:

function useFetchData(url) {
  const [data, setData] = React.useState(null);
  const [loading, setLoading] = React.useState(true);

  React.useEffect(() => {
    fetch(url)
      .then(response => response.json())
      .then(result => {
        setData(result);
        setLoading(false);
      });
  }, [url]);

  return { data, loading };
}

function UserList() {
  const { data: users, loading } = useFetchData('/api/users');

  if (loading) return <p>Loading...</p>;
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

5. Context API 활용

Context API를 사용하면 컴포넌트 계층 구조를 통해 데이터를 전달할 때 발생하는 "Prop Drilling" 문제를 해결하고, 상태를 전역적으로 공유할 수 있습니다.

예시:

const ThemeContext = React.createContext();

function ThemeProvider({ children }) {
  const [theme, setTheme] = React.useState('light');

  const toggleTheme = () => {
    setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

function ThemedButton() {
  const { theme, toggleTheme } = React.useContext(ThemeContext);

  return (
    <button style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#000' : '#fff' }}
      onClick={toggleTheme}>
      Toggle Theme
    </button>
  );
}

function App() {
  return (
    <ThemeProvider>
      <ThemedButton />
    </ThemeProvider>
  );
}

결론

React에서 컴포넌트의 재사용성을 높이기 위해서는 컴포넌트의 구조를 잘 설계하고, 다양한 패턴과 도구를 활용하는 것이 중요합니다. 단일 책임 원칙, HOC, Render Props, Custom Hooks, Context API 등 다양한 접근 방식을 활용하여 유지보수성과 생산성을 동시에 향상시킬 수 있습니다. 이러한 방법을 실무에 적용하여 더 나은 React 애플리케이션을 만들어 보세요!

반응형