2017-12-31 62 views
1

Ich möchte Anfragen nicht auslösen, solange der Benutzer schreibt. Mein Code sollte Anforderungen drosseln, so dass der Benutzer bei einer schnellen Eingabe eine Anfrage mit dem letzten Eingabewert anstatt mit vielen auslösen wird.Verwenden von Lodash Debounce in React, um das Anfordern von Daten zu verhindern, solange der Benutzer schreibt

Denn jetzt, wenn ich die Eingabe von "test" es feuert 4 verschiedene Anfragen:

  1. "t"
  2. "te"
  3. "tes"
  4. "test"

So fand ich lodash _.debounce und _.throttle ([https://lodash.com/docs/4.17.4#debounce]) aber verstehe nicht wirklich, wie ich es zu meinem Code implementieren kann. Kann mir jemand helfen?

Mein 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 zu Sagiv bg, ich hinzufüge, eine Erklärung:

ok, so sollte der Benutzer mehr als 2 Buchstaben eingeben & & auch meine App sollte mindestens 2 Sekunden warten, bevor Ajax Anfrage

starten

EDIT2: Danke an Sagiv B.g, für großartige Lösung!

Ich habe meinen Code wie so geändert:

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 zu behandeln

Aber es hat einen letzten Fehler, dass ich nicht weiß, wie man abschieben. Wenn der Benutzer die Suchabfrage ändern und die Rücktaste zum Löschen des Suchfelds verwenden möchte, löst meine App immer unerwartet eine andere API-Anfrage aus. Hier ist ein Beispiel:

https://youtu.be/uPEt0hHDOAI

Irgendwelche Ideen, wie ich dieses Verhalten loswerden kann?

+0

wenn Sie sagen, "_so lange der Benutzer tippt ..._ ", können Sie erklären, wie genau Sie bestimmen möchten, wenn ein Benutzer einen anderen Buchstaben eingeben möchte? Manche Benutzer geben 1 Buchstabe pro 0,5 Sekunden ein und andere geben langsamer ein. Sie können nicht wirklich sicher sein, wann ein Benutzer fertig ist Sie können die Ajax-Anfrage auf eine Zeiteinheit (1,5 Sekunden?) und/oder Mindestlänge string und hoffen auf das Beste –

+0

ok, so sollte der Benutzer mehr als 2 Buchstaben eingeben & & auch meine App sollte 2 Sekunden warten vor dem Start von Ajax Anfrage – MountainConqueror

Antwort

1

Nun, das ist einfach mit lodash _.debounce.
Sie wickeln Ihre Methode damit und übergeben die Millisekunden, die Sie warten möchten.
Was die Mindestlänge des Eingangs, rufen Sie einfach die neue Methode nur, wenn die Länge oben ist 2.

Hier ist ein kleines Lauf Beispiel:

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>

+0

Vielen Dank für die Lösung! Ich schätze wirklich Ihre Hilfe! – MountainConqueror

+0

@MountainConqueror Gern geschehen :) –

+0

Ok, aber ich habe einen letzten Bug zu behandeln. Sollte ich Ihre Antwort akzeptieren und neue StackOverflow erstellen Frage? Hier ist mein Problem -> https://youtu.be/uPEt0hHDOAI – MountainConqueror

Verwandte Themen