[RAPID-fix] 스크롤 sentinel 방식으로 교체: scrollIntoView useLayoutEffect (페인트 전 보장)
This commit is contained in:
@@ -23,7 +23,7 @@ export function ChatPanel({ room }: ChatPanelProps) {
|
||||
const { emitTypingStart, emitTypingStop, typingUsers } = useMessengerSocket();
|
||||
const scrollRef = useRef<HTMLDivElement>(null);
|
||||
const [isAtBottom, setIsAtBottom] = useState(true);
|
||||
const [scrollReady, setScrollReady] = useState(false);
|
||||
const bottomRef = useRef<HTMLDivElement>(null);
|
||||
const [isEditingName, setIsEditingName] = useState(false);
|
||||
const [editName, setEditName] = useState("");
|
||||
const editInputRef = useRef<HTMLInputElement>(null);
|
||||
@@ -36,22 +36,14 @@ export function ChatPanel({ room }: ChatPanelProps) {
|
||||
|
||||
const lastMessageId = messages?.[messages.length - 1]?.id;
|
||||
|
||||
// useLayoutEffect: fires before browser paint → hide + scroll synchronously
|
||||
// Scroll to bottom: sentinel scrollIntoView before paint (no visible jump)
|
||||
useLayoutEffect(() => {
|
||||
const el = scrollRef.current;
|
||||
if (!el) return;
|
||||
setScrollReady(false);
|
||||
el.scrollTop = el.scrollHeight;
|
||||
// Reveal after scroll is applied
|
||||
requestAnimationFrame(() => setScrollReady(true));
|
||||
bottomRef.current?.scrollIntoView();
|
||||
}, [selectedRoomId, lastMessageId]);
|
||||
|
||||
// Second pass: re-scroll after async images load
|
||||
// Second pass for async image loads
|
||||
useEffect(() => {
|
||||
const t = setTimeout(() => {
|
||||
const el = scrollRef.current;
|
||||
if (el) el.scrollTop = el.scrollHeight;
|
||||
}, 600);
|
||||
const t = setTimeout(() => { bottomRef.current?.scrollIntoView(); }, 600);
|
||||
return () => clearTimeout(t);
|
||||
}, [lastMessageId, selectedRoomId]);
|
||||
|
||||
@@ -167,7 +159,7 @@ export function ChatPanel({ room }: ChatPanelProps) {
|
||||
</div>
|
||||
|
||||
{/* Messages */}
|
||||
<div ref={scrollRef} className={`flex-1 min-h-0 overflow-y-auto relative${scrollReady ? "" : " invisible"}`}>
|
||||
<div ref={scrollRef} className="flex-1 min-h-0 overflow-y-auto relative">
|
||||
<div className="pt-2">
|
||||
{messages?.map((msg, idx) => (
|
||||
<div key={msg.id}>
|
||||
@@ -196,6 +188,7 @@ export function ChatPanel({ room }: ChatPanelProps) {
|
||||
<div className="px-4 h-5 flex items-center text-xs text-muted-foreground">
|
||||
{roomTyping && roomTyping.length > 0 ? `${roomTyping.join(", ")}님이 입력 중...` : ""}
|
||||
</div>
|
||||
<div ref={bottomRef} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user