From ea360486112d0bc90b143b47a98da259996d22fd Mon Sep 17 00:00:00 2001
From: PARK NA HYUN <116629752+studioOwol@users.noreply.github.com>
Date: Thu, 28 Nov 2024 14:09:25 +0900
Subject: [PATCH] =?UTF-8?q?[FE]=20=EB=B0=A9=20=EB=AA=A9=EB=A1=9D=20?=
=?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=EB=84=A4=EC=9D=B4=EC=85=98=20?=
=?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20(#189)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* refactor: useEffect 하나로 동작하도록 변경
* feat: Pagination을 위한 데이터 구조, 상태, API 변경
* feat: Pagination 버튼 컴포넌트 데이터 사용
* feat: 페이지네이션 기능 추가
SSE, RoomList, RoomListPage 로직 변경 및 상수 추가
* docs: README.md 업데이트
---
fe/README.md | 25 +++++++++
fe/src/components/common/SearchBar.tsx | 16 ++----
fe/src/constants/rules.ts | 1 +
fe/src/hooks/usePagination.ts | 31 -----------
fe/src/hooks/useRoomsSSE.ts | 54 ++++++++++---------
.../RoomListPage/RoomList/Pagination.tsx | 38 +++++++------
.../pages/RoomListPage/RoomList/RoomList.tsx | 47 ++++++++--------
fe/src/pages/RoomListPage/index.tsx | 22 ++++++--
fe/src/stores/queries/getRoomsQuery.ts | 11 ++--
fe/src/stores/zustand/useRoomStore.ts | 23 ++++++--
fe/src/types/roomTypes.ts | 13 +++++
11 files changed, 163 insertions(+), 118 deletions(-)
delete mode 100644 fe/src/hooks/usePagination.ts
diff --git a/fe/README.md b/fe/README.md
index 3209eed..3221f1b 100644
--- a/fe/README.md
+++ b/fe/README.md
@@ -86,3 +86,28 @@ npm install react@latest react-dom@latest
- Player 컴포넌트 내부에 isMuted 초기 상태를 정해주고, muteStatus 데이터 상태가 변경되었을 때 isMuted를 변경해 주는 방식으로 바꿨다.
- 이렇게 해서 Player 컴포넌트와 GameScreen 컴포넌트를 독립적으로 리렌더링 해줄 수 있게 됐다.
- 문제: muteStatus의 initial state를 null로 설정하니까 처음에 가져올 때 에러 발생해서 빈 객체로 초기화
+
+### 검색과 실시간성은 분리하자
+
+- 한 사용자가 검색 중일 때 새로운 방이 생성되거나 삭제된 경우 이를 실시간으로 반영해서 필터링해야 하나 고민을 했다.
+- 사용자 입장에서 필터링된 방이 갑자기 새로 생기거나 없어지는 게 이상할 것 같다는 생각이 들었다.
+- 그래서 검색어를 지우면 1페이지의 방 목록을 보여주도록 함
+ - 대신 검색으로 필터링된 방이 삭제된 경우에는 `삭제된 방입니다.`와 같은 알림을 띄우는 게 어떨까
+ - 검색 중 필터링된 방이 삭제되면 에러 발생 -> 이 경우는 나중에 해결하기로
+- 아.. 근데 1페이지가 꽉 차지 않은 경우에는 방 생성, 방 삭제 시 방 목록이 업데이트돼서 SSE로 리렌더링 될 텐데.. 하 모르겠다
+
+### 실시간 통신 페이지네이션 이렇게 어려울 일이야?
+
+- 페이지네이션 하려면 서버에서 전체 방 개수, 혹은 페이지 개수 등의 정보를 내려줘야 한다.
+ - Taskify 할 때 엄청 고민했던 부분이었다. DB에 count 컬럼을 두고 관리했던..
+- 그래야 페이지를 이동시킬 수 있고, 페이지를 이동할 수 있어야 해당 페이지 번호로 요청을 보내서, 해당 페이지의 방 목록을 받아와 렌더링 해줄 수 있기 때문이다.
+- 그래서 데이터 구조도 바뀌었고, SSE 부분도 다 바꿔줘야 했다. 머리가 터질 것 같다.
+ - SSE는 해결된 걸 확인하긴 했는데, REST API 쪽이 문제인 것 같다. 초기 데이터가 null로 오는 건가..? 나는 뭔지 모르겠다.
+- 서버 쪽도 갑자기 많은 걸 바꿔서 그런지 자꾸 서버 에러가 나서, 나는 아무래도 기다려야 할 것 같다.🫠
+- 원인을 알아냈다.
+ - 지금 페이지네이션 버튼 생성은 REST API에 의존하고 있다. 위에서 말한 것처럼 전체 방 개수나, 총 페이지 개수를 받아와야 얘로 버튼을 만들 수 있고, 띄워줄 수 있다.
+ - 초기 페이지 번호를 0으로 Store에서 가지고 있고(프론트에서 먼저 페이지네이션을 구현할 때 인덱스로 사용한 부분이 있어서 0으로 했음), 초기 데이터 가져올 때 이 상태 값을 가지고 REST API 요청하고 받아 온 데이터를 렌더링 해준다.
+ - 지금 REST API 응답은 data: {rooms: [], pagination: {}} 구조인데, SSE 응답은 rooms 배열뿐이다.
+ - 메인 페이지에 입장해서 방 생성, 삭제를 하지 않은 사용자에게 실시간으로 페이지네이션 버튼이 뜨도록 하려면 SSE 응답에도 pagination 정보, 적어도 현재 페이지 정보를 같이 받아와서 상태를 변경시켜 줄 수 있어야 한다. 그렇지 않으면 초기에 설정된 0(1페이지)으로만 계속 SSE 요청을 보내게 된다.
+ - REST API를 또 요청하면 되지 않나? 싶어서 refetch도 시켜줬지만 무의미한 일이었다. 버튼이 생겨야 현재 페이지 상태를 변경시켜 줄 수 있기 때문이다.
+ - 현재 상황에서 새로고침을 하지 않는 한 실시간으로 페이지네이션 버튼을 띄울 수 없는 것 같다는 게 결론이다..! -> 서버에 데이터 구조 맞춰서 내려달라고 요청함
diff --git a/fe/src/components/common/SearchBar.tsx b/fe/src/components/common/SearchBar.tsx
index 9c4d8f0..b6ca7cd 100644
--- a/fe/src/components/common/SearchBar.tsx
+++ b/fe/src/components/common/SearchBar.tsx
@@ -9,14 +9,15 @@ import { getRoomsQuery } from '@/stores/queries/getRoomsQuery';
const SearchBar = () => {
const [searchTerm, setSearchTerm] = useState('');
const debouncedSearch = useDebounce(searchTerm, 200); // 200ms 디바운스
- const { setRooms } = useRoomStore();
+ const { setRooms, userPage } = useRoomStore();
const { data: searchResults } = searchRoomsQuery(debouncedSearch);
- const { data: allRooms, refetch: refetchAllRooms } = getRoomsQuery();
+ const { data: roomsData, refetch: refetchAllRooms } = getRoomsQuery(userPage);
// 검색 결과 또는 전체 방 목록으로 업데이트
useEffect(() => {
- if (!debouncedSearch.trim()) {
+ if (!debouncedSearch.trim() && roomsData?.rooms) {
refetchAllRooms();
+ setRooms(roomsData.rooms);
return;
}
@@ -24,14 +25,7 @@ const SearchBar = () => {
if (searchResults) {
setRooms(searchResults);
}
- }, [debouncedSearch, searchResults, setRooms, refetchAllRooms]);
-
- // allRooms가 업데이트되면 방 목록 갱신
- useEffect(() => {
- if (!debouncedSearch.trim() && allRooms) {
- setRooms(allRooms);
- }
- }, [allRooms, debouncedSearch, setRooms]);
+ }, [debouncedSearch, searchResults, roomsData, setRooms, refetchAllRooms]);
return (