본문 바로가기
Front-End/React

리액트 컴포넌트 패턴: 프레젠테이션 vs 컨테이너

by 두두리안 2024. 2. 19.
728x90

리액트 애플리케이션을 개발할 때, 컴포넌트를 어떻게 구성하고 관리할지에 대한 선택은 중요합니다. 이 글에서는 리액트 컴포넌트의 두 가지 주요 패턴인 "프레젠테이션 컴포넌트"와 "컨테이너 컴포넌트"에 대해 알아보겠습니다.

프레젠테이션 컴포넌트

프레젠테이션 컴포넌트는 주로 UI를 렌더링하는 데에 집중합니다. 이러한 컴포넌트는 데이터나 상태 관리보다는 UI 요소의 표현에 관심이 있습니다. 주로 함수형 컴포넌트로 작성되며, props를 통해 데이터를 받아들이고 UI를 렌더링합니다.

import UserItem from './UserItem'
import './UsersList.css'

const UsersList = (props) => {
  if (props.items.length === 0) {
    return (
      <div className="center">
        <h2>No users found.</h2>
      </div>
    )
  }

  return (
    <ul className="users-list">
      {props.items.map((user) => (
        <UserItem
          key={user.id}
          id={user.id}
          image={user.image}
          name={user.name}
          placeCount={user.places}
        />
      ))}
    </ul>
  )
}

export default UsersList
  • 이러한 컴포넌트는 보여지는 방식에 중점을 둡니다. 로직보다는 UI 표현에 관심이 있습니다.
  • props를 통해 데이터와 콜백을 받아들이고, 주로 UI 요소를 렌더링하는 데에 책임이 있습니다.
  • 프레젠테이션 컴포넌트는 주로 상태가 없는 함수형 컴포넌트이지만, 클래스 컴포넌트일 수도 있습니다.
  • 재사용 가능하며, 주로 버튼, 폼, 카드 등과 같은 일반적인 UI 요소를 나타냅니다.
  • UI 렌더링에만 관심이 있기 때문에 테스트 및 유지 관리가 쉬울 수 있습니다.

컨테이너 컴포넌트

컨테이너 컴포넌트는 주로 데이터 및 상태 관리, 로직 처리에 관심이 있습니다. 이러한 컴포넌트는 주로 클래스 컴포넌트로 작성되며, 상태(state)를 가지고 있고 라이프사이클 메서드를 사용하여 데이터를 가져오고 상태를 업데이트합니다. 또한 사용자의 액션 및 이벤트를 처리하고 애플리케이션의 상태를 관리합니다.

더미 데이터

import React from 'react'
import UsersList from '../components/UsersList'

const Users = () => {
  // API 데이터 가져오는 부분
  const USERS = [
    {
      id: 'u1',
      name: 'Max Schwarz',
      image:
        'https://images.pexels.com/photos/839011/pexels-photo-839011.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260',
      places: 3,
    },
  ]

  return <UsersList items={USERS} />
}

export default Users
  • 컨테이너 컴포넌트는 기능에 중점을 둡니다. 데이터 가져오기, 상태 관리 및 상호 작용 로직에 관심이 있습니다.
  • 주로 상태와 라이프사이클 메서드를 포함하는 클래스 컴포넌트입니다.
  • 컨테이너 컴포넌트는 API 또는 Redux 스토어에서 데이터를 가져와 프레젠테이션 컴포넌트에 props로 전달합니다.
  • 사용자의 액션과 이벤트(예: 폼 제출 또는 클릭)을 처리하고 애플리케이션의 상태를 관리합니다.
  • 프레젠테이션 컴포넌트보다 재사용성이 낮으며, 특정 데이터와 로직에 더 밀접하게 관련될 수 있습니다.

API 데이터 (async/await)

import React, { useState, useEffect } from 'react';
import UsersList from '../components/UsersList';

const Users = () => {
  // 사용자 데이터 상태 및 데이터 로딩 상태 설정
  const [users, setUsers] = useState([]);
  const [isLoading, setIsLoading] = useState(true);

  // useEffect를 사용하여 초기 데이터 로딩
  useEffect(() => {
    const fetchUsers = async () => {
      try {
        const response = await fetch('API 엔드포인트 URL');
        if (!response.ok) {
          throw new Error('데이터를 불러오는 데 실패했습니다.');
        }
        const data = await response.json();
        setUsers(data.users);
        setIsLoading(false);
      } catch (error) {
        console.error(error);
        setIsLoading(false);
      }
    };

    fetchUsers();
  }, []);

  return (
    <React.Fragment>
      {isLoading ? (
        <p>데이터를 불러오는 중입니다...</p>
      ) : (
        <UsersList items={users} />
      )}
    </React.Fragment>
  );
};

export default Users;
  • useState와 useEffect 훅을 사용하여 상태를 관리하고 데이터를 가져옵니다.
  • useState를 사용하여 사용자 데이터와 데이터 로딩 상태를 관리하고, useEffect를 사용하여 컴포넌트가 마운트될 때 한 번만 데이터를 가져옵니다.

API 데이터 (React Query)

import React from 'react';
import { useQuery } from 'react-query';
import UsersList from '../components/UsersList';

const Users = () => {
  // useQuery 훅을 사용하여 데이터 가져오기
  const { data: users, isLoading, isError } = useQuery('users', async () => {
    const response = await fetch('API 엔드포인트 URL');
    if (!response.ok) {
      throw new Error('데이터를 불러오는 데 실패했습니다.');
    }
    const data = await response.json();
    return data.users;
  });

  return (
    <React.Fragment>
      {isLoading ? (
        <p>데이터를 불러오는 중입니다...</p>
      ) : isError ? (
        <p>데이터를 불러오는 중에 오류가 발생했습니다.</p>
      ) : (
        <UsersList items={users} />
      )}
    </React.Fragment>
  );
};

export default Users;
  • React Query 라이브러리의 useQuery 훅을 사용하여 데이터를 가져옵니다.
  • useQuery를 사용하면 데이터 가져오기, 로딩 상태 및 오류 처리 등을 더 쉽게 관리할 수 있습니다. 또한 캐싱 및 재로딩과 같은 고급 기능도 제공합니다.

결론

프레젠테이션 컴포넌트와 컨테이너 컴포넌트는 리액트 애플리케이션의 구조화와 유지 관리에 큰 도움이 됩니다. UI 관련 작업은 프레젠테이션 컴포넌트에, 데이터 및 상태 관리는 컨테이너 컴포넌트에 위임함으로써 개발 생산성을 향상시킬 수 있습니다.

리액트 컴포넌트를 설계할 때, 프레젠테이션과 컨테이너의 적절한 분리를 고려하여 애플리케이션의 유연성과 확장성을 높일 수 있습니다.

728x90