【发布时间】:2022-06-18 23:29:24
【问题描述】:
我正在编写一个小型 聊天应用程序,但遇到了一些困难。应用程序正常工作,但我想设置 keydown 事件监听器来跟踪用户何时按下 Enter 以便他也可以通过这种方式发送消息(而不仅仅是手动单击 发送消息按钮)。
我使用 Firebase 和 firestore 作为数据库来保存消息。下面是 Chat.jsx 组件的完整代码:
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
谈到问题 - 当我尝试通过 useEffect 设置事件侦听器时,每当我按下 Enter 时,它会发送两个空消息,然后是一个像这样的几条消息:
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])
如果我用useCallback 钩子包裹handleSendMessage 并将[user, value, firestore] 放入deps,也会发生同样的情况。
问题:如何解决此问题并正确设置keydown 事件侦听器以通过按Enter 发送消息?
【问题讨论】:
标签: javascript reactjs firebase event-handling use-effect