프론트엔드 비즈니스 로직 분리 - boostcampwm-2022/web30-TODY GitHub Wiki

프론트엔드 비즈니스 로직 분리

💡 프론트엔드에서 비동기 API 요청, 입력 유효성 검증과 같은 비즈니스 로직을 분리하고 효율적으로 관리하기 위해 React Custom Hooks를 사용했습니다.

목표

  • 컴포넌트의 UI 로직과 비즈니스 로직을 분리한다.
  • API 호출, 입력 유효성 검증과 같은 반복되는 비즈니스 로직을 분리하여 재사용성을 높인다.

방법

  • 리액트 커스텀 훅 사용

성과

  • 공부방 페이지 컴포넌트의 UI 로직과 비즈니스 로직 분리를 위해 커스텀 훅을 만들어 적용했다. ( 공부방 페이지 컴포넌트 내부 코드 : 436줄 → 91줄)

    • useSfu
      • WebRTC SFU방식 연결을 위한 로직
    • useStudyRoomPage
      • 공부방 정보, 하단바, 사이드바 활성 상태 로직
  • 반복되는 비즈니스 로직의 재사용성을 위해 커스텀 훅을 만들어 적용했다.

    • useAxios<T>
      • 코드로 살펴보기

        import axios, { AxiosPromise } from 'axios';
        import { useCallback, useEffect, useState } from 'react';
        import { useNavigate } from 'react-router-dom';
        
        export default function useAxios<T>(
          axiosFunction: (arg?: any) => AxiosPromise<T>,
          options?: { onMount?: boolean; arg?: any; errNavigate?: boolean },
        ): [
          (arg?: any) => Promise<void>,
          boolean,
          {
            statusCode: number | undefined;
            message: any;
            error: string;
          } | null,
          T | null,
        ] {
          const onMount = options?.onMount || false;
          const argument = options?.arg || undefined;
          const errNavigate = options?.errNavigate ?? true;
          const [loading, setLoading] = useState<boolean>(onMount);
          const [error, setError] = useState<{
            statusCode: number | undefined;
            message: any;
            error: string;
          } | null>(null);
          const [data, setData] = useState<T | null>(null);
          const navigate = useNavigate();
        
          useEffect(() => {
            if (!error) return;
            if (errNavigate) navigate('/error', { state: error });
          }, [error]);
        
          const request = useCallback(
            async (arg?: any) => {
              setLoading(true);
              setError(null);
              setData(null);
              try {
                const response = await axiosFunction(arg);
                setData(response.data);
              } catch (err) {
                if (axios.isAxiosError(err)) {
                  if (err.response) {
                    setError(err.response.data);
                  } else {
                    setError({
                      statusCode: undefined,
                      message: err.message,
                      error: err.message,
                    });
                  }
                }
              }
              setLoading(false);
            },
            [axiosFunction],
          );
        
          useEffect(() => {
            if (!onMount) return;
            request(argument);
          }, []);
        
          return [request, loading, error, data];
        }
      • API 요청비동기 데이터 상태 로직

      • 인자 : axios로 API 호출 후 AxiosPromise<T>를 반환하는 함수

        • /axios/requests 폴더에 API 호출 함수들을 분리
      • 반환 값 : [ request, loading, error, data ]

        • request : wrapping된 API 호출 함수 (function)
        • loading : loading에 대한 상태 값 (boolean)
        • error : error에 대한 상태 값 (object | null)
        • data : success시 받아온 데이터 (T | null)
      • 옵션

        • onMount : 컴포넌트 초기 렌더링 후 API 요청 자동화 여부 (boolean)
        • errNavigate : error 응답 시 에러페이지로의 이동 여부 (boolean)
    • useInputValidation
      • 코드로 살펴보기

        import React, { useState } from 'react';
        
        export default function useInputValidation(
          callback: (value: string) => boolean,
          initialValue: string,
        ): [(e: React.ChangeEvent<HTMLInputElement>) => void, boolean] {
          const [isValidated, setIsValidated] = useState(callback(initialValue));
          const validateInputValue = (e: React.ChangeEvent<HTMLInputElement>) => {
            const { value } = e.currentTarget;
            setIsValidated(callback(value));
          };
          return [validateInputValue, isValidated];
        }
      • Input 요소의 유효성 검증 로직을 담당

      • 인자 : input 요소 value 검증 후 boolean을 반환하는 함수

      • 반환 값 : [ validateValue, isValueValidated ]

        • validateValue : input 요소의 onChange 핸들러 (function)
        • isValueValidated : input 요소 value의 validation 결과 값 (boolean)
⚠️ **GitHub.com Fallback** ⚠️