Gather here - 5
layout.tsx
를 이용해 컴포넌트 마운트 수 줄이기
전반적인 리팩토링을 진행했다.
먼저 Chat, Calender 컴포넌트가 페이지 이동마다 새로 마운트 되고 있는 것이 비효율적이라 생각했다.
그래서 useEffect 를 통해 페이지 이동 마다 mount 되는 것을 확인했다. 내가 담당한 Sidebar 영역도 하나의 컴포넌트로 만들어 코드를 더 세세히 나누고 싶어 이전에 구현되어 있던 부분을 layout.tsx
로 옮겨두었다.
그런데, MainLayout 내에서 모바일 브라우저인지 확인하는 부분이 있는데 useEffect 를 통해 검사하고 있어 상태를 최소화했다.
화면 사이즈는 이벤트 핸들러보다 css 를 통해 관리하는 것이 효율적이라고 생각했다. 그래서 모달을 위한 상태만 남기고 모두 정리했다.
또한 레이아웃이 클라이언트 컴포넌트 인것이 마음에 들지 않았었는데, 상태를 정리하고 나니 레이아웃으로 만들 수 있게 되었다.
그제서야 MainSideBar 라는 컴포넌트로 분리가 가능해졌다!!!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
"use client";
import Calender from "@/components/MainPage/MainSideBar/Calender/Calender";
import Chat from "@/components/MainPage/MainSideBar/Chat/Chat";
import { useState } from "react";
import Image from "next/image";
import ChatModal from "./Chat/ChatModal";
const MainSideBar = () => {
const [isModalOpen, setIsModalOpen] = useState(false);
const openModal = () => {
setIsModalOpen(true);
};
const closeModal = () => {
setIsModalOpen(false);
};
return (
<>
<div className="col-span-1 m:hidden">
<div className="sticky top-4">
<h4 className="flex items-center ml-2 mb-4 text-labelStrong">
아래에 새로운 요소 들어갈 자리임
</h4>
<div className="w-full h-full bg-primary">
<Image
src="/assets/blank.svg"
width={322}
height={256}
alt="빈 이미지"
/>
</div>
<Calender />
</div>
</div>
{isModalOpen ? (
<button
onClick={closeModal}
className="fixed bottom-4 right-1 z-10 hover:animate-bounce"
>
<Image
src="/Chat/close.svg"
alt="채팅창 닫기 버튼"
width={90}
height={60}
priority
className="w-auto h-auto"
/>
</button>
) : (
<button
onClick={openModal}
className="fixed bottom-4 right-1 z-10 hover:animate-bounce"
>
<Image
src="/Chat/chat.svg"
alt="채팅창 열기 버튼"
width={90}
height={60}
priority
className="w-auto h-auto"
/>
</button>
)}
<ChatModal isOpen={isModalOpen} onRequestClose={closeModal}>
<Chat />
</ChatModal>
</>
);
};
export default MainSideBar;
아예 이렇게 컴포넌트로 분리하고 나니, 정말로 한 번만 마운트가 발생했다.
컴포넌트 분리 전에는 매번 마운트가 발생했다.
layout 으로 분리하고 난 뒤에는 페이지를 계속 이동해도 마운트가 일어나지 않았다!
UI 와 비즈니스 로직 분리
다음으로는 채팅 부분의 비즈니스 로직을 커스텀 훅으로 분리해줬다!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { useState, useEffect, useRef, FormEvent } from "react";
import { useUser } from "@/provider/UserContextProvider";
import { createClient } from "@/utils/supabase/client";
import { MessageRow } from "@/types/chats/Chats.type";
const useChat = () => {
const { user } = useUser();
const [messages, setMessages] = useState<MessageRow[]>([]);
const [inputValue, setInputValue] = useState<string>("");
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const chatContentDiv = useRef<HTMLDivElement>(null);
useEffect(() => {
const supabase = createClient();
const getAllMessages = async () => {
const { data: messages, error } = await supabase
.from("Messages")
.select(`*, Users (nickname, profile_image_url)`)
.order("sent_at", { ascending: true });
if (error) {
console.error(error);
return;
}
setMessages(messages as MessageRow[]);
if (chatContentDiv.current) {
requestAnimationFrame(() => {
chatContentDiv.current!.scrollTop =
chatContentDiv.current!.scrollHeight;
});
}
};
getAllMessages();
const openTalkSubscription = supabase
.channel("openTalk")
.on(
"postgres_changes",
{
event: "INSERT",
schema: "public",
table: "Messages"
},
() => {
getAllMessages();
}
)
.on(
"postgres_changes",
{
event: "DELETE",
schema: "public",
table: "Messages"
},
() => {
getAllMessages();
}
)
.subscribe();
return () => {
openTalkSubscription.unsubscribe();
};
}, []);
const handleSubmit = async (evt: FormEvent<HTMLFormElement>) => {
evt.preventDefault();
if (!user) return;
const supabase = createClient();
const { error } = await supabase
.from("Messages")
.insert({
channel_id: "214322ba-1cbd-424c-9ef1-e4b281f71675", // 예제에서는 하드코딩된 채널 ID 사용
user_id: `${user.id}`,
content: inputValue
})
.select("*");
if (error) {
console.error("에러: ", error);
return;
}
setInputValue("");
};
const handleDelete = async (message_id: string) => {
const supabase = createClient();
const { error } = await supabase
.from("Messages")
.delete()
.eq("message_id", message_id);
if (error) {
console.error("에러: ", error);
return;
}
};
return {
user,
messages,
inputValue,
setInputValue,
isModalOpen,
setIsModalOpen,
chatContentDiv,
handleSubmit,
handleDelete
};
};
export default useChat;
여기 useChat
이라는 hook 을 하나 만들어 UI 와 비즈니스 로직을 분리해냈다!
이번엔 여기까지!
This post is licensed under CC BY 4.0 by the author.