ReactTS中Context首次点击未设用户信息,二次点击正常的问题
问题:首次点击用户列表项时,Context中的选中用户未更新,二次点击才生效
开发聊天应用时,点击用户列表项会触发设置选中用户到Context、获取对应消息并展示的逻辑。目前消息获取正常,但首次点击时Context中的选中用户为空,console.log能输出正确的selectedUserInfo,二次点击后Context才会正确设置选中用户。
相关代码
点击处理函数
const handleUserClick = (messsagesID:string, selectedUserInfo:selectedUserProps)=>{ setSelectedUserMessages(selectedUserInfo); console.log(selectedUserInfo); selectMessage(messsagesID); showMessage(); }
Context中的状态更新函数
const setSelectedUserMessages=(selectedUser:selectedUserProps|undefined)=>{ setSelectedUser(selectedUser); }
用户列表渲染
{ Object.entries(messages!)?.map((chat:any)=>( <div key={chat[1].userInfo.uid} className="" onClick={()=>handleUserClick(chat[0],chat[1].userInfo)}> <UserMessage name={chat[1].userInfo.displayName} photoUrl={chat[1].userInfo.photoUrl} message={chat[1].lastMessage.message} /> </div> )) }
问题原因
React的状态更新(包括Context内部的setSelectedUser)是异步批量更新的。在handleUserClick中,调用setSelectedUserMessages后,Context的状态并不会立即更新,此时如果selectMessage或showMessage依赖了Context中刚设置的选中用户,就会读取到旧的空值。二次点击时,上一次的状态更新已完成,所以能获取到正确的用户信息。
解决方案
方案1:使用useEffect监听Context状态变化
将依赖选中用户的逻辑放到useEffect中,当Context的选中用户更新后再执行:
import { useContext, useEffect, useState } from 'react'; import { YourChatContext } from './你的Context路径'; const ChatList = () => { const { selectedUser, setSelectedUserMessages } = useContext(YourChatContext); const [currentMessagesID, setCurrentMessagesID] = useState<string>(''); useEffect(() => { if (selectedUser && currentMessagesID) { selectMessage(currentMessagesID); showMessage(); } }, [selectedUser, currentMessagesID, selectMessage, showMessage]); const handleUserClick = (messagesID:string, selectedUserInfo:selectedUserProps)=>{ setSelectedUserMessages(selectedUserInfo); setCurrentMessagesID(messagesID); console.log(selectedUserInfo); } // 用户列表渲染代码... }
方案2:直接传递用户信息给依赖函数
如果selectMessage和showMessage不需要等待DOM更新,可直接将selectedUserInfo作为参数传入,跳过对Context状态的依赖:
// 修改handleUserClick const handleUserClick = (messagesID:string, selectedUserInfo:selectedUserProps)=>{ setSelectedUserMessages(selectedUserInfo); console.log(selectedUserInfo); // 直接传递用户信息到函数中 selectMessage(messagesID, selectedUserInfo); showMessage(selectedUserInfo); } // 调整selectMessage和showMessage的定义 const selectMessage = (messagesID: string, user: selectedUserProps) => { // 使用传入的user参数,而非从Context读取 } const showMessage = (user: selectedUserProps) => { // 使用传入的user参数,而非从Context读取 }
说明
两种方案的核心都是避免在状态更新的同步流程中依赖未完成更新的状态。方案1适合需要等待DOM或状态完全更新后再执行的逻辑,方案2更简洁,适合逻辑不依赖状态更新后的DOM渲染的场景。
内容的提问来源于stack exchange,提问作者Mat
相关产品推荐
相关产品推荐

