如何在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
}
});
您可以使用引用变量来存储计时器,然后将其清除。下面是一个不使用任何第三方包在react中实现deboundation的例子
import { useState, useRef } from "react";
import "./styles.css";
export default function App() {
// Variables for debouncing
const [text, setText] = useState("");
const timer = useRef();
// Variables for throtteling
const [throttle, setThrottle] = useState(false)
const handleDebouncing = ({ target }) => {
clearTimeout(timer.current)
timer.current = setTimeout(() => {
callApi();
}, 300);
setText(target.value);
};
const handleThrottleing = () => {
callApi()
setThrottle(true)
setTimeout(() => {
setThrottle(false)
}, 2000)
}
const callApi = () => {
console.log("Calling Api");
};
return (
<div className="App">
<input type="text" onChange={handleDebouncing} />
<button onClick={handleThrottleing} disabled={throttle} >Click me to see throtteling</button>
</div>
);
}
下面是我想出的一个用debouncer包装另一个类的例子。这使得自己很好地成为一个装饰器/高阶函数:
export class DebouncedThingy extends React.Component {
static ToDebounce = ['someProp', 'someProp2'];
constructor(props) {
super(props);
this.state = {};
}
// On prop maybe changed
componentWillReceiveProps = (nextProps) => {
this.debouncedSetState();
};
// Before initial render
componentWillMount = () => {
// Set state then debounce it from here on out (consider using _.throttle)
this.debouncedSetState();
this.debouncedSetState = _.debounce(this.debouncedSetState, 300);
};
debouncedSetState = () => {
this.setState(_.pick(this.props, DebouncedThingy.ToDebounce));
};
render() {
const restOfProps = _.omit(this.props, DebouncedThingy.ToDebounce);
return <Thingy {...restOfProps} {...this.state} />
}
}
如果你正在使用redux,你可以通过中间件以一种非常优雅的方式做到这一点。你可以这样定义Debounce中间件:
var timeout;
export default store => next => action => {
const { meta = {} } = action;
if(meta.debounce){
clearTimeout(timeout);
timeout = setTimeout(() => {
next(action)
}, meta.debounce)
}else{
next(action)
}
}
然后你可以添加debounging到动作创建者,比如:
export default debouncedAction = (payload) => ({
type : 'DEBOUNCED_ACTION',
payload : payload,
meta : {debounce : 300}
}
实际上已经有中间件你可以脱离npm来为你做这件事。
你必须使用useCallback,正如在这篇博客中提到的:
https://www.freecodecamp.org/news/debounce-and-throttle-in-react-with-hooks/
import React, { useCallback } from 'react';
import debounce from 'debounce'; // or another package
function App() {
...
const debouncedSave = useCallback(
debounce(x => foo(x), 1000),
[], // will be created only once initially
);
...
}
今天遇到了这个问题。使用setTimeout和clearTimeout解决。
我将给出一个你可以适应的例子:
import React, { Component } from 'react'
const DEBOUNCE_TIME = 500
class PlacesAutocomplete extends Component {
debounceTimer = null;
onChangeHandler = (event) => {
// Clear the last registered timer for the function
clearTimeout(this.debounceTimer);
// Set a new timer
this.debounceTimer = setTimeout(
// Bind the callback function to pass the current input value as arg
this.getSuggestions.bind(null, event.target.value),
DEBOUNCE_TIME
)
}
// The function that is being debounced
getSuggestions = (searchTerm) => {
console.log(searchTerm)
}
render() {
return (
<input type="text" onChange={this.onChangeHandler} />
)
}
}
export default PlacesAutocomplete
你也可以在它自己的函数组件中重构它:
import React from 'react'
function DebouncedInput({ debounceTime, callback}) {
let debounceTimer = null
return (
<input type="text" onChange={(event) => {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(
callback.bind(null, event.target.value),
debounceTime
)
}} />
)
}
export default DebouncedInput
像这样使用它:
import React, { Component } from 'react'
import DebouncedInput from '../DebouncedInput';
class PlacesAutocomplete extends Component {
debounceTimer = null;
getSuggestions = (searchTerm) => {
console.log(searchTerm)
}
render() {
return (
<DebouncedInput debounceTime={500} callback={this.getSuggestions} />
)
}
}
export default PlacesAutocomplete