Skip to content

Commit a93f49d

Browse files
committed
Fead: Rewrite ItemListPage
Better performance with caches
1 parent 5693dce commit a93f49d

2 files changed

Lines changed: 136 additions & 88 deletions

File tree

Lines changed: 81 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,100 @@
1-
import React, { useState, useEffect } from 'react';
2-
import { useSelector } from 'react-redux';
3-
import { useParams } from 'react-router';
4-
import R from 'ramda';
1+
import { Container, Stack } from "@mui/material";
2+
import R from "ramda";
3+
import React, { useEffect, useState } from "react";
4+
import { useDispatch, useSelector } from "react-redux";
5+
import { useLocation } from "react-router";
6+
import TypeIcon from "_atoms/TypeIcon";
7+
import Item from "_molecules/Item";
8+
import { attemptGetItem } from "_thunks/item";
59

6-
import HorizontalHeader from '_organisms/HorizontalHeader';
7-
import HorizontalContent from '_organisms/HorizontalContent';
8-
import PromiseItemArray from '_utils/promiseArray';
9-
import { snakeToCamelCase } from 'json-style-converter/es5';
10-
import { getItem } from '_api/item';
11-
import { object } from 'prop-types';
10+
const ItemList = ({ items, title, iconType }) => (
11+
<div className="item-list">
12+
<div className="item-list-header">
13+
<TypeIcon type={iconType} size={1.5} opacity={0.7} />
14+
<div className="item-list-title">{title}</div>
15+
</div>
16+
<Stack direction="row" className="item-list-content">
17+
{items != null ? (
18+
items.length > 0 ? (
19+
items.map((item) => <Item item={item} />)
20+
) : (
21+
<div>표시할 항목이 없습니다.</div>
22+
)
23+
) : (
24+
<div>Loading...</div>
25+
)}
26+
</Stack>
27+
</div>
28+
);
1229

1330
export default function ItemListPage() {
14-
const { user } = useSelector(R.pick(['user']));
15-
const { userItem } = useSelector(R.pick(['userItem']));
16-
const [title, setTitle] = useState('');
17-
const [itemObjects, setItemObjects] = useState({ cabinet: [], document: [], card: [] });
18-
const [loading, setLoading] = useState(true);
19-
const { path } = useParams();
31+
const { user } = useSelector(R.pick(["user"]));
32+
const { itemCache } = useSelector(R.pick(["itemCache"]));
33+
34+
const dispatch = useDispatch();
35+
36+
const [title, setTitle] = useState("");
37+
const [items, setItems] = useState(null);
38+
const { pathname } = useLocation();
39+
40+
const addItem = (item) => {
41+
console.log("adding item", item, "previous item", items);
42+
let currentItems = items != null ? items : [];
43+
setItems([...currentItems, item]);
44+
};
2045

2146
useEffect(() => {
22-
// setting the array w.r.t. the path given
23-
console.log(`loading bookmarks with :${user.bookmarks}`);
24-
let array;
25-
switch (path) {
26-
case 'bookmarks':
27-
setTitle('북마크');
47+
let array = [];
48+
switch (pathname) {
49+
case "/bookmarks":
50+
setTitle("북마크");
2851
array = user.bookmarks;
2952
break;
30-
case 'myitems':
31-
setTitle('내가 작성한 문서');
32-
array = userItem;
53+
case "/recents":
54+
setTitle("최근에 본 문서");
55+
const localStorageRecents = JSON.parse(localStorage.getItem("recents"));
56+
array = localStorageRecents != null ? localStorageRecents : [];
3357
break;
34-
case 'recents':
35-
setTitle('최근 문서');
36-
array = JSON.parse(localStorage.getItem('recents'));
37-
break;
38-
case 'drafts':
39-
setTitle('임시저장 문서');
40-
array = userItem.filter((elem) => elem.status === 'draft');
58+
case "/drafts":
59+
setTitle("임시저장한 문서");
60+
array = Object.keys(itemCache).map(itemId => itemCache[itemId]).filter(
61+
(item) => item.owner._id === user._id && item.status === "draft"
62+
);
4163
break;
4264
default:
4365
array = [];
4466
}
4567

46-
// the array can be either an array of item objectss we wish to render
47-
// or the array of item ids
48-
Promise.all(array.map((elem) => {
49-
if (typeof elem === 'object') {
50-
return elem;
68+
let cachedItems = [];
69+
70+
array.forEach((itemId) => {
71+
if (itemCache.hasOwnProperty(itemId)) {
72+
cachedItems.push(itemCache[itemId]);
73+
} else {
74+
dispatch(attemptGetItem(itemId)).then((item) => addItem(item));
5175
}
52-
return getItem(elem);
53-
})).then((objectArray) => {
54-
const camelObjectArray = snakeToCamelCase(objectArray);
55-
setItemObjects({
56-
cabinet: camelObjectArray.filter((elem) => elem.type === 'cabinet'),
57-
document: camelObjectArray.filter((elem) => elem.type === 'document'),
58-
card: camelObjectArray.filter((elem) => elem.type === 'card'),
59-
});
60-
setLoading(false);
6176
});
62-
}, [path, user]);
6377

64-
return !loading && (
65-
<div className="recommend-page">
66-
<div className="recommend-page-header">
67-
{title}
68-
</div>
69-
<div className="recommend-container">
78+
setItems(cachedItems);
79+
}, [pathname, user]);
7080

71-
{
72-
(itemObjects.cabinet.length === 0)
73-
? ''
74-
: (
75-
<div className="recommend-block">
76-
<HorizontalHeader type="cabinet" />
77-
<hr />
78-
<HorizontalContent type="cabinet" cardArray={itemObjects.cabinet} />
79-
</div>
80-
)
81-
}
82-
{
83-
(itemObjects.document.length === 0)
84-
? ''
85-
: (
86-
<div className="recommend-block">
87-
<HorizontalHeader type="document" />
88-
<hr />
89-
<HorizontalContent type="document" cardArray={itemObjects.document} />
90-
</div>
91-
)
92-
}
93-
{
94-
(itemObjects.card.length === 0)
95-
? ''
96-
: (
97-
<div className="recommend-block">
98-
<HorizontalHeader type="card" />
99-
<hr />
100-
<HorizontalContent type="card" cardArray={itemObjects.card} />
101-
</div>
102-
)
103-
}
104-
</div>
105-
</div>
81+
const cabinetItems =
82+
items != null ? items.filter((item) => item.type === "cabinet") : null;
83+
const documentItems =
84+
items != null ? items.filter((item) => item.type === "document") : null;
85+
const cardItems =
86+
items != null ? items.filter((item) => item.type === "card") : null;
87+
88+
return items != null ? (
89+
<Container maxWidth="md">
90+
<Stack spacing={1} className="item-list-page" sx={{ py: 4 }}>
91+
<div className="item-list-page-title">{title}</div>
92+
<ItemList items={cabinetItems} title="서랍" iconType="cabinet" />
93+
<ItemList items={documentItems} title="문서" iconType="document" />
94+
<ItemList items={cardItems} title="카드" iconType="card" />
95+
</Stack>
96+
</Container>
97+
) : (
98+
<div>Loading...</div>
10699
);
107100
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
@import "mixins";
2+
3+
.content-pane {
4+
.outer-div {
5+
@include flexBox($display: flex, $justify-content: center);
6+
width: 100%;
7+
.grid-container {
8+
margin-top: 0;
9+
max-height: 100%;
10+
overflow-x: auto;
11+
width: fit-content;
12+
display: grid;
13+
grid-template-columns: 1fr;
14+
gap: 80px;
15+
}
16+
}
17+
}
18+
19+
.item-list-page {
20+
21+
.item-list-page-title {
22+
width: 100%;
23+
font-size: 2.5em;
24+
font-weight: bolder;
25+
white-space: nowrap;
26+
overflow: hidden;
27+
text-overflow: ellipsis;
28+
}
29+
30+
.item-list-header {
31+
display: flex;
32+
flex-direction: row;
33+
align-items: center;
34+
gap: 8px;
35+
padding: 8px 0;
36+
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
37+
38+
.item-list-title {
39+
flex-grow: 1;
40+
font-size: 2em;
41+
font-weight: bold;
42+
white-space: nowrap;
43+
overflow: hidden;
44+
text-overflow: ellipsis;
45+
}
46+
}
47+
48+
.item-list-content {
49+
height: $height;
50+
align-items: center;
51+
margin: 16px 0;
52+
gap: 8px;
53+
overflow-x: hidden;
54+
}
55+
}

0 commit comments

Comments
 (0)