web-dev-qa-db-ja.com

ReactJSでデバウンスを使用する方法

私はReactJSを学んでいて、次の問題で立ち往生しています。連絡先検索の入力があり、ユーザーが入力を停止してから1000ミリ秒後にそれを処理したいと考えています。私はこの目的のためにデバウンス機能を使用します:

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

検索入力を入力した後、コンソールログにwarningが表示されます。この合成イベントは、パフォーマンス上の理由で再利用されます。これが表示されている場合、リリース済み/無効化された合成イベントのプロパティtargetにアクセスしています。これはnullに設定されています。元の合成イベントを保持する必要がある場合は、event.persist()を使用してください "

およびerror "キャッチされていないTypeError:ContactList._this2.handleChangeでnullのプロパティ 'value'を読み取れません。

persist関数でhandleChangeメソッドを使用しています。このエラーが発生するのはなぜですか?

5
Dmitry Stepanov

イベントハンドラーは同期的に実行するのが最適です。 valueを個別に処理し、別のデバウンス関数で連絡先をフィルタリングできます。

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