const columns = [
{ id: "date", label: "Category", minWidth: 110 },
{ id: "title", label: "Title", minWidth: 110 },
{ id: "category", label: "Category", minWidth: 120 },
{ id: "amount", label: "Amount", minWidth: 100, align: "right" },
];
컬럼을 미리 정해줘서, 입력한 데이터가 어떤 key: value형식으로 들어가는지 정해준다.
const AccountList = (props) => {
const { totalIncome, totalExpense, monthFilter, tagFilter } = props;
const [ rows, setRows ] = useState([]);
const [ page, setPage ] = useState(0);
const [ rowsPerPage, setRowsPerPage ] = useState(10);
let [ expense, setExpense ] = useState(0);
let [ income, setIncome ] = useState(0);
...중략
}
상태관리를 위해 useState()를 사용하는데, 컴포넌트 데이터와 UI를 동기화 하기 위해 사용한다. 상태가 변경되면 다시 렌더링 해서, 최신 데이터를 반영해준다. useState()를 사용할 때, 초기값을 넣지 않으면 undefined로 나온다.
const formatDate = (format) => {
const options = { year: "numeric", month: "2-digit", day: "2-digit" };
const date = new Date();
return Intl.DateTimeFormat("en-CA", options).format(date);
}
useEffect(() => {
const data = async() => {
try {
const response = await axios.get("http://localhost:4000/wallet/money");
const formattedData = response.data.map((item) => ({
...item, date: formatDate(item.date)
})))
setRows(formattedData);
} catch(err) {
console.error(err);
}
}
data();
}, []);
formatDate함수를 만들어서 format을 인자로 받고 year: 숫자, month, day는 2자리로 구성해서 "2024-05-19"같은 날짜 형식을 띄운다.
axios.get()요청을 보내줘서 MongoDB에 저장된 데이터를 item변수에 담아도록 한 뒤, map()함수를 통해 분리하고, 날짜 형식 date는 위에서 만든 formatDate(item.date)를 넣어서 가져와서 연동해주고, setRows()를 호출해서 상태를 업데이트 해준다.
그 후 data()를 호출해준다.
배열이 비어있으므로, useEffect()는 컴포넌트가 처음 실행될 때 배열 내부가 추가되고 변경되지 않는다.
useEffect(() => {
let exp = 0;
let inc = 0;
rows.forEach((item) => {
if (item.tag === "지출") {
exp += parseInt(item.amount);
else if (item.tag === "수입") {
inc += parseInt(item.amount);
}
});
setExpense(exp);
setIncome(inc);
totalExpense(exp);
totalIncome(inc);
}, [rows, totalExpense, totalIncome]);
useEffect()를 한번 더 사용해준다. 다시 설명하자면 useEffec()는 컴포넌트가 렌더링 될 때마다 함수 내부의 문장을 실행하는 Hook이라고 정의할 수 있다.
배열 안에 rows, totalExpense, totalIncome을 넣었으니 이 부분이 변경되면 다시 렌더링 되도록 한다.
rows의 tag가 지출이라면, exp에 값을 추가하고, 수입이라면 inc에 값을 추가해준다. 그리고 지출과 수입을 useState()에 업데이트 해준다.
const handleChangePage = (event, newPage) => {
setpage(newPage);
};
const handleChangeRowsPerPage = (event) => {
setRowsPerPage(+event.target.value);
setPage(0);
};
페이지네이션을 위한 함수이다. handleChangePage는 사용자가 페이지를 변경할 때 호출된다. newPage를 호출해서 현재 페이지 상태를 newPage로 업데이트 해준다.
handleChangeRowsPerPage는 setRowsPerPage를 호출해서 페이지 당 표시할 행 숫자를 업데이트 해준뒤, 현재 페이지를 0으로 리셋해준다.
<div className="AccountList">
<TableContainer sx={{ maxHeight: 440 }}>
<Typography sx={{ flex: "1 1 100%" }} id="tableTitle" component="div">
<Tooltip title="Filter list">
<IconButton>
<FilterListIcon type="button" onClick={tagFilter} />
</IconButton>
</Tooltip>
<select
className="monthFilter"
placeholder="월"
onChange={monthFilter}
required
defaultValue=""
>
<option value="" disabled>
월별 필터
</option>
<option value="01">1월</option>
<option value="02">2월</option>
<option value="03">3월</option>
<option value="04">4월</option>
<option value="05">5월</option>
<option value="06">6월</option>
<option value="07">7월</option>
<option value="08">8월</option>
<option value="09">9월</option>
<option value="10">10월</option>
<option value="11">11월</option>
<option value="12">12월</option>
</select>
</Typography>
<Table stickyHeader aria-label="sticky table">
<TableHead>
<TableRow>
{columns.map((column) => (
<TableCell
key={column.id}
align={column.align}
style={{ minWidth: column.minWidth }}
>
{column.label}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{rows
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((row) => {
return (
<TableRow hover role="checkbox" tabIndex={-1} key={row.id}>
{columns.map((column) => {
const value = row[column.id];
return (
<TableCell key={column.id} align={column.align}>
{value}
</TableCell>
);
})}
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
<TablePagination
rowsPerPageOptions={[10, 25, 100]}
component="div"
count={rows.length}
rowsPerPage={rowsPerPage}
page={page}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</div>
);