如何正确设置键盘事件侦听器发送消息?
我正在写一个小的聊天应用,我遇到了一些困难。应用程序正常工作,但我想设置键入
事件侦听器以跟踪用户按下 enter ,以便他也可以以这种方式发送消息(不仅是手动单击 send消息按钮)。
我正在使用 firebase 和 firestore 作为保存消息的DB。这是 chat.jsx component的完整代码:
import { useAuthState } from 'react-firebase-hooks/auth'
import { FirebaseContext } from '..'
import { useCollectionData } from 'react-firebase-hooks/firestore'
import firebase from 'firebase/compat/app'
import Loader from './loader/Loader'
import { generateRandomKey } from '../helpers/generateRandomKey'
const Chat = () => {
const { auth, firestore } = useContext(FirebaseContext)
const [user] = useAuthState(auth)
const [value, setValue] = useState('')
const [messages, loading] = useCollectionData(
firestore.collection('messages').orderBy('createdAt')
)
const handleSendMessage = async () => {
firestore.collection('messages').add({
uid: user.uid,
displayName: user.displayName,
photoURL: user.photoURL,
text: value,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
})
setValue('')
} // useCallback?
useEffect(() => {
document.body.addEventListener('keydown', e => {
if (e.key === 'Enter') {
handleSendMessage()
}
})
return () =>
document.body.removeEventListener('keydown', e => {
if (e.key === 'Enter') {
handleSendMessage()
}
})
}, []) // what to put in deps?
if (loading) return <Loader />
return (
<div className="content">
<div>
{messages.map(message => {
return (
<div key={generateRandomKey()}>
<div>
<img
src={message.photoURL}
alt="User avatar"
/>
<p>{message.displayName}</p>
</div>
<p>{message.text}</p>
</div>
)
})}
</div>
<div>
<input
placeholder="Enter your message..."
value={value}
onChange={e => setValue(e.target.value)}
></input>
<button onClick={handleSendMessage}>Send message</button>
</div>
</div>
)
}
export default Chat
谈论问题 - 当我尝试通过使用
设置事件侦听器时handlemessage
依赖关系每当我按 Enter 时,它会发送两个空消息,然后发送几条类似的消息:
消息:'Hello'' - &gt; ' - '' - 'h' - 'He' - 'hel' - 'Hell' - 'Hello'
,
useEffect(() => {
document.body.addEventListener('keydown', e => {
if (e.key === 'Enter') {
handleSendMessage()
}
})
return () =>
document.body.removeEventListener('keydown', e => {
if (e.key === 'Enter') {
handleSendMessage()
}
})
}, [handleSendMessage])
如果我用handlesendMessage
用usecallback
也发生了同样的情况。 >挂钩并放置[用户,值,firestore]
in Deps。
问题:如何修复此操作并正确设置keydown
事件侦听器通过按下 Enter 发送消息?
I am writing a small chat app and I ran up into some difficulties. App is properly working but I want to set keydown
event listener to track when user presses Enter so he can also send message this way (not just manually clicking the Send message button).
I am using Firebase and firestore as a DB to save messages. Here is the full code of Chat.jsx component:
import { useAuthState } from 'react-firebase-hooks/auth'
import { FirebaseContext } from '..'
import { useCollectionData } from 'react-firebase-hooks/firestore'
import firebase from 'firebase/compat/app'
import Loader from './loader/Loader'
import { generateRandomKey } from '../helpers/generateRandomKey'
const Chat = () => {
const { auth, firestore } = useContext(FirebaseContext)
const [user] = useAuthState(auth)
const [value, setValue] = useState('')
const [messages, loading] = useCollectionData(
firestore.collection('messages').orderBy('createdAt')
)
const handleSendMessage = async () => {
firestore.collection('messages').add({
uid: user.uid,
displayName: user.displayName,
photoURL: user.photoURL,
text: value,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
})
setValue('')
} // useCallback?
useEffect(() => {
document.body.addEventListener('keydown', e => {
if (e.key === 'Enter') {
handleSendMessage()
}
})
return () =>
document.body.removeEventListener('keydown', e => {
if (e.key === 'Enter') {
handleSendMessage()
}
})
}, []) // what to put in deps?
if (loading) return <Loader />
return (
<div className="content">
<div>
{messages.map(message => {
return (
<div key={generateRandomKey()}>
<div>
<img
src={message.photoURL}
alt="User avatar"
/>
<p>{message.displayName}</p>
</div>
<p>{message.text}</p>
</div>
)
})}
</div>
<div>
<input
placeholder="Enter your message..."
value={value}
onChange={e => setValue(e.target.value)}
></input>
<button onClick={handleSendMessage}>Send message</button>
</div>
</div>
)
}
export default Chat
Speaking about problems - when I am trying to set event listener via useEffect
with handleMessage
dependency whenever I press Enter it sends two empty messages and then a couple of messages like this:
message: 'hello' -> '' - '' - 'h' - 'he' - 'hel' - 'hell' - 'hello'
useEffect(() => {
document.body.addEventListener('keydown', e => {
if (e.key === 'Enter') {
handleSendMessage()
}
})
return () =>
document.body.removeEventListener('keydown', e => {
if (e.key === 'Enter') {
handleSendMessage()
}
})
}, [handleSendMessage])
Same happens if I wrap handleSendMessage
with useCallback
hook and put [user, value, firestore]
in deps.
Question: How can I fix this and properly set keydown
event listener to send messages via pressing Enter?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我不小心解决了这个问题。我以错误的方式思考试图设置
keydown
useffect
钩子中的事件侦听器。我要做的就是在
&lt; input /&gt; < /code>元素中设置自定义事件:
然后添加一个处理程序:
现在一切正常,我最终可以通过按来发送消息。在没有任何副作用的情况下输入键!
I've accidentally solved this problem. I was thinking in a wrong way trying to set
keydown
event listener inuseEffect
hook.All I had to do is to set custom event in
<input />
element like this:And then add a handler:
Now everything's working just fine and I can finally send messages by pressing Enter key without any side-effects!