React聊天消息默认滚动到底部无滚动动画问题求助
解决聊天页面默认滚动到底部的可见动画问题
核心问题分析
当前实现存在两个关键问题导致滚动动画可见:
- 使用
behavior: 'smooth'触发平滑滚动,产生了可见的滚动过程 loading状态切换时机与DOM渲染顺序不匹配,导致消息先显示在顶部再触发滚动
具体解决方案
1. 改为瞬间滚动,移除平滑动画
修改scrollToBottom函数,将滚动行为设置为auto(默认值,瞬间完成滚动,无动画):
const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: 'auto' }); };
2. 优化加载状态的视觉隐藏逻辑
通过CSS在加载阶段隐藏消息容器,避免消息顶部提前暴露:
- 给容器添加加载状态类:
<div className={`chat-messages ${loading ? 'chat-messages--loading' : ''}`}>
- 在
chat-messages.scss中补充对应样式:
.chat-messages--loading { visibility: hidden; overflow: hidden; height: 0; }
3. 避免不必要的useLayoutEffect重复触发
当前messages变量每次渲染都会重新创建,导致useLayoutEffect反复执行。用useMemo缓存消息数组:
import { useRef, useLayoutEffect, useState, useContext, useMemo } from 'react'; // ... const messages = useMemo(() => Array.from({ length: 10 }).reverse(), []);
4. 调整状态更新时机,确保滚动完成后再显示内容
用requestAnimationFrame保证滚动完成后再关闭加载状态,让用户直接看到底部的消息:
useLayoutEffect(() => { scrollToBottom(); requestAnimationFrame(() => { setLoadingMessages(false); }); }, [messages]);
最终修改后的完整代码
'use client'; import '@styles/chat-messages.scss'; import ChatMessage from '@components/chat-message'; import Spinner from '@components/spinner'; import { LoadingContext } from '@components/providers/LoadingProvider'; import { useRef, useLayoutEffect, useState, useContext, useMemo } from 'react'; export default function ChatMessages() { const [loading, setLoadingMessages] = useState(true); // const {setLoading} = useContext(LoadingContext); const messages = useMemo(() => Array.from({ length: 10 }).reverse(), []); const messagesEndRef = useRef<HTMLDivElement>(null); const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: 'auto' }); }; useLayoutEffect(() => { scrollToBottom(); requestAnimationFrame(() => { setLoadingMessages(false); }); }, [messages]); return ( <div className={`chat-messages ${loading ? 'chat-messages--loading' : ''}`}> { !loading && ( messages.map((_, index) => ( <ChatMessage key={index} i={index} /> )) ) } { loading && ( <Spinner /> ) } <div ref={messagesEndRef} className='chat-messages__point'></div> </div> ); }
内容的提问来源于stack exchange,提问作者Eugene
相关产品推荐
相关产品推荐

