Reputation: 2470
The code below shows user is typing when someone starts typing on the form input.
Below is what am trying to accomplish now:
How do I add timeout like 5 seconds so that the applications can only show user typing alert only for 5 seconds whenever user starts typing in a form inputs (just like in chat typing notification).
I guess it has to do with timeout function like code below:
setTimeout(()=>{
this.sate.data
},5000);
Is there a better approach to this?
Here is the code so far:
class App extends React.Component {
constructor(props) {
super(props)
this.state = { data: [], email: '' };
this.handleChange1 = this.handleChange1.bind(this);
this.onKeyPressed = this.onKeyPressed.bind(this);
}
handleChange1(event) {
this.setState({ [event.target.name]: event.target.value });
}
onKeyPressed(event) {
console.log(event.key);
this.setState({
data: [{ id: '1', name: 'Tony' }]
});
}
render() {
return (
<div>
<h1>Display User is Typing.....</h1>
<label>
<input
onKeyDown={event => this.onKeyPressed(event)}
value={this.state.email}
onChange={this.handleChange1}
name="email"
/>
</label>
<ul>
{this.state.data.map((person, i) => {
if (person.id == 1) {
console.log('am typing.......');
return (
<div key={i}>
<div>{person.name} is typing.....</div>
</div>
);
}
})}
</ul>
</div>
);
}
}
Upvotes: 1
Views: 3565
Reputation: 21
Here is a version of the Hooks version of this answer... I found the answer very useful
import { useState } from "react";
import { Form, Button, FormControl, InputGroup } from "react-bootstrap";
import debounce from "lodash/debounce";
const SendMessageForm = ({ sendMessage, messages }) => {
const [message, setMessage] = useState("");
const [isTyping, setIsTyping] = useState(false);
// const [currentUserTyping, setCurrentUserTyping] = useState("");
// useEffect(() => {
// checkUserTyping();
// }, [messages]);
const handleIsTyping = debounce(function () {
// continually delays setting "isTyping" to false for 500ms until the user has stopped typing and the delay runs out
setIsTyping(false);
}, 500);
// const checkUserTyping = () => {
// const user = messages.map((m) => m.user);
// setCurrentUserTyping(user);
// console.log(user);
// };
return (
<Form
onSubmit={(e) => {
e.preventDefault();
sendMessage(message);
setMessage("");
}}
>
<InputGroup>
<FormControl
type="user"
placeholder="message..."
onChange={(e) => {
setMessage(e.target.value);
setIsTyping(true);
handleIsTyping();
}}
name="message"
value={message}
/>
<span className="user-typing">
{isTyping && `a user is typing....`}
</span>
<InputGroup.Append>
<Button variant="primary" type="submit" disabled={!message}>
Send
</Button>
</InputGroup.Append>
</InputGroup>
</Form>
);
};
export default SendMessageForm;
Upvotes: 2
Reputation: 19782
You can use lodash's debounce function, which will delay an action for a specified amount of ms
. For example, if a user is typing, it'll continually reset the delay. When the user stops typing, the delay runs out and triggers the action. (also, please read my note below the example code)
You can scale up the example below to include the user's name by mapping over your data
in a container and passing it down to a reusable component.
Working example: https://codesandbox.io/s/j3n6q98m0w
components/App/App.js
import debounce from "lodash/debounce";
import React, { Component } from "react";
export default class App extends Component {
constructor() {
super();
this.state = { isTyping: false, test: "" };
this.handleChange = this.handleChange.bind(this);
}
handleChange({ target: { name, value } }) {
this.setState({ isTyping: true, [name]: value }, () => { // allows user input updates and continually sets "isTyping" to true
this.handleTyping();
});
}
handleTyping = debounce(function() { // continually delays setting "isTyping" to false for 500ms until the user has stopped typing and the delay runs out
this.setState({ isTyping: false });
}, 500);
render() {
return (
<div className="app-container">
<h1>Capturing User Input</h1>
<input
className="uk-input"
placeholder="Type something..."
type="text"
name="test"
value={this.state.test}
onChange={this.handleChange}
/>
<p className="user-typing">
{this.state.isTyping && "User is typing..."}
</p>
</div>
);
}
}
Note: You don't need to create an anonymous function inside the render
method:
onKeyDown={(event) => this.onKeyPressed(event)}
Instead, it'll just be:
onKeyDown={this.onKeyPressed}
By default onKeyDown
sends an event
to the callback onKeyPressed
:
onKeyPressed(e){
console.log(e.keyCode);
}
The only time you'll need to create an anonymous function is when you want to include a value in addition to the event
:
onKeyDown={(event) => this.onKeyPressed(event, this.state.value)}
Then your callback onKeyPressed
will accept two parameters:
onKeyPressed(e, val){
console.log(e.keyCode);
console.log(val);
}
Upvotes: 1