Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use debounce in ReactJS

I'm learning ReactJS and stuck with the following problem. I have an input for contact searching and want to handle it in 1000ms after a user stop typing. I use debounce function for this purpose:

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')
);

In console log after filling in the search input I get a warning "This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the property target on a released/nullified synthetic event. This is set to null. If you must keep the original synthetic event around, use event.persist()"

and an error "Uncaught TypeError: Cannot read property 'value' of null at ContactList._this2.handleChange".

I use persist method in handleChange function. Why I get this error?

like image 705
Dmitry Stepanov Avatar asked Jul 04 '18 15:07

Dmitry Stepanov


People also ask

How do you use debounce in react JS?

In the case of Debouncing, the API will trigger only once after 2 seconds, after we type our whole pin-code. First of all, create a state using the useState hook in React. const [pinCode, setPinCode] = React. useState("");

How do you apply Debouncing?

The debounce() function forces a function to wait a certain amount of time before running again. The function is built to limit the number of times a function is called. The Send Request() function is debounced. Requests are sent only after fixed time intervals regardless of how many times the user presses the button.

What does debounce mean in react JS?

A Debouncing Events in ReactJS will allow you to call a function that ensures that a time-consuming task does not fire so often. It's a function that takes a function as a parameter and wraps that function in a closure and returns it so this new function displays the “wait for a bit” behavior.

How do I debounce a callback?

Debouncing a callback, the first attempt You can use any other library at your will, or even write the debounce function by yourself. import debounce from 'lodash. debounce'; const debouncedCallback = debounce(callback, waitTime);


1 Answers

Events handlers are best run synchronously. You could handle the value separately and filter the contacts in a separate debounced function.

Example

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>
    );
  }
}
like image 103
Tholle Avatar answered Oct 16 '22 21:10

Tholle