๐ Task TODOLIST
- [x] ์คํฌ๋กคํ div ์ ์ ํ๊ธฐ
- [x] ref ๋ถ์ฌํ๊ธฐ
- [x] onScroll props๋ก ์คํฌ๋กค ํจ์ ๋ฃ๊ธฐ
- [x] ์คํฌ๋กค ๋ค์ดํ๊ธฐ
โจ ๊ฐ๋ฐ ๋ด์ฉ
1. ์คํฌ๋กคํ div ์ ์ ํ๊ธฐ
2. ref ๋ถ์ฌํ๊ธฐ
3. onScroll props๋ก ์คํฌ๋กค ํจ์ ๋ฃ๊ธฐ
How(๊ณผ์ ) ?
(1) ์คํฌ๋กค์ ๊ด์ฌํ๋ ์์๋ค์ด ๋ช ๊ฐ์ง ์์๋๋ฐ, scrollBox๋ฅผ scrollRef ๋ฅผ ์ค ๊ฒ์ current ๊ฐ, ์ฆ scrollRef.current๋ผ๊ณ ํ ๋,
scrollBox.scrollTop
- ์คํฌ๋กค ๋ฐ๊ฐ ํ์ฌ ์ ์ผ ์ต์๋จ์ผ๋ก๋ถํฐ ์ผ๋ง๋ ๋จ์ด์ ธ ์๋์ง
scrollBox.scrollHeight
- ์คํฌ๋กค ๊ฐ๋ฅํ ์์ญ์ ์ ์ฒด ๋์ด
- ๋ด์ฉ์ด ์คํฌ๋กค ๋ฐ์ผ๋ก ๋์น๋ ๊ฒฝ์ฐ ๋ทฐํฌํธ์ ๊ธธ์ด๋ณด๋ค ์ปค์ง ์ ์์ / ํญ์ ์ผ์
scrollBox.clientHeight
- ์ฝํ ์ธ ๊ฐ ๋ณด์ฌ์ง๋ ์์ญ์ ๋์ด
- ๋ทฐํฌํธ
(2) ์ด ์ธ ๊ฐ์ ๊ฐ๋ ๋ค์ ํ์ฉํด์ ํ์ฌ ์คํฌ๋กค ์ค์์
const isScroll = scrollBox.scrollTop < scrollBox.scrollHeight - scrollBox.clientHeight - SCROLL_GAP;
์ด๋ ๊ฒ ํํํ ์ ์๋ค.
์ฌ๊ธฐ์ SCROLL_GAP์ด๋ 5๋ผ๋ ์์์ธ๋ฐ, ์คํฌ๋กค ์ค์ ํ๋จํ๋ ์๊ณ๊ฐ์ผ๋ก ์ฌ์ฉ๋๋ค.
์ฆ, ๋ง์ฝ SCROLL_GAP์ด 0 ์ด๋ผ๋ฉด ์ฌ์ฉ์๊ฐ ์คํฌ๋กค ๋งจ ์๋์ ๋๋ฌํ์ ๋๋ง ์คํฌ๋กค ์ค์ผ๋ก ํ๋จ์ด ๋๋๋ฐ,
๋ด๊ฐ ์ํ๋ ๊ฒ์ ์คํฌ๋กค์ด ๋งจ ์/์๋์ ๋๋ฌํ์ง ์์ ๋๋ฅผ ์คํฌ๋กค ์ค์ผ๋ก ํ๊ณ ์ถ๊ธฐ ๋๋ฌธ์ ์ผ์ ๊ฐ์ ๋นผ๋ ๊ฒ์ด๋ค.
5๊ฐ ์๋ 10 ๋๋ ๊ทธ ์ด์์ผ๋ก ํด๋ ๋๋ค.
(3) ํ์ฌ ๋ด๊ฐ ๋ง๋ ์คํฌ๋กค ํจ์ handleScroll์ scrollRef์ ํจ๊ป ์คํฌ๋กค ํ ์์ญ์ props๋ก ๋๊ธด๋ค.
// ์คํฌ๋กค ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ๋
const handleScroll = () => {
const scrollBox = scrollRef.current;
if (scrollBox) {
const isScroll = scrollBox.scrollTop < scrollBox.scrollHeight - scrollBox.clientHeight - SCROLL_GAP;
setIsScrolling(isScroll);
if (!isScroll) {
setNewAddedMsgNum(0);
}
setIsScrollTop(scrollBox.scrollTop === 0);
}
};
ใด setIsScrollTop์ ์ฑํ ๊ฒ์์ ํ์ํ ์์๋ค.
return (
<>
<div
className={'w-full h-full flex-1 p-[16px] flex flex-col gap-[8px] overflow-y-auto scroll-smooth'}
ref={scrollRef}
onScroll={handleScroll}
>
...
4. ์คํฌ๋กค ๋ค์ด ํ๊ธฐ
Why(์ด์ ) ?
์ฑํ ์ ๋ณด๊ณ ์๋ค๊ฐ ์ตํ๋จ์ผ๋ก ๋ด๋ ค๊ฐ๋ ๋ฒํผ์ ๋ง๋ค๊ณ ์ถ์๋ค.
๋ํ, ์ฑํ ์ ๋ณด๊ณ ์๋ค๊ฐ ์๋ก์ด ๋ฉ์ธ์ง๊ฐ ์ถ๊ฐ๋๋ฉด "์๋ก์ด ๋ฉ์ธ์ง 0๊ฐ ์ถ๊ฐ" ๋ผ๋ ๋ฒํผ๋ ์กฐ๊ฑด๋ถ๋ก ๋ง๋ค๊ณ ์ถ์๋ค.
How(๊ณผ์ ) ?
์์ ์ค๋ช ์ ํ ๋๋ก ์คํฌ๋กค ๋ค์ด์ ๊ตฌํํ๋ค.
scrollTop์ด scrollHeight ์ ๊ฐ์์ง๋ฉด ํ์ฌ ์คํฌ๋กค๋ฐ์ ์์น๊ฐ ์ ์ฒด ๋์ด์ ๊ฐ์์ง๋ฏ๋ก ์คํฌ๋กค ๋ค์ด์ด ๋๋ค.
const handleScrollDown = () => {
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
};
์ด ์คํฌ๋กค ๋ค์ด ํจ์๋ฅผ ์ตํ๋จ์ผ๋ก ๋ด๋ฆฌ๋ ๋ฒํผ์ ์์ฑํด์ props๋ก ๋๊ธด๋ค.
๋๋ 1. ์คํฌ๋กค ์ค์ด๊ณ 2. ์๋ก ์ถ๊ฐ๋ ๋ฉ์ธ์ง ์๊ฐ 0๊ฐ์ธ์ง์ ์กฐ๊ฑด์ผ๋ก
๊ทธ๋ฅ ์คํฌ๋กค ๋ค์ด ๋ฒํผ์ ํ ์ง, ์๋ก์ด ๋ฉ์ธ์ง ์ถ๊ฐ๋ฒํผ์ ํ ์ง ์กฐ๊ฑด๋ถ๋ก ๋ ๋๋งํ๋ค.
{isScrolling ? (
newAddedMsgNum === 0 ? (
<ChatScroll handleScrollDown={handleScrollDown} />
) : (
<NewChatAlert
newAddedMsgNum={newAddedMsgNum}
handleScrollDown={handleScrollDown}
setNewAddedMsgNum={setNewAddedMsgNum}
/>
)
) : (
<></>
)}
const ChatScroll = ({ handleScrollDown }: { handleScrollDown: () => void }) => {
return (
<>
<div className="absolute bottom-28 w-full" id="์คํฌ๋กค ๋ด๋ฆฌ๋ ๋ฒํผ">
<FaArrowCircleDown
className="w-12 h-12 text-[#E4D4F4] mx-auto cursor-pointer hover:scale-105 transition-all ease-in-out animate-bounce"
onClick={handleScrollDown}
/>
</div>
</>
);
};
export default ChatScroll;
const NewChatAlert = ({
newAddedMsgNum,
handleScrollDown,
setNewAddedMsgNum
}: {
newAddedMsgNum: number;
handleScrollDown: () => void;
setNewAddedMsgNum: Dispatch<SetStateAction<number>>;
}) => {
const handleNewMsgAlertScroll = () => {
handleScrollDown();
setNewAddedMsgNum(0);
};
return (
<div className="absolute bottom-28 w-full">
<div className="flex mx-auto w-full cursor-pointer" onClick={handleNewMsgAlertScroll}>
<div className="flex gap-[6px] mx-auto my-auto px-[16px] py-[14px] bg-[#F2EAFA] rounded-lg font-bold text-lg text-mainColor font-semibold">
<div className="my-auto">
<FaChevronDown />
</div>
<h1>{newAddedMsgNum} New Message</h1>
</div>
</div>
</div>
);
};
export default NewChatAlert;
๐จ TroubleShotting
-
๊ทธ๋ด ๋ฏํ ํธ๋ฌ๋ธ์ํ ์ ์์๋ค. ์์ํ ๊ฐ๋ ์ด ์ด๋ ค์ ์ ๋ฟ..
๐ธ ์คํฌ๋ฆฐ์ท
![]() |
![]() |
์คํฌ๋กค ์ค + ์๋ก์ด ๋ฉ์ธ์ง ์ === 0 | ์คํฌ๋กค ์ค + ์๋ก์ด ๋ฉ์ธ์ง๊ฐ ์ถ๊ฐ๋์ ๋ |
![]() |
์คํฌ๋กค ๋ค์ด |
๐ ๋ ํผ๋ฐ์ค
์คํฌ๋กค ๊ฐ๋ ์ ๋ฆฌ๋ฅผ ๋๋ฌด ์ํด๋์ จ๋ค.
https://devbirdfeet.tistory.com/228
์คํฌ๋กค ๋ฐ ๊พธ๋ฏธ๊ธฐ
https://www.geeksforgeeks.org/how-to-change-style-of-scrollbar-using-tailwind-css/