[react] HOC으로 반복되는 로직 줄이기

Suyeon·2021년 2월 13일
3

React

목록 보기
22/26

A higher-order component (HOC) is an advanced technique in React for reusing component logic. HOCs are not part of the React API, per se. They are a pattern that emerges from React's compositional nature. Concretely, a higher-order component is a function that takes a component and returns a new component.

Problem

데이터를 fetch하게 되면, 주로 아래와 같은 패턴이 사용된다.

function List({ dataStatus }) {
  const { loading, error, data } = dataStatus;
  
  if(loading) return <p>Loading...</p>
  if(Error) return <p>Error occurs!</p>
  return data.map(d => <div>...</div>)
}

한개의 컴포넌트에서 데이터를 fetch한다면, 위와 같은 패턴을 사용하는 것이 문제가 없지만, 여러 컴포넌트에서 useFetch와 같은 커스텀훅을 사용해서 fetch를 한다면, 위의 패턴이 계속 반복된다. 우리는 알고있다. 반복되는 로직을 피해야한다는 것을!

그렇다면 어떻게 효율적으로 반복되는 로직을 줄일 수있을까? 🤓
➡️ HOC을 사용할 수 있다.

How to solve

HOC을 생성할때는 withSomething과 같은 이름을 사용한다.

WithLoading을 생성

function WithLoading(Component) {
  return function WihLoadingComponent({ dataObj, ...props }) {
    const { loading, error } = dataObj;

    if (loading) return <p>Loading...</p>;
    if (error) return <p>Error</p>;
    return <Component dataObj={dataObj} {...props} />;
  };
}
export default WithLoading;

컴포넌트를 HOC으로 래핑

import List1 from 'components/List1';
import List2 from 'components/List2';

const List1WithLoading = WithLoading(List1);
const List2WithLoading = WithLoading(List2);

function App() {
  useFetch(ACTIVE_STATUS, 'activeStatus');
  useFetch(INFORMATICS, 'informatics');
  
  return(
      <div>
        <List1WithLoading dataObj={data1} title="Informatics" />
        <List2WithLoading dataObj={data2} title="Active Status" />
      </div>
  )
}

위와 같이 useFetch를 반복적으로 사용하고 싶지 않다면, HOC안에 url을 파라미터로 받아서 데이터를 fetch하는 로직을 작성할 수 있다.

withFetch

const withFetch = (WrappedComponent, url) => {
  const [data, setData] = useState([]);
  
  const handleFetch = useCallback(async() => {
    try {
      const res = await fetch(url);
      setData(res.data);
    } catch(error) {
      console.log(error)  
      }
  });
  
  useEffect(() => {
    handleFetch();
  }, [])
 
  return <WrappedComponent data={data}/>
}

export default withFetch;

컴포넌트를 HOC으로 래핑

function List() {
// ...
}
export default withFetch(List, "http://example.com")

Typescript 적용하기

참고 포스팅

import React, { ComponentType } from 'react';
import { Placeholder } from 'styles/styles';
import { DataState } from 'types/types';

interface WithLoadingProps {
  dataObj: DataState;
}

function WithLoading<P extends object>(
  Component: ComponentType<P>
): React.FC<P & WithLoadingProps> {
  return function WihLoadingComponent({ dataObj, ...props }: WithLoadingProps) {
    const { loading, error } = dataObj;

    if (loading) return <Placeholder>Loading...</Placeholder>;
    if (error) return <Placeholder>Error</Placeholder>;
    return <Component dataObj={dataObj} {...(props as P)} />;
  };
}

export default WithLoading;
profile
Hello World.

0개의 댓글