Skip to content

Commit 68394ca

Browse files
committed
feat [#52] 롤링페이퍼에 달린 메시지 목록에 무한 스크롤 구현
1 parent 5928352 commit 68394ca

File tree

4 files changed

+71
-3
lines changed

4 files changed

+71
-3
lines changed

src/features/message/api/messages.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import axios from "axios";
12
import { apiClient } from "../../../api/client";
23

4+
let nextPage;
5+
36
async function getMessages({ recipientId, limit, page = 1 }) {
47
const searchParams = new URLSearchParams();
58
searchParams.append("page", page);
@@ -15,7 +18,23 @@ async function getMessages({ recipientId, limit, page = 1 }) {
1518
}
1619

1720
const data = response.data;
21+
nextPage = data.next;
22+
23+
return data.results;
24+
}
25+
26+
async function getNextPageMessages() {
27+
if (!nextPage) return;
28+
29+
const response = await axios.get(nextPage);
30+
if (response.status !== 200) {
31+
throw new Error("Message data를 가져오는데 실패했습니다.");
32+
}
33+
34+
const data = response.data;
35+
nextPage = data.next;
36+
1837
return data.results;
1938
}
2039

21-
export { getMessages };
40+
export { getMessages, getNextPageMessages };

src/features/message/components/messages-grid.jsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import { useRef } from "react";
12
import { useNavigate, useParams } from "react-router";
23
import styled from "styled-components";
34
import Modal from "../../../components/modal/modal.jsx";
5+
import { useIntersectionObserver } from "../../../hooks/use-intersection-observer.jsx";
46
import { media } from "../../../utils/media.js";
57
import MessageCardAdd from "./message-card-add.jsx";
68
import MessageCardDetail from "./message-card-detail.jsx";
@@ -22,9 +24,16 @@ const StyledRollingPaperMessagesGrid = styled.div`
2224
}
2325
`;
2426

25-
function MessagesGrid({ isEditing, messages, onDelete }) {
27+
function MessagesGrid({ isEditing, messages, onDelete, onInfiniteScroll }) {
2628
const navigate = useNavigate();
2729
const { id } = useParams();
30+
const infiniteScrollTargetRef = useRef();
31+
32+
const observerCallback = (entry) => {
33+
if (!entry.isIntersecting) return;
34+
onInfiniteScroll();
35+
};
36+
useIntersectionObserver(infiniteScrollTargetRef, observerCallback);
2837

2938
const handleAddClick = () => {
3039
navigate(`/post/${id}/message`);
@@ -55,6 +64,7 @@ function MessagesGrid({ isEditing, messages, onDelete }) {
5564
</Modal>
5665
)
5766
)}
67+
<div ref={infiniteScrollTargetRef}></div>
5868
</StyledRollingPaperMessagesGrid>
5969
);
6070
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { useEffect } from "react";
2+
3+
function useIntersectionObserver(targetRef, callback) {
4+
useEffect(() => {
5+
const observer = new IntersectionObserver((entries) => {
6+
entries.forEach(callback);
7+
});
8+
9+
if (targetRef) {
10+
observer.observe(targetRef.current);
11+
}
12+
13+
return () => {
14+
observer.disconnect();
15+
};
16+
}, [targetRef, callback]);
17+
}
18+
19+
export { useIntersectionObserver };

src/pages/messages-page.jsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ import styled from "styled-components";
44
import { OutlinedButton, PrimaryButton } from "../components/button/button";
55
import BUTTON_SIZE from "../components/button/button-size";
66
import BACKGROUND_COLOR from "../components/color/background-color";
7-
import { getMessages } from "../features/message/api/messages";
7+
import {
8+
getMessages,
9+
getNextPageMessages,
10+
} from "../features/message/api/messages";
811
import MessagesGrid from "../features/message/components/messages-grid";
912
import { getRecipient } from "../features/rolling-paper/api/recipients";
1013
import RollingPaperHeader from "../features/rolling-paper/components/header/rolling-paper-header";
@@ -113,6 +116,22 @@ function MessagesPage() {
113116
console.log(`Delete Message ${messageId}`);
114117
};
115118

119+
const handleInfiniteScroll = async () => {
120+
const messages = await getNextPageMessages();
121+
if (!messages) return;
122+
123+
setMessages((prev) => {
124+
const newMessages = [...prev];
125+
126+
for (const message of messages) {
127+
if (newMessages.find((value) => value.id === message.id)) continue;
128+
newMessages.push(message);
129+
}
130+
131+
return newMessages;
132+
});
133+
};
134+
116135
useEffect(() => {
117136
async function fetchRollingPaper() {
118137
try {
@@ -159,6 +178,7 @@ function MessagesPage() {
159178
isEditing={isEditing}
160179
messages={messages}
161180
onDelete={handleMessageDelete}
181+
onInfiniteScroll={handleInfiniteScroll}
162182
/>
163183
</div>
164184
</Content>

0 commit comments

Comments
 (0)