Slack(์ฌ๋) ์๋น์ค๋ฅผ ๋ฐ๋ผ ๋ง๋ค๋ Reacr Web ๊ฐ๋ฐ
โ ํด๋น ๊ฐ์๋ฅผ ์๊ฐ ํ ์์ฑํ ๋ณต์ต ๋ฐ ๊ฐ์ธ ์คํฐ๋ ๊ธฐ๋ก์ ๋๋ค.
Socket.io ? ๐ค
Websocket์ ๊ธฐ๋ฐ์ผ๋ก ์ค์๊ฐ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ JavaScript ๋ผ์ด๋ธ๋ฌ๋ฆฌ
์น ํด๋ผ์ด์ธํธ์ ์๋ฒ ๊ฐ์ ์ค์๊ฐ ์๋ฐฉํฅ ํต์ ์ ๊ฐ๋ฅํ๊ฒ ํด์ฃผ๋ Node.js์ ๋ชจ๋์ด๋ค.
Websocket ? ๐ค
์น์์ผ์ ๋ฐ์ดํฐ๊ฐ ๋๋ฝ๋์ง ์๊ฒํ๋ tcp๊ธฐ๋ฐ์ ์๋ฐฉํฅํต์ ์ ์ ๊ณตํ๋ ์ปดํจํฐ ํ๋กํ ์ปฌ
npm i socket.io-client@2
socket.io ์ค์นbackUrl
Url์ ๊ด๋ จํด์ ๋ฐ๋ก ๋ณ์๋ก ์ค์ ํด ๋์์ผ ์์ ์ด ์ฉ์ดํ๋ค.[workspace]
workspace๋ฅผ namespace ๋ก ์ง์ ํ์ฌ ํต์ disconnect
ํด๋ผ์ด์ธํธ์์ ์ฐ๊ฒฐ์ด ๋์ด์ก์ ๋ ๋ฐ์์๋ฒ์ ํด๋ผ์ด์ธํธ๊ฐ ์ฐ๊ฒฐ๋๋ฉด ์ค์๊ฐ ๋ฐ์ดํฐ ๊ณต์ ๊ฐ ๊ฐ๋ฅํ๋ฐ,ย socket์ ๊ทธ๋ฅ ์ฌ์ฉํ๋ฉด ๋ฐ์ดํฐ๊ฐ ๋ชจ๋ socket์ผ๋ก ๋ค์ด๊ฐ๊ฒ ๋๋ค.
์ฌ๋ - ํด๋น ์ํฌ์คํ์ด์ค์๋ง ํด๋นํ๋ ํน์ ๋ฐ์ดํฐ๋ง ๋ฐ์์ผ ํ๋ฏ๋ก Namespace ์ฌ์ฉํด ํต์ ์ ํ๋ค.
Namespace ? ๐ค
Express์ ๋ผ์ฐํ ์ฒ๋ผ url์ ์ง์ ๋ ์์น์ ๋ฐ๋ผ ์ ํธ์ ์ฒ๋ฆฌ๋ฅผ ๋ค๋ฅด๊ฒ ํ๋ ๊ธฐ์
๋ง ๊ทธ๋๋ก ์ด๋ฆ์ด ๋ถ์ ๊ณต๊ฐ์ด๋ฉฐ, ์์ผ์ ๋ฌถ์ด์ฃผ๋ ๋จ์๋ผ๊ณ ์๊ฐํ๋ฉด ๋๋ค.
!sockets[workspace]
๊ธฐ์กด์ ์ฐ๊ฒฐ ๋ฐ์ดํฐ ๊ฐ์ด ์์ ๊ฒฝ์ฐ ๊ธฐ์กด ๋ฐ์ดํฐ return ํ๋๋ก ํ๋ค.
transports
websocket์ผ๋ก ์ค์ ํ๋ฉด polling ๋ฐฉ์์ ์ฌ์ฉํ์ง ์๊ฒ ๋๋ค.
sid
socket id
์์ ์ซ์๋ ping-pong์ผ๋ก ์ฐ๊ฒฐ์ด ์ ์ ์ง๋๊ณ ์๋ socket.io๊ฐ ํ์ธํ๋ ๊ฒ์ด๋ค.
onlineList
๋ฅผ ํตํด ์ ์ํด์๋ ์ ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ ์ฌ ์ ์๋ค.
npm install react-custom-scrollbars
react-custom-scrollbars ์ค์น
autoHide
์คํฌ๋กค ๊ธฐ๋ฅ์ ์ํ ์ ํ๋ฉด์์ ์ฌ๋ผ์ง๊ฒํจ
npm install dayjs
dayjs ์ค์น (๋ ์ง ํ์ ๊ด๋ จ ๋ผ์ด๋ธ๋ฌ๋ฆฌ)format
์ผ๋ก ์ํ๋ ํ์์ ๋ ์ง ํ๊ธฐ๋ก ๋ณ๊ฒฝํ๋ค.npm install react-mentions
react-mentions ์ค์น
trigger
: ๋ฉ์
ํ์ฑํ ํธ๋ฆฌ๊ฑฐappendSpaceOnAdd
์ปค์ ๋ค์์ ํ์นธ ์ฌ๋ฐฑ ๋์ด์ฃผ๋ ๊ธฐ๋ฅrenderSuggestion
: ๋ฉ์
ํ ๋์ด์ ธ ์๋ ์ฐฝ์ ๋ ๋๋ฅผ ์ค์ ํ๋ ๊ธฐ๋ฅ๋ฉ์ ์ผ๋ก ์ ๋ ฅํ์ฌ ๋ฌ ID๋ฅผ style์ ์ง์ ํ์ฌ ๊ตฌ๋ถํ๋ค.
npm i regexify-string
regexify-string ์ค์น (์ ๊ทํํ์ ๊ด๋ จ ๋ผ์ด๋ธ๋ฌ๋ฆฌ)
pattern: /@[(.+?)]((\d+?))|\n/g
makeSection
๊ณตํต ํจ์ ์์
Object.entries(chatSections)
๊ฐ์ฒด๋ฅผ [ํค, ๊ฐ] ํํ์ ๋ฐฐ์ด๋ก ๋ณ๊ฒฝStickyHeader
position: sticky๋ฅผ ํ์ฉํ์ฌ ๋ ์ง ํ๊ธฐ ์ปดํฌ๋ํธ๊ฐ ์๋จ์ ๋ถ๋๋ก ๊ณ ์ ํด๋๋๋ค.์คํฌ๋กค์ ์ต์๋จ์ผ๋ก ์ฌ๋ ค ์ฑํ ๋ฐ์ดํฐ ๋ถ๋ฌ์ฌ ์ ๋ฌดํ ์คํฌ๋กค ์ ์ฉ ์์
onScrollFrame
๋ฐ์ดํฐ์์ ์คํฌ๋กค๋ฐ ์์น๋ฅผ ๋ฐ์์จ๋ค.forwardRef
Ref๋ฅผ ๋ค๋ฅธ ์ปดํฌ๋ํธ๋ก ์ ๋ฌํ ๋ ์ฌ์ฉํ ์ ์๋ค.useSWR
๊ณผ ๋ค๋ฅด๊ฒ ์ฒซ๋ฒ์งธ ์ธ์๊ฐ ํจ์๋ก ๋ณ๊ฒฝ๋๋ค.index
ํ์ด์ง ์ setSize
ํ์ด์ง ์๋ฅผ ๋ณ๊ฒฝํด์ค๋ค.isEmpty
: ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ์์ฒญ ์ ๋ฐ์ดํฐ๊ฐ ๋น์ด์๋ ๊ฒฝ์ฐ
isReachingEnd
: ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ์์ฒญ ์ ์ํ๋ ๋ฐ์ดํฐ์ ์๋ ์๋์ง๋ง ์์ฌ ๋ฐ์ดํฐ๊ฐ ์๋ ๊ฒฝ์ฐ
scrollbarRef.current?.scrollToBottom();
์ฑํ
๋ฐ์ดํฐ๊ฐ ์์ด์ ๋ถ๋ฌ์ค๋ ๊ฒฝ์ฐ์๋ ๋ก๋ฉ ์ ์คํฌ๋กค ๋ฐ๊ฐ ๊ฐ์ฅ ํ๋จ์ผ๋ก ์์นํ๋๋ก ํ๋ค.
onSubmitForm
์ฑํ
์ ๋ณด๋ธ ํ์๋ ๊ฐ์ฅ ํ๋จ์ผ๋ก ์์น
์ฑํ ์ ๋ ฅ ํ ์คํฌ๋กค์ด ํ๋จ์ ๋ด๋ ค์ค๊ธฐ ๊น์ง ์ฝ๊ฐ์ delay ์์
์ฌ์ฉ์ ๊ฒฝํ์ ์ํด mutateChat
๋ฅผ ์ฌ์ฉํ์ฌ axios ์์ฒญ ์ ๋ฐ์ดํฐ๊ฐ ๋ฐ์๋์ด ํ๋ฉด์ ๋ํ๋๋ก ์ตํฐ๋ฏธ์คํฑ UI (Optimistic UI) ๋ฅผ ์ ์ฉํ์๋ค.
๋ฐ์ดํฐ๋ฅผ ๋ ๋ถ๋ฌ ์ฌ ๋ ์คํฌ๋กค๋ฐ์ ์์น๋ฅผ ์ ์งํ ์ ์๋๋ก ํ๋ค.
current.scrollTop(current.getScrollHeight() - values.scrollHeight);
์คํฌ๋กค๋ฐ์ ์์น ์ ์งํ๊ธฐ :
์ง๊ธ ํ์ฌ ์คํฌ๋กค๋ฐ ์์น - ์คํฌ๋กค๋ฐ์ hegiht
socket.io
์ฐ๊ฒฐmutateChat
socket.io๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ค์๊ฐ์ผ๋ก ์ ๋ฌํด์ฃผ๊ธฐ ๋๋ฌธ์ mutateChat ์ฌ์ฉ
scrollbarRef.current.getScrollHeight() < scrollbarRef.current.getClientHeight() + scrollbarRef.current.getScrollTop() + 150
์คํฌ๋กค๋ฐ๋ฅผ ์๋จ์ ์ฌ๋ฆด ์(150px ์ ๋ ์ด์์ผ๋ก ์คํฌ๋กค ๋ฐ๋ฅผ ์ฌ๋ ธ์ ๋) ์๋๋ฐฉ์ด ์ฑํ
์ ๋ณด๋ผ ๋๋ ์คํฌ๋กค๋ฐ๊ฐ ์๋๋ก ๋ด๋ ค๊ฐ์ง ์๋๋ก ์์
https://jangstory.tistory.com/12
https://inpa.tistory.com/entry/SOCKET-%F0%9F%93%9A-Namespace-Room-%EA%B8%B0%EB%8A%A5