

위 사진은 최종 결과 컴포넌트이다.
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에 올린다.