sihyun10 / FE_PS_Final_Refactor

몰리턴 기업 연계 프로젝트 코드리뷰 및 리팩토링
0 stars 0 forks source link

데이터 처리 프로세스 이해하기 #18

Closed 05Castle closed 1 year ago

05Castle commented 1 year ago

PdfUploadModule 코드리뷰및 리팩토링 과정에서 구조를 보다 가독성 좋게 리팩토링하는 것에 집중하면서, 데이터가 처리되는 로직을 제대로 분석하지 못하였다.

PdfUploadModule에서 데이터를 fetch하고 DataStore에 전역 상태로 저장하는 과정을 분석하고 이해해보자. 서버에서 받은 PDF 데이터와 아파트 시세 데이터의 흐름을 추적해보자.

sihyun10 commented 1 year ago

PdfUploadModule 파일에서 파일데이터를 업로드하는 부분

  const onFileUpload = async () => {
    if (!PDFfile) {
      setErrorModalOpen(true);
      return;
    }

    const formData = createFormData(PDFfile);
    if (!formData) {
      console.log('FormData 생성에 실패했습니다.');
      setIsUploading(false);
      return;
    }
    setModalIsOpen(true);
    setIsUploading(true);
    setDownloadProgress(0);
    try {
      const response = await uploadFileToServer(formData);

      if (response) {
        const customData = await ApartData(response.data.summary.newAddress);
        if (customData) {
          const lastId = addResponseItem(fileName, { ...response.data, customData });
          setDataStoreId(lastId);
        } else {
          const lastId = addResponseItem(fileName, { ...response.data });
          setDataStoreId(lastId);
        }
      }
      setDownloadProgress(100);
    } catch (error) {
      setDownloadProgress(0);
      console.error('파일 업로드 실패:', error);
      UploadErrorModal();
    } finally {
      setIsUploading(false);
    }
  };

위의 코드를 봤을때, createFormData 함수를 사용하여 PDFfile로부터 formData를 생성함. formData 생성에 실패하게된다면 오류 메시지를 출력하고, setIsUploading(false)를 호출하여 업로드 상태를 변경하고 함수를 종료한다.

폼 데이터 생성후, 모달을 열고, 업로드 상태 변경 후 setDownloadProgress(0)를 호출해 다운로드 진행률 0 (초기화) 시킴.

uploadFileToServer 함수를 사용해, 서버에 파일을 업로드한다. response 변수에 서버 응답한 내용을 저장한다.

sihyun10 commented 1 year ago

만약 서버 응답이 되면 response.data.summary.newAddress를 사용해, ApartData 함수를 호출해 customData를 가져오게 된다. customData가 있으면, response.data와 customData를 합쳐서 addResponseItem 함수를 호출해 데이터 store에 새로운 항목을 추가한다. setDataStoreId 함수를 사용하여 데이터 store에서 생성된 ID를 설정함.

sihyun10 commented 1 year ago

(참고) 여기서 addResponseItem 함수DataStore.tsx파일에서 명시하였는데,

export const useDataStore = create<DataStoreState>()(
  persist(
    (set, get) => ({
      responseItems: [],
      addResponseItem: (filename: string, data: string) => {
        const currentResponseItems = get().responseItems;
        const newId =
          currentResponseItems.length > 0
            ? currentResponseItems[currentResponseItems.length - 1].id + 1
            : 1;
        const newItem = { id: newId, filename, data };
        set((state: DataStoreState) => {
          return { responseItems: [...state.responseItems, newItem] };
        });
        return newId;
      },

filename과 data 매개변수를 받아서 새로운 ResponseItem을 생성하고 상태를 업데이트하는 함수다.

sihyun10 commented 1 year ago

uploadFileToServer 함수는 서버로 파일을 업로드하는 하는 부분이다.

  const uploadFileToServer = async (formData: FormData): Promise<any> => {
    try {
      const source = axios.CancelToken.source();
      setCancelToken(source);
      const response = await instance.post('api/pdfupload', formData, {
        cancelToken: source.token,
        onUploadProgress: (progressEvent: AxiosProgressEvent) => {
          if (progressEvent.loaded && progressEvent.total) {
            const progress = Math.round((progressEvent.loaded * 100) / progressEvent.total);
            setUploadProgress(progress);
          }
        },
        onDownloadProgress: (progressEvent?: AxiosProgressEvent) => {
          if (progressEvent?.loaded && progressEvent?.total) {
            const progress = Math.round((progressEvent.loaded * 100) / progressEvent.total);
            setDownloadProgress(progress);
          }
        },
      });

      return response.data;
    } catch (error) {
      if (axios.isCancel(error)) {
        setIsUploadComplete(false);
        setUploadProgress(0);
        console.log('사용자 취소 실패:', error.message);
      } else {
        setIsUploadComplete(false);
        setUploadProgress(0);
        console.log('통신 실패:');
        setModalIsOpen(false);

        ErrorModal(false, false);
      }
    }
  };

일단, FormData를 매개변수로 받고, 파일을 서버에 업로드하는데요. instance.post를 작성해, 서버의 api/pdfupload endpoint로 파일을 업로드를 해요.

업로드 과정에서 cancelToken을 사용하여 요청을 취소할 수 있도록 설정하였고, onUploadProgress 콜백 함수를 통해 업로드 진행 상황을 추적하고, setUploadProgress 함수를 호출하여 업로드 진행률을 설정한다.

onDownloadProgress 콜백 함수를 통해 다운로드 진행 상황을 추적하고, setDownloadProgress 함수를 호출하여 다운로드 진행률을 설정한다.

따라서, axios 를 사용해, 파일을 서버로 업로드하고, 업로드 진행 상황을 보며 오류 처리 또한 처리해주었다.

05Castle commented 1 year ago

데이터를 fetch해오는 함수는 업로드 모듈의 uploadFileToServer와 onFileUpload, ApartDataApi의 ApartData와 fetchData함수. fetchData는 ApartData 내부에서 실행되고, uploadFileToServer, ApartData함수는 onFileUpload 내부에서 실행되기 때문에, 사실상 onFileUpload가 data fetch를 실행하는 함수라고 볼 수 있겠다.

uploadFileToServer는 api/pdfupload로 폼데이터(등기부 pdf 파일)를 보내고 response를 받는다. 이 과정에서 업로드 진행상황을 추적하기 위해서 AxiosProgressEvent를 매개변수로 받는 onUploadProgress, onDownloadProgress 콜백함수가 등록되어 있다 그리고 도중에 업로드 요청을 취소할 수 있는 취소 토큰이 있다. (파일을 불러오는 시간이 오래 걸릴 수 있는 이벤트이므로)

ApartData는 입력된 주소를 기반으로 KaKaoSearchApi를 통해 주소에서 법정동 코드와 도로명건물번호 정보를 받고, fetchData를 통해 api/proxy로 법정동 코드와 도로명주소를 보내고 response를 받아와서 이를 다시 반환한다.

업로드 버튼을 누르면 onFileUpload가 실행되면서 uploadFileToServer를 내부에서 실행하여 서버와 통신하고 받아온 데이터를 response 변수로 저장. 그리고 response를 받아오면, 받아온 주소값(response.data.summary.newAddress)을 사용하요 ApartData함수를 호출하고 ApartData에서 받아온 데이터를 customData 변수로 저장.

그리고 전역 상태에 파일 이름과 두 응답 데이터를 전달하면 스토어의 responseItems 배열에 추가한다. (이 과정에서 id까지 추가하여 상태에 업데이트 된다)

데이터를 가져오는 과정을 전반적으로 정리하자면,

  1. 사용자가 파일을 선택하고 업로드 버튼을 클릭
  2. onFileUpload 함수가 호출.
  3. 선택한 파일을 기반으로 formData를 생성합니다.
  4. uploadFileToServer 함수를 호출하여 서버로 파일을 업로드합니다.
  5. 받아온 데이터를 response 변수로 저장.
  6. response가 존재한다면, ApartData 함수를 호출하여 해당 주소의 추가 데이터를 가져온다.
  7. ApartData 함수에서는 Kakao API를 사용하여 주소에 대한 상세 정보를 가져온다.
  8. fetchData 함수를 사용하여 백앤드에서 해당 주소의 과거 데이터를 가져온다.
  9. fetchData 함수는 페이지별로 데이터를 가져오며, 페이지가 넘칠 경우 다음 페이지를 호출하여 데이터를 추가로 가져온다.
  10. 가져온 데이터를 필터링하여 결과를 저장
  11. ApartData 함수가 결과 데이터를 반환
  12. 반환된 추가 데이터를 포함하여 addResponseItem 함수를 호출하여 결과를 저장 전역 상태에 저장
  13. addResponseItem 함수는 파일 이름과 해당 데이터를 인자로 받아 새로운 아이템을 생성하고 responseItems 배열에 추가.
  14. 이때, 새로운 아이템의 id는 현재 responseItems 배열의 마지막 아이템의 id에 1을 더한 값. 만약 배열이 비어있다면 id는 1로 설정.
  15. 전역 상태는 persist 함수를 사용하여 세션 스토리지에 저장
  16. 모든 과정이 완료되면 파일 업로드 상태를 해제