web-dev-qa-db-fra.com

Comment utiliser debounce dans ReactJS

J'apprends ReactJS et suis coincé avec le problème suivant. J'ai une entrée pour la recherche de contacts et je veux la gérer en 1000 ms après l'arrêt de la frappe d'un utilisateur. J'utilise la fonction anti-rebond à cette fin:

import React, { Component}  from 'react';
import ReactDOM  from 'react-dom';
import './index.css';
import {debounce} from 'lodash';

const contacts = [
    {
        id: 1,
        name: 'Darth Vader',
        phoneNumber: '+250966666666',
        image: 'img/darth.gif'
    }, {
        id: 2,
        name: 'Princess Leia',
        phoneNumber: '+250966344466',
        image: 'img/leia.gif'
    }, {
        id: 3,
        name: 'Luke Skywalker',
        phoneNumber: '+250976654433',
        image: 'img/luke.gif'
    }, {
        id: 4,
        name: 'Chewbacca',
        phoneNumber: '+250456784935',
        image: 'img/chewbacca.gif'
    }
];

class Contact extends React.Component {
    render() {
        return (
            <li className="contact">
                <img className="contact-image" src={this.props.image} width="60px" height="60px"/>
                <div className="contact-info">
                    <div className="contact-name">{this.props.name}</div>
                    <div className="contact-number">{this.props.phoneNumber}</div>
                </div>
            </li>
        );
    }
}

class ContactList extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            displayedContacts: contacts,
        };
        this.handleChange = debounce(this.handleChange.bind(this), 1000);
    }

    handleChange = e => {
        e.persist();
        let input = e.target.value.toLowerCase();
        this.setState({
            displayedContacts: contacts.filter(c => c.name.toLowerCase().includes(input))
        });   
    }

    render() {
        return (
            <div className="contacts">
                <input type="text" className="search-field" onChange={this.handleChange}/>
                <ul className="contacts-list">
                    {
                        this.state.displayedContacts.map(c =>
                            <Contact 
                                key={c.id} 
                                name={c.name}
                                phoneNumber={c.phoneNumber}
                                image={c.image} />
                        )
                    }
                </ul>
            </div>
        );
    }
}

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

Dans le journal de la console après avoir rempli l'entrée de recherche, j'obtiens un avertissement "Cet événement synthétique est réutilisé pour des raisons de performances. Si vous voyez cela, vous accédez à la propriété target sur un événement synthétique libéré/annulé. Il est défini sur null. Si vous devez conserver l'événement synthétique d'origine, utilisez event.persist () "

et une erreur "TypeError non intercepté: impossible de lire la propriété 'value' de null à ContactList._this2.handleChange".

J'utilise la méthode persist dans la fonction handleChange. Pourquoi je reçois cette erreur?

5
Dmitry Stepanov

Les gestionnaires d'événements sont mieux exécutés de manière synchrone. Vous pouvez gérer le value séparément et filtrer les contacts dans une fonction anti-rebond distincte.

Exemple

class ContactList extends React.Component {
  state = {
    contacts,
    displayedContacts: contacts
  };

  setDisplayedContacts = debounce(query => {
    this.setState({
      displayedContacts: this.state.contacts.filter(c =>
        c.name.toLowerCase().includes(query)
      )
    });
  }, 1000);

  handleChange = e => {
    let input = e.target.value.toLowerCase();
    this.setDisplayedContacts(input);
  };

  render() {
    return (
      <div className="contacts">
        <input
          type="text"
          className="search-field"
          onChange={this.handleChange}
        />
        <ul className="contacts-list">
          {this.state.displayedContacts.map(c => (
            <Contact
              key={c.id}
              name={c.name}
              phoneNumber={c.phoneNumber}
              image={c.image}
            />
          ))}
        </ul>
      </div>
    );
  }
}
15
Tholle