web-dev-qa-db-fra.com

Recherche dans Réagir lorsque l'utilisateur cesse de taper

Je dois effectuer une recherche lorsque l'utilisateur cesse de taper. Je sais que je suis censé utiliser setTimeout () . Mais avec Reactjs, je ne trouve pas comment ça marche. Quelqu'un peut-il me dire comment invoquer une méthode (qui gérera la recherche) lorsque l'utilisateur arrêtera de taper pendant quelques secondes (supposons que 5). Je ne peux pas trouver où écrire le code pour vérifier que l'utilisateur a bien arrêté de taper.

import React, {Component, PropTypes} from 'react';

export default class SearchBox extends Component {

    state={
      name:" ",
    }

    changeName = (event) => {
        this.setState({name: event.target.value}); 
    }

    sendToParent = () => {
        this.props.searching(this.state.name);
    }

    render() {
        return (
            <div>
                 <input type="text"  placeholder='Enter name you wish to Search.'  onChange={this.changeName} />

            </div>
        );
    }
}   

Je souhaite appeler la méthode sendToParent lorsque l'utilisateur cesse de taper.

16
shinite

Vous pouvez utiliser setTimeout en ce qui concerne votre code comme suit,

state = {
    name: '',
    typing: false,
    typingTimeout: 0
}
changeName = (event) => {
    const self = this;

    if (self.state.typingTimeout) {
       clearTimeout(self.state.typingTimeout);
    }

    self.setState({
       name: event.target.value,
       typing: false,
       typingTimeout: setTimeout(function () {
           self.sendToParent(self.state.name);
         }, 5000)
    });
}

En outre, vous devez lier la fonction de gestionnaire changeName au constructeur.

constructor(props) {
   super(props);
   this.changeName = this.changeName.bind(this);
}
25
Saba Hassan

Une autre façon qui a fonctionné avec moi:

class Search extends Component {
  constructor(props){
    super(props);
    this.timeout =  0;
  }

  doSearch(evt){
    var searchText = evt.target.value; // this is the search text
    if(this.timeout) clearTimeout(this.timeout);
    this.timeout = setTimeout(() => {
      //search function
    }, 300);
  }

   render() {
    return (
      <div className="form-group has-feedback">
        <label className="control-label">Any text</label>
        <input ref="searchInput" type="text" onChange={evt => this.doSearch(evt)} />
      </div>
    );
  }
}
8
Ninh Ngo

Je pense que nous pouvons le faire d'une manière plus simple et plus propre, sans abruptement le paramètre d'état qui appelle le cycle de vie complet du composant comme ceci:

constructor(props) {
    super(props);

    //Timer
    this.typingTimeout = null;

    //Event
    this.onFieldChange = this.onFieldChange.bind(this);

    //State
    this.state = { searchValue: '' }; 
}   


 /**
 * Called on the change of the textbox.
 * @param  {[Object]} event [Event object.]
 */
onFieldChange(event) {
    // Clears the previously set timer.
    clearTimeout(this.typingTimeout);

    // Reset the timer, to make the http call after 475MS (this.callSearch is a method which will call the search API. Don't forget to bind it in constructor.)
    this.typingTimeout = setTimeout(this.callSearch, 475);

    // Setting value of the search box to a state.
    this.setState({ [event.target.name]: event.target.value });
}


<div className="block-header">
     <input
           type="text"
           name="searchValue"
           value={this.state.searchValue}
           placeholder="User Name or Email"
           onChange={this.onFieldChange}
     />
</div>
1
Rahul

Problème de la bibliothèque Typeahead https://Twitter.github.io/typeahead.js/

Comme le cas est simple, je peux utiliser une solution rapide et sale:

onChange: (event) ->
  if @_timeoutTask?
    clearTimeout @_timeoutTask

  @_timeoutTask = setTimeout (=>
    @sendToParent event.target.value
    clearTimeout @_timeoutTask
  ), 5000

De cette façon, la tâche sera déclenchée 5 secondes après l'événement d'entrée. Si un nouvel événement se produit, l'ancienne tâche sera annulée et une nouvelle tâche est planifiée. Il faudra attendre encore 5 secondes.

La différence dans React est l'emplacement où stocker l'état de calcul comme _timeoutTask. L'étendue du fichier, l'état du composant ou l'instance du composant.

Étant donné que _timeoutTask est au niveau composant, il devrait être stocké globalement. Et cela n'affecte pas le rendu, donc pas dans l'état du composant aussi. Je suggère donc de l'attacher directement à l'instance de composant.

1
jiyinyiyong

vous pouvez simplement utiliser l'anti-rebond de lodash ou simuler avec setTimeout.

import React, {Component, PropTypes} from 'react';

export default class SearchBox extends Component {
    constructor(props){
       super(props);
       this.state={ name:" "}
       this.timeout =  null;

    }

    changeName = (event) => {
        clearTimeout(timeout);
         if(timeout){
           setTimeout((event)=> this.setState({name: event.target.value}), 200)
         }
    }

    sendToParent = () => {
        this.props.searching(this.state.name);
    }

    render() {
        return (
            <div>
                 <input type="text"  placeholder='Enter name you wish to Search.'  onChange={this.changeName} />

            </div>
        );
    }
}
0
Khalid Azam

Utilisateur lodash bibliothèque javascript et utilisation de [_.debounce][1]

changeName: _.debounce(function (val) {
  console.log(val)                
}, 1000)
0
Amir Ur Rehman

J'avais travaillé sur un projet où nous transmettions une grande quantité de données pour réagir. La quantité de données en cause est décalée après la saisie de chaque lettre. Je ne pouvais pas utiliser d'entrées non contrôlées car un formulaire était réparti sur 5 onglets différents et lorsque vous changiez d'onglet, il avait perdu la valeur d'entrée. C'est une sorte de version de la situation que j'ai eue. La solution réside dans l'état de la mise à jour, pas après la saisie de chaque lettre, mais après que l'utilisateur arrête de taper. Pour ce faire, nous pouvons utiliser deux types d’entrées contrôlées et non contrôlées qui fonctionnent ensemble.

Cela peut aider quelqu'un https://github.com/Pyot/react-update-state-on-stop-typing et l'exemple de code ci-dessous:

import React, { Component } from 'react'

class ForHeavyData extends Component {
  state = {
    value: ''
  }

  timer = null

  handleChange = (e) => {
    clearTimeout(this.timer);
    let value = e.target.value;
    this.timer = setTimeout(() => { this.triggerChange(value) }, 2000);
  }

  triggerChange = (targetValue) => {
    this.setState({ value: targetValue })
  }

render() {

return (
  <div className={'container'}>
    <div className={'row'}>
      <div className={'col-md-6'}>
        <div className={"form-group"}>
          <label forHtml="exampleInputEmail1"></label>
          <input
            className={'form-control'}
            placeholder={'Please type text...'}
            defaultValue={this.state.value}
            onChange={this.handleChange}
            onKeyDown={this.handleKeyDown} />
          <small className={"form-text text-muted"}>You'll see what you type after 2sec when you stop typing below.</small>
        </div>
      </div>
    </div>
    <div className={'row'}>
      <div className={'col-md-6'}>
        <div className={'redborder'}>
          {this.state.value !== '' ? this.state.value : 'You will see updated state here'}
        </div>
      </div>
    </div>
  </div>
)
}
}
export default ForHeavyData
0
Pyot