Monday, May 20, 2024
 Popular · Latest · Hot · Upcoming
58
rated 0 times [  61] [ 3]  / answers: 1 / hits: 20800  / 7 Years ago, sun, december 31, 2017, 12:00:00

I don't want to fire requests as long as the user is typing. My code should throttle requests so that when the user types quickly, it will fire one request with the latest input value instead of many.



For now when I'm typing test it fires 4 different requests:




  1. t

  2. te

  3. tes

  4. test



So I found lodash _.debounce and _.throttle ( [https://lodash.com/docs/4.17.4#debounce] ) but don't really understand how I can inplement it to my code. Can anyone help me?



My code:



import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import './style.css';

import { search } from '../../actions/';

class SearchBar extends Component {
constructor(props) {
super(props);
this.state = { searchTerm: '' };
}

startSearch(query) {
const storedTerms = this.props.searchedTerm;
let foundDuplicate = false;

if (storedTerms.length === 0 && query) {
return this.props.search(query);
}

if (storedTerms.length !== 0 && query) {
const testDuplicate = storedTerms.map(term => term === query);
foundDuplicate = testDuplicate.some(element => element);
}

if (storedTerms.length !== 0 && !query) {
return false;
}

if (foundDuplicate) {
return false;
}

return this.props.search(query);
}

handleInputChange(term) {
this.setState({ searchTerm: term });
this.startSearch(term);
}

render() {
return (
<div className=Search-bar>
<input
value={this.state.searchTerm}
onChange={event => this.handleInputChange(event.target.value)}
/>
</div>
);
}


function mapStateToProps(state) {
return {
searchedTerm: state.searchedTerm,
savedData: state.savedData,
};
}

function mapDispatchToProps(dispatch) {
return bindActionCreators({ search }, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(SearchBar);





EDIT:



Thx to Sagiv b.g, I'm adding some explanation:



ok, so the user should type more than 2 letters && also my app should wait minimum 2 seconds before starting ajax request






EDIT2:
Thx to Sagiv b.g, for great solution!



I've changed my code like so:



import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import _ from 'lodash';
import './style.css';

import { search } from '../../actions/';

class SearchBar extends Component {
constructor(props) {
super(props);
this.state = { inputValue: '' };

this.startSearch = _.debounce(this.startSearch, 2000);
}

startSearch(query) {
const storedTerms = this.props.searchedTerm;
let foundDuplicate = false;

if (storedTerms.length === 0 && query) {
return this.props.search(query);
}

if (storedTerms.length !== 0 && query) {
const testDuplicate = storedTerms.map(term => term === query);
foundDuplicate = testDuplicate.some(element => element);
}

if (storedTerms.length !== 0 && !query) {
return false;
}

if (foundDuplicate) {
return false;
}

return this.props.search(query);
}

onChange = ({ target: { value } }) => {
this.setState({ inputValue: value });
if (value.length > 2) {
this.startSearch(value);
}
};

render() {
return (
<div className=Search-bar>
<input
placeholder=Type something to search GitHub
value={this.state.inputValue}
onChange={this.onChange}
/>
</div>
);
}
}

function mapStateToProps(state) {
return {
searchedTerm: state.searchedTerm,
savedData: state.savedData,
};
}

function mapDispatchToProps(dispatch) {
return bindActionCreators({ search }, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(SearchBar);





Last Bug to deal with



But it has one last bug, that I don't know how to get rid off. When the user wants to change search query and uses backspace to erase search field, my app always fires unexpectedly another API request.
Here is an example:



https://youtu.be/uPEt0hHDOAI



Any ideas how I can get rid of that behavior?


More From » reactjs

 Answers
14

Well this is easy with lodash _.debounce.

You wrap your method with it and pass the milliseconds you want to wait.

As for the minimum length of the input, just invoke the new method only if the length is above 2.



Here is a small running example:





class App extends React.Component {
constructor(props) {
super(props);
this.state = {
message: '',
inputValue: ''
};

this.updateMessage = _.debounce(this.updateMessage, 2000);
}


onChange = ({ target: { value } }) => {
this.setState({ inputValue: value });
if (value.length > 2) {
this.updateMessage(value);
}
}


updateMessage = message => this.setState({ message });

render() {
const { message, inputValue } = this.state;
return (
<div>
<input placeholder=type something... value={inputValue} onChange={this.onChange} />
<hr/>
<div>server call >> wait 2 seconds & min length of 2</div>
<p>{message}</p>
</div>
);
}
}

ReactDOM.render(<App />, document.getElementById('root'));

<script src=https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js></script>
<script src=//cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.compat.js></script>
<div id=root></div>




[#55568] Tuesday, December 26, 2017, 7 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
janettejordynm

Total Points: 550
Total Questions: 94
Total Answers: 98

Location: Senegal
Member since Fri, Aug 21, 2020
4 Years ago
janettejordynm questions
Tue, Nov 24, 20, 00:00, 4 Years ago
Sat, May 23, 20, 00:00, 4 Years ago
Mon, Apr 6, 20, 00:00, 4 Years ago
Tue, Feb 18, 20, 00:00, 4 Years ago
;