[TIL] 240525 (React 가계부 월별 지출 Summary 제작)

·2024년 5월 25일

TIL

목록 보기
52/268
post-thumbnail

🥞 오늘 한 일

  • 리액트 숙련 개인과제
    • 월별 지출 Summary
    • 지출 내역 없을 경우 분기 처리
    • Detail.jsx 필요없는 useRef 정리
    • 지출 금액 천 단위마다 콤마 찍기
    • 과제 질문 2번까지 답변
    • 가이드 영상 수강
  • 리액트 숙련 강의
    • useRef 재수강

🍽️ 문제 해결

월별 지출 Summary

summary

위 사진은 최종 결과 컴포넌트이다.

  const expensesSummary = expensesList.reduce((acc, cur) => {
    return acc + Number(cur.amount);
  }, 0);

먼저 총 지출을 계산했다. 총 지출은 reduce를 사용해 간단하게 구할 수 있었다.
항목별 지출 금액을 계산해 배열로 만드는 게 은근히 까다로웠다.

  const expensesItemList = () => {
    const expensesItemList = {};
    expensesList.forEach((expense) => {
      if (Object.keys(expensesItemList).includes(expense.item)) {
        expensesItemList[expense.item] += +expense.amount;
      } else {
        expensesItemList[expense.item] = +expense.amount;
      }
    });
    return Object.entries(expensesItemList)
      .sort((a, b) => b[1] - a[1])
      .reduce((acc, cur, idx) => {
        if (idx < 4) {
          acc.push(cur);
        } else if (idx === 4) {
          acc.push(["기타", `${+cur[1]}`]);
        } else {
          acc[4][1] = +acc[4][1] + cur[1];
        }
        return acc;
      }, []);
  };

먼저 객체를 만들어, 객체 안에 같은 이름의 key가 없을 경우 해당 item이 key, amount가 value가 되는 요소를 넣어주고, 같은 이름의 key가 있을 경우 해당 key의 value에 amount를 더해줘서 각 항목 별 지출 금액을 계산했다.
그렇게 만든 객체를 배열로 바꿔준 다음, 금액이 많은 순으로 정렬하고, reduce를 사용해 지출 항목이 5개 이상일 경우 5번째 항목부터는 전부 기타 항목으로 처리했다.

아래는 위 코드들이 들어간 ExpenseSummary 컴포넌트의 코드이다.

// ExpenseSummary.jsx

const ExpenseSummary = () => {
  const { expensesList } = useSelector((state) => state.expensesList);
  const { selectedMonth } = useSelector((state) => state.selectedMonth);
  const graphColor = ["#007BFF", "#28A745", "#DC3545", "#FFC107", "#17A2B8"];
  // 월별 총 지출 계산
  const expensesSummary = expensesList.reduce((acc, cur) => {
    return acc + Number(cur.amount);
  }, 0);
  // 항목별 지출 금액 계산
  const expensesItemList = () => {
    const expensesItemList = {};
    expensesList.forEach((expense) => {
      if (Object.keys(expensesItemList).includes(expense.item)) {
        expensesItemList[expense.item] += +expense.amount;
      } else {
        expensesItemList[expense.item] = +expense.amount;
      }
    });
    return Object.entries(expensesItemList)
      .sort((a, b) => b[1] - a[1])
      .reduce((acc, cur, idx) => {
        if (idx < 4) {
          acc.push(cur);
        } else if (idx === 4) {
          acc.push(["기타", `${+cur[1]}`]);
        } else {
          acc[4][1] = +acc[4][1] + cur[1];
        }
        return acc;
      }, []);
  };
  return (
    <StDiv>
      <StTitle>
        {selectedMonth}월 총 지출: {expensesSummary.toLocaleString()}</StTitle>
      <StGraph>
        {expensesItemList().map((item, idx) => {
          return (
            <StGraphItem
              key={item[0]}
              $backColor={graphColor[idx]}
              $width={((item[1] / expensesSummary) * 100).toFixed(2)}
            ></StGraphItem>
          );
        })}
      </StGraph>
      <StUl>
        {expensesItemList().map((item, idx) => {
          return (
            <StLi key={item[0]}>
              <StColorItem $backColor={graphColor[idx]}></StColorItem>
              {item[0]}: {item[1].toLocaleString()} (
              {((item[1] / expensesSummary) * 100).toFixed(2)}%)
            </StLi>
          );
        })}
      </StUl>
    </StDiv>
  );
};

위에서부터 순서대로 '총 지출 / 그래프 / 각 항목 별 금액 및 퍼센트'를 나타냈다. styled-components의 이점을 사용하여 각 항목 별로 다른 컬러를 조건부 스타일링으로 적용했다.
((item[1] / expensesSummary) * 100).toFixed(2) : 비율을 계산하기 위해 쓴 코드. 해당 amount를 총합으로 나눠주고, 백분위를 위해 100을 곱한 다음 toFixed 메서드를 사용해 소수점 두번째 자리까지만 나오게 했다.

지출 내역 없을 경우 분기 처리

// ExpensesList.jsx

{expensesList.length > 0 ? (
  expensesList.map((expense) => {
    return <ExpenseItem key={expense.id} expense={expense} />;
  })
) : (
  <StDiv>지출이 없습니다.</StDiv>
)}

간단하게 삼항 연산자를 사용해 지출 내역이 없을 경우 지출이 없다는 텍스트가 나오도록 만들었다.

지출 금액 천 단위마다 콤마 찍기

지인이 새로운 메서드를 알려줘서 쉽게 적용했다.

<StItemRight>{amount.toLocaleString()}</StItemRight> // 1,055,000원

과제 질문 답변

이번 과제에서도 과제와 함께 제출해야하는 질문이 세가지가 있었다. 세번째 질문에는 아직 답변을 못 했기에, 현재까지 답변한 두번째 질문까지만 TIL에 올린다.

  1. styled-components 는 CSS in JS 라이브러리 중 하나로 리액트 개발 시 자주 사용되는 방법입니다. 본인이 생각하는 styled-components의 장점과 단점을 말씀해 주세요.
    • 장점 : 기존의 css에서는 이용할 수 없었던 조건문, 변수 등 다양한 로직을 이용할 수 있다는 장점이 있습니다.
    • 단점 : jsx 파일 내에서 사용할 경우 코드가 너무 길어져 가독성이 떨어지는 단점이 있습니다.
  2. props-drilling으로 전체를 먼저 구현하신 다음 context api와 redux로 리팩터링해서 전역 상태 관리를 경험해 보셨습니다. 어떤 상태들을 전역 상태로 관리하셨나요? context나 redux로 전역상태를 관리해봤을 때 어떤 문제를 해결해준다고 느끼셨나요?
    • 전체 지출 목록, 월 별로 화면에 보여줄 지출 목록, 선택된 월. 이 세가지 상태들을 전역 상태로 관리했습니다.
    • props-drilling 이용 시 해당 props가 필요없는 컴포넌트임에도 자식 요소에 props를 넘겨주기 위해 props를 가지고 있어야하는 번거로움이 있었는데, 전역 상태 관리를 하니 그럴 필요가 없고 필요한 컴포넌트에서 바로 가져다 쓸 수 있어 해당 번거로운 문제를 해결해준다고 느꼈습니다.

🍪 배운 것

  • toLocaleString() : number 타입에서 사용할 경우 3자리 숫자(천 단위)마다 콤마.
  • toFixed() : 매개 숫자에 따라 소수점을 해당 숫자만큼 자를 수 있다.

🍴 돌아보기

  • 처음에는 월별 지출 Summary를 과연 내가 할 수 있을까 싶어 일단 총 지출이라도 해보자! 하고 시작했는데, 역시 해보니까 그렇게 큰 어려움이 없었다. 막상 해보면 별 거 아닌게 많다는 점을 오늘 또 한 번 깨달았다.

🍳 내일 할 일

  • 리액트 숙련 개인과제
    • 남은 선택 구현 사항
    • 남은 과제 질문 답변
profile
웹 프론트엔드 개발자

0개의 댓글