I have such a functional component. When a user enters input, I send a message to the server and output to other users what someone writes. Here is the code:
const ChatInput = (props) => {
const [message, setMessage] = useState('');
const typingMessage = () =>{
socket.emit('typing',props.username);
}
return (
<div className>
<Input
value = {message}
onChange = {
(e) => typingMessage(e.target.value)
}
placeholder="Type a message here"
/>
<Button
onClick={sendMessage}
icon={<SendOutlined />
}/>
</div>
);
};
How do I track that the user has stopped writing? If he does not enter anything into the input for more than 10 seconds?
CodePudding user response:
You need deboune function, that will count 10sec (it may be different time, depends on you) after last input (onChange trigger)
function debounce(func, timeout = 10000){
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => { func.apply(this, args); }, timeout);
};
}
function saveInput(){
console.log('User has stopped writting 10 sec ago');
}
const processChange = debounce(() => saveInput());
const typingMessage = () =>{
socket.emit('typing',props.username);
processChange()
}
CodePudding user response:
You can use a combination of onFocus
, onBlur
, and onMouseLeave
. When onFocus
happens, he is writing. When onBlur
happens, he is not writing anymore. When onMouseLeave
happens or when he clicks on send, you trigger onBlur
with JavaScript. Like below:
I assumed that your
Input
component can forwardref
. If not make it so by following Forwarding Refs.
const ChatInput = (props) => {
const [message, setMessage] = useState("");
const inputRef = useRef();
const typingMessage = () => {
socket.emit("typing", props.username);
};
const notTypingMessage = () => {
socket.emit("typing", "");
};
return (
<div className>
<Input
ref={inputRef}
value={message}
onChange={(e) => setMessage(e.target.value)}
onFocus={() => typingMessage()}
onBlur={() => notTypingMessage()}
onm ouseLeave={() => inputRef?.current.blur()}
placeholder="Type a message here"
/>
<Button onClick={()=>{sendMessage(); inputRef?.current.blur()}} icon={<SendOutlined />} />
</div>
);
};
export default ChatInput;
CodePudding user response:
- This is a one solution waiting for a second after finish typing and emits
stoppedTyping
event. - you may still want to optimize it according to the your applications needs
const emit = (action, data) => {
console.log(action, data)
}
function App() {
const props = { username: 'me' }
const [message, setMessage] = useState('');
const [isTyping, setIsTyping] = useState(false);
useEffect(() => {
if (message && !isTyping) {
emit('stoppedTyping', props.username)
}
}, [isTyping])
const typingMessage = (v) => {
emit('typing', props.username);
setMessage(v)
}
const sendMessage = (e) => {
console.log(e)
}
return (
<div className=''>
<input
value={message}
onKeyDown={() => setIsTyping(true)}
onKeyUp={() => {
setTimeout(() => {
setIsTyping(false)
}, 1000)
}}
onChange={
(e) => typingMessage(e.target.value)
}
placeholder="Type a message here"
/>
<button
onClick={sendMessage}
>send</button>
<pre>{
JSON.stringify({ message, isTyping })
}</pre>
</div>
);
}