React中如何追踪输入框用户停止输入(10秒无输入判定)
输入停止状态追踪实现方案
核心逻辑通过防抖计时实现:只要用户触发输入操作,就重置10秒倒计时,倒计时走完且期间没有新输入时,判定为停止输入。
具体实现步骤
- 用
useRef存储定时器ID,保证跨组件重渲染周期能拿到正确的定时器引用,避免普通变量因重渲染重置导致的定时器清除失效问题 - 每次输入事件触发时:
- 先清除上一轮未执行完的停止输入定时器
- 正常发送「正在输入」状态给服务端,同步更新输入框的value值
- 启动新的10秒定时器,定时器触发时发送「停止输入」状态给服务端
- 增加两个边界场景处理:
- 组件卸载时清除未执行的定时器,避免内存泄漏
- 点击发送按钮提交消息时,立刻清除定时器、上报停止输入状态,避免消息发完后还残留输入状态
改造后完整代码
import { useState, useRef, useEffect } from 'react'; import { Input, Button } from 'antd'; import { SendOutlined } from '@ant-design/icons'; const ChatInput = (props) => { const [message, setMessage] = useState(''); // 存储停止输入定时器ID const stopTypingTimer = useRef(null); // 组件卸载时清理定时器 useEffect(() => { return () => { if (stopTypingTimer.current) { clearTimeout(stopTypingTimer.current); } }; }, []); const typingMessage = (inputValue) => { // 每次输入先清除之前的定时器,重置倒计时 if (stopTypingTimer.current) { clearTimeout(stopTypingTimer.current); } // 发送正在输入状态 socket.emit('typing', props.username); // 启动新的10秒倒计时 stopTypingTimer.current = setTimeout(() => { // 10秒无新输入,发送停止输入状态 socket.emit('stop_typing', props.username); }, 10000); }; const sendMessage = () => { if (!message.trim()) return; // 发送消息的原有逻辑 socket.emit('send_message', { username: props.username, content: message.trim() }); // 发完消息立刻清除定时器,上报停止输入 if (stopTypingTimer.current) { clearTimeout(stopTypingTimer.current); } socket.emit('stop_typing', props.username); setMessage(''); }; return ( <div className="chat-input-wrapper"> <Input value={message} onChange={(e) => { setMessage(e.target.value); typingMessage(e.target.value); }} placeholder="Type a message here" /> <Button onClick={sendMessage} icon={<SendOutlined />} /> </div> ); };
注意事项
- 不要用普通局部变量存储定时器ID:函数组件每次重渲染都会重置局部变量,会导致无法清除上一轮的定时器,出现多次触发停止输入事件的问题
- 不要把定时器ID存在state里:state更新会触发组件重渲染,存定时器ID属于高频更新的非渲染相关数据,用
useRef是性能最优的选择 - 如果输入框失焦,也可以根据业务需求主动触发停止输入逻辑,和发送消息的处理逻辑一致即可
内容的提问来源于stack exchange,提问作者qwerty
相关产品推荐
相关产品推荐

