React 컴포넌트에서 UI 로직 분리하기

April 26, 2021

이 포스트는 https://javascript.plainenglish.io/decoupling-logic-from-ui-create-react-components-like-a-boss-7ebde91671c8 를 번역하였습니다. 논리 로직과 UI를 분리하면 컴포넌트를 더 쉽게 작성하고 테스트 할 수 있습니다.

이 포스트의 주 목적은 각 컴포넌트가 데이터, 오류처리, 로드 및 기타 필요한 논리에만 관심을 갖는 방식으로 새롭게 컴포넌트를 작성하도록 하는 것입니다.

중요한 이유

  • 확장성: 실제로 컴포넌트에 대한 확장성이 뛰어납니다.
  • 제거 가능성: 컴포넌트 삭제가 문제되지 않아야 하며, 주요 변경이나 회귀가 발생하지 않습니다.
  • 이동성: 어디서나 동일한 API를 사용하는 프로젝트 간에 컴포넌트를 사용할 수 있습니다.

Hands-On

코드를 자세히 살펴보고, 리팩토링 전후의 2가지 예를 보여 드리겠습니다.

import React, { useMemo } from 'react';
import useAxios from 'axios-hooks';

const TodoList = () => {
  const [{ data, loading, error }] = useAxios( `/`);

  const todoItems = useMemo(
    () => (data ? data.filter((item) => item.status === 'TODO') : []),
    [data],
  );

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error</div>;
  return <div>{JSON.stringify(todoItems)}</div>;
};

export default TodoList;

위에서 볼 수 있듯이, axios를 사용하여 원격 API 구성을 통해 데이터를 요청하여 To-Do 목록을 구현하는 간단한 예제가 있습니다.

상태 = ToDo인 항목을 추출하는 간단한 계산을 할 수 있나요? 대답이 '예!' 라면 같은 페이지에 있다고 할 수 있습니다.

포스트 시작부분에서 설명 한 것처럼 우리의 임무는 UI 에서 논리를 분리하는 것이지만, 위 예에서는 동일한 JS 파일에 논리가 있으므로 임무를 달성하기 위해 수행해야 하는 작업을 살펴 보겠습니다.

import { useMemo } from 'react';
import useAxios from 'axios-hooks';

const useTodoList = () => {
  const [{ data, loading, error }] = useAxios( `/`);

  const todoItems = useMemo(
    () => (data ? data.filter((item) => item.status === 'TODO') : []),
    [data],
  );

  return [{ data, loading, error, todoItems }];
};

export default useTodoList;

보시다 시피, useTodoList 라고 불렀습니다. 이 Hook은 TodoList 컴포넌트의 로직을 포함해야 합니다. 파일에 UI가 없다는 것을 알 수 있는데, 이는 사용자가 지정한 커스텀 훅 (Custom Hook) 입니다.

import React from 'react';

import useTodoList from './useTodoList';

const TodoList = () => {
  const [{ data, loading, error, todoItems }] = useTodoList();

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error</div>;
  return <div>{JSON.stringify(todoItems)}</div>;
};

export default TodoList;

그리고, 컴포넌트 상에서는 다음과 같이 사용하면 됩니다!

...