본문 바로가기
공부낙서장

부트캠프 프론트엔드 및 백엔드 협업 과제 완료

by 곰인간 2023. 8. 13.

배포 주소: https://kdt-5-mini-team-11-eifz.vercel.app/

GitHub: https://github.com/KDT5-MINI-TEAM11/client

참고로 팀 이름은 개쩌는팀 이다 ㅋㅋ

이번 프로젝트를 하면서 공부가 필요한 부분

recoil 등 다른 전역상태관리 라이브러리, axios interceptor


이번 협업 과제가 완료 되었다.

일단 과제를 진행하면서 어려웠던 점은 

새로운 라이브러리나 외부 서비스를 사용함에 있어서 영문 Docs를 대충 훑어 넘어가버려서 

쉽게 해결 할 수 있던 문제들을 오래 끌었던 점과

원래 프론트엔드 작업 인원은 총 3명이었으나, 

한 분이 과제를 진행하는데 있어서 무리가 있을거 같다는 다른 분의 의견에

그분 작업량을 나누고 다른 한 분이 그 분을 케어? 1:1로 공부?지도?를 중간중간 진행하였다.
(과제는 초기에 잠깐 참여했으나 그땐 더미 데이터를 이용해서 간단하게 하던 작업이라 그 부분 틀만 찍먹하고 빠지셨다..)

뭐 이건 어려웠던거 보단 이런 일도 있구나 정도..

이전엔 전역상태관리 라이브러리로 zustand를 사용해봤는데,

이번엔 처음으로 recoil을 사용했다.

제대로 모든 기능을 사용한건 아닌거 같고, 간단하게 전역상태관리가 필요한 일부분에 사용하고,

accessToken 관리에 사용되었다.

아, acceessToken이라고 하니깐 refreshToken 때문에 처음부터 끝까지 상당히 애먹었던거 같다.

이 부분은 다른 분이 해결하셨는데, axios의 interceptor를 이용하였다.
(개인적으로 이 부분 추가 적으로 공부가 필요함!)

그리고 전체적인 분위기는 다들 좋은 분들이라 잡음 없이 원활하게 소통하였고,

처음부터 끝까지 웃으면서 작업을 마무리했다.

개인적으로 신경을 많이 썼던 부분은

쓸데 없이 리렌더링이 일어나는걸 줄이는 것과,

불필요한 서버와의 통신을 줄이는 부분이었다.

기회, 설계 단계부터 단추를 잘 못 끼우고 시작하다보니 주먹구구식으로 변경하면서

문제가 생겼던 부분들이었고,

팀원들과 의견조율을 하면서 해결하였다.

간단하게 이야기 하자면 우리가 작업한 과제는 연차와 당직을 관리하는 웹애플리케이션이고,

연차와 당직을 신청하는 부분에서 연차를 신청하면 Header의 유저 정보에서 

연차가 차감되는게 유저입장에서 바로 직관적으로 보여졌어야하는데,

처음엔 이 부분을 신경쓰지 못 하고 있다가 1차 테스트 하던 때에 발견하여 

신청을 하면 유저 정보가 리렌더링 되어 연차가 차감되는게 보이게 하였다.

하지만 이 이후에도 2차 테스트 때 문제를 찾았던게,

당직을 신청하였을 때도 이 부분엔 상태가 변동이 없는데 리렌더링이 일어나는걸 확인하였다.

그래서 이 부분의 로직을 추가적으로 수정하여, 연차가 신청 되었을 때만 그 날만큼 유저 정보의 연차 상태가 변경되게 하였고,

당직을 신청 했을 때는 상태값에 변동이 없게 하였다.

물론 연차/당직 취소하는 부분 또한 마찬가지로 손을 보았다.

서버에서의 불필요한 통신은 메인에서 switch로 토글하면 모든 사용자의 연차/당직 일정 또는 

나만의 연차 당직 일정을 볼 수 있게 하였다.

먼저 달력에 표기되는 일정들은 1년 단위의 데이터를 받아왔고, 처음 백엔드 쪽과 협의 했을 당시에

받아온 데이터에 유저를 구분할 수 있는 부분은 유저이름만 보내왔었다.

그래서 switch로 나의 일정을 볼 때는 1년치의 response date에 있는 userName과 

유저 정보를 가져오는 엔드포인트 response date의 userName이 같으면 필터링을 통해서 렌더링 되게 하였는데,

useEffect(() => {
    const schedule = async () => {
      // getAccessTokenFromCookie를 이용해서 쿠키에 저장된 accessToken을 가져옴
      const accessToken = getAccessTokenFromCookie();
      // 엑세스 토큰이 없으면 서버에 요청하지 않음
      if (!accessToken) {
        return;
      }

      setIsLoading(true);

      const listResponse = await scheduleList(year);
      const infoResponse = await getMyAccount();

      // 실제 응답 데이터 추출
      const listResponseData = listResponse.data.response;
      const infoResponseData = infoResponse.data.response;

      // response data를 가져오는데 그 내부에 있는 response라는 배열 데이터를 각각의 요소를
      // 아래의 형태의 객체로 변환해서 events 변수에 저장, setEvents에 전달
      const events = listResponseData
        .filter(
          (item: ScheduleItem) =>
            (isAllChecked && item.state === 'APPROVE') ||
            (item.userName === infoResponseData.userName &&
              item.state === 'APPROVE'),
        )
        .map((item: ScheduleItem) => {
          return {
            title: item.userName,
            start: item.startDate,
            end: item.endDate,
            color: DUTY_ANNUAL[item.scheduleType].color,
          };
        });
      setEvents(events);
      setIsLoading(false);
    };
    schedule();
  }, [isSignedin, year, month, isAllChecked]);

위의 내용을 보면 scheduleList와 getMyAccount를 서버에 요청해서 데이터를 받아온다.

그리고 제일 밑에 부분에 보면 월 단위가 바뀔 때 마다 서버에 요청이 되는데 생각보면

scheduleList에 고유의 user정보를 받아와서 확인하면 되는거였고,

월 단위가 바뀔 때 마다 useEffect내부의 함수가 동작하게 되어있는데,

이 부분도 처음에 미처 생각하지 못 한게 어차피 scheduleList로 년단위의 데이터를 불러오는데 월 단위의 상태값 변경에 

신경 쓸 필요가 없었다.

  const userEmail = useRecoilValue(UserEmailAtom);

useEffect(() => {
    const getUsersYearlySchedules = async () => {
      if (!accessToken) {
        return;
      }
      try {
        setUserYearlySchedulesLoading(true);
        const listResponse = await scheduleList(year);
        const listResponseData = listResponse.data.response;

        const sideMyScheduleData = listResponseData
          .filter((item: mySchedule) => item.userEmail === userEmail)
          .map((item: mySchedule) => {
            return {
              id: item.id,
              key: item.id,
              scheduleType: item.scheduleType,
              startDate: item.startDate,
              endDate: item.endDate,
              state: item.state,
            };
          });
        setSideMyschedule(sideMyScheduleData);

        const events = listResponseData
          .filter((item: mySchedule) => item.state === 'APPROVE')
          .map((item: ScheduleItem) => {
            const adjustEndDate = dayjs(item.endDate)
              .add(1, 'day')
              .format('YYYY-MM-DD');
            return {
              userEmail: item.userEmail,
              title: item.userName,
              start: item.startDate,
              end: adjustEndDate,
              color: DUTY_ANNUAL[item.scheduleType].color,
            };
          });
        setEvents(events);
      } catch (error) {
        console.log(error);
      } finally {
        setUserYearlySchedulesLoading(false);
      }
    };
    getUsersYearlySchedules();
  }, [year, accessToken, userEmail]);

그래서 userEmail을 recoil을 사용해서 전역으로 상태관리하였고,

백엔드 분들과 소통을 통해서 scheduleList 스키마에 userEmail 부분을 추가하였다.

그리고 위에서 말 안했지만 추가적으로 switch토글 될 때 마다 리렌더링일어나서 useEffect내부의 함수가 다시 동작하는걸 방지하기 위해 종속성 배열에서 제거하였다.

이제 보면 scheduleList는 로그인, 로그아웃 해서 accessToken이 변동, user가 변동 되었을 때와 년도가 변경 되었을 때 

useEffect내부의 함수가 동작하게 되었고, 

이로써 불필요한 서버와의 통신을 대폭 줄였다.

 

댓글