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?
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()
}
You can use a combination of onFocus, onBlur, and onMouseLeave, in such a way that when onFocus happens, he is writing, when onBlur happens, he is not writing anymore, and when onMouseLeave happens or when he clicks on send, you trigger onBlur yourself. Like below:
I assumed that your
Inputcomponent 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()}
onMouseLeave={() => inputRef?.current.blur()}
placeholder="Type a message here"
/>
<Button onClick={()=>{sendMessage(); inputRef?.current.blur()}} icon={<SendOutlined />} />
</div>
);
};
export default ChatInput;
stoppedTyping event.
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={() => !isTyping && setIsTyping(true)}
onKeyUp={() => {
setTimeout(() => {
setIsTyping((t) => t ? false : t)
}, 1000)
}}
onChange={
(e) => typingMessage(e.target.value)
}
placeholder="Type a message here"
/>
<button
onClick={sendMessage}
>send</button>
<pre>{
JSON.stringify({ message, isTyping })
}</pre>
</div>
);
}