如何正确设置键盘事件侦听器发送消息?

发布于 2025-02-05 09:17:06 字数 3676 浏览 1 评论 0原文

我正在写一个小的聊天应用,我遇到了一些困难。应用程序正常工作,但我想设置键入事件侦听器以跟踪用户按下 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]) 

如果我用handlesendMessageusecallback也发生了同样的情况。 >挂钩并放置[用户,值,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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

所有深爱都是秘密 2025-02-12 09:17:06

我不小心解决了这个问题。我以错误的方式思考试图设置keydown useffect钩子中的事件侦听器。

我要做的就是在&lt; input /&gt; < /code>元素中设置自定义事件:

<input
    placeholder="Enter your message..."
    value={value}
    onChange={e => setValue(e.target.value)}
    onKeyDown={handleKeyDown} //this one
/> 

然后添加一个处理程序:

function handleKeyDown(e) {
    if (e.key === 'Enter') {
        if (value) {
            handleSendMessage()
        }   
    }
}

现在一切正常,我最终可以通过按来发送消息。在没有任何副作用的情况下输入键!

I've accidentally solved this problem. I was thinking in a wrong way trying to set keydown event listener in useEffect hook.

All I had to do is to set custom event in <input /> element like this:

<input
    placeholder="Enter your message..."
    value={value}
    onChange={e => setValue(e.target.value)}
    onKeyDown={handleKeyDown} //this one
/> 

And then add a handler:

function handleKeyDown(e) {
    if (e.key === 'Enter') {
        if (value) {
            handleSendMessage()
        }   
    }
}

Now everything's working just fine and I can finally send messages by pressing Enter key without any side-effects!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文