如何在React.js中执行debounce ?

我想撤消handleOnChange。

我尝试debounce(这。handleOnChange, 200)但它不起作用。

function debounce(fn, delay) {
  var timer = null;
  return function() {
    var context = this,
      args = arguments;
    clearTimeout(timer);
    timer = setTimeout(function() {
      fn.apply(context, args);
    }, delay);
  };
}

var SearchBox = React.createClass({
  render: function() {
    return <input type="search" name="p" onChange={this.handleOnChange} />;
  },

  handleOnChange: function(event) {
    // make ajax call
  }
});

当前回答

对于throttle或debounce,最好的方法是创建一个函数生成器,这样你就可以在任何地方使用它,例如:

  updateUserProfileField(fieldName) {
    const handler = throttle(value => {
      console.log(fieldName, value);
    }, 400);
    return evt => handler(evt.target.value.trim());
  }

在你的渲染方法中,你可以这样做:

<input onChange={this.updateUserProfileField("givenName").bind(this)}/>

updateUserProfileField方法将在每次调用它时创建一个单独的函数。

注意不要尝试直接返回处理程序,例如,这将不起作用:

 updateUserProfileField(fieldName) {
    return evt => throttle(value => {
      console.log(fieldName, value);
    }, 400)(evt.target.value.trim());
  }

为什么这将不会工作的原因,因为这将生成一个新的油门函数每次事件调用而不是使用相同的油门函数,所以基本上油门将是无用的;)

此外,如果你使用debounce或throttle,你不需要setTimeout或clearTimeout,这实际上是我们使用它们的原因:P

其他回答

对于debounce,你需要在event.persist()中保留原始的合成事件。下面是用React 16+测试的工作示例。

import React, { Component } from 'react';
import debounce from 'lodash/debounce'

class ItemType extends Component {

  evntHandler = debounce((e) => {
    console.log(e)
  }, 500);

  render() {
    return (
      <div className="form-field-wrap"
      onClick={e => {
        e.persist()
        this.evntHandler(e)
      }}>
        ...
      </div>
    );
  }
}
export default ItemType;

使用功能组件,您可以做到这一点-

const Search = ({ getBooks, query }) => {

  const handleOnSubmit = (e) => {
    e.preventDefault();
  }
  const debouncedGetBooks = debounce(query => {
    getBooks(query);
  }, 700);

  const onInputChange = e => {
    debouncedGetBooks(e.target.value)
  }

  return (
    <div className="search-books">
      <Form className="search-books--form" onSubmit={handleOnSubmit}>
        <Form.Group controlId="formBasicEmail">
          <Form.Control type="text" onChange={onInputChange} placeholder="Harry Potter" />
          <Form.Text className="text-muted">
            Search the world's most comprehensive index of full-text books.
          </Form.Text>
        </Form.Group>
        <Button variant="primary" type="submit">
          Search
        </Button>
      </Form>
    </div>
  )
}

引用- - - - - - ——https://gist.github.com/elijahmanor/08fc6c8468c994c844213e4a4344a709 ——https://blog.revathskumar.com/2016/02/reactjs-using-debounce-in-react-components.html

Julen的解决方案有点难以阅读,这里有更清晰和准确的反应代码,供那些根据标题而不是问题的微小细节绊倒他的人使用。

Tl;dr版本:当你要更新到观察者发送调用一个调度方法,反过来实际上会通知观察者(或执行ajax等)

使用示例组件jsfiddle完成jsfiddle

var InputField = React.createClass({

    getDefaultProps: function () {
        return {
            initialValue: '',
            onChange: null
        };
    },

    getInitialState: function () {
        return {
            value: this.props.initialValue
        };
    },

    render: function () {
        var state = this.state;
        return (
            <input type="text"
                   value={state.value}
                   onChange={this.onVolatileChange} />
        );
    },

    onVolatileChange: function (event) {
        this.setState({ 
            value: event.target.value 
        });

        this.scheduleChange();
    },

    scheduleChange: _.debounce(function () {
        this.onChange();
    }, 250),

    onChange: function () {
        var props = this.props;
        if (props.onChange != null) {
            props.onChange.call(this, this.state.value)
        }
    },

});

使用React Hooks和响应式编程(RxJS)的React ajax debounce和cancel示例解决方案:

import React, { useEffect, useState } from "react";
import { ajax } from "rxjs/ajax";
import { debounceTime, delay, takeUntil } from "rxjs/operators";
import { Subject } from "rxjs/internal/Subject";

const App = () => {
  const [items, setItems] = useState([]);
  const [loading, setLoading] = useState(true);
  const [filterChangedSubject] = useState(() => {
    // Arrow function is used to init Singleton Subject. (in a scope of a current component)
    return new Subject<string>();
  });

  useEffect(() => {
    // Effect that will be initialized once on a react component init.
    const subscription = filterChangedSubject
      .pipe(debounceTime(200))
      .subscribe((filter) => {
        if (!filter) {
          setLoading(false);
          setItems([]);
          return;
        }
        ajax(`https://swapi.dev/api/people?search=${filter}`)
          .pipe(
            // current running ajax is canceled on filter change.
            takeUntil(filterChangedSubject)
          )
          .subscribe(
            (results) => {
              // Set items will cause render:
              setItems(results.response.results);
            },
            () => {
              setLoading(false);
            },
            () => {
              setLoading(false);
            }
          );
      });

    return () => {
      // On Component destroy. notify takeUntil to unsubscribe from current running ajax request
      filterChangedSubject.next("");
      // unsubscribe filter change listener
      subscription.unsubscribe();
    };
  }, []);

  const onFilterChange = (e) => {
    // Notify subject about the filter change
    filterChangedSubject.next(e.target.value);
  };
  return (
    <div>
      Cards
      {loading && <div>Loading...</div>}
      <input onChange={onFilterChange}></input>
      {items && items.map((item, index) => <div key={index}>{item.name}</div>)}
    </div>
  );
};

export default App;

扩展useState钩子

import { useState } from "react";
import _ from "underscore"
export const useDebouncedState = (initialState, durationInMs = 500) => {
    const [internalState, setInternalState] = useState(initialState);
    const debouncedFunction = _.debounce(setInternalState, durationInMs);
    return [internalState, debouncedFunction];
};
export default useDebouncedState;

使用钩

import useDebouncedState from "../hooks/useDebouncedState"
//...
const [usernameFilter, setUsernameFilter] = useDebouncedState("")
//...
<input id="username" type="text" onChange={e => setUsernameFilter(e.target.value)}></input>

https://trippingoncode.com/react-debounce-hook/

有一个使用react钩子的简单方法。

步骤1:定义一个状态来维护搜索的文本

const [searchTerm, setSearchTerm] = useState('')

步骤2:使用useEffect捕获搜索Term中的任何变化

useEffect(() => {
  const delayDebounceFn = setTimeout(() => {
    if (searchTerm) {
      // write your logic here
    }
  }, 400)

  return () => clearTimeout(delayDebounceFn)
}, [searchTerm])

步骤3:编写一个函数来处理输入更改

function handleInputChange(value) {
  if (value) {
    setSearchTerm(value)
  }
}

就这些!在需要时调用此方法