如何在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钩子的简单方法。
步骤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)
}
}
就这些!在需要时调用此方法
您可以使用引用变量来存储计时器,然后将其清除。下面是一个不使用任何第三方包在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>
);
}
I was searching for a solution to the same problem and came across this thread as well as some others but they had the same problem: if you are trying to do a handleOnChange function and you need the value from an event target, you will get cannot read property value of null or some such error. In my case, I also needed to preserve the context of this inside the debounced function since I'm executing a fluxible action. Here's my solution, it works well for my use case so I'm leaving it here in case anyone comes across this thread:
// at top of file:
var myAction = require('../actions/someAction');
// inside React.createClass({...});
handleOnChange: function (event) {
var value = event.target.value;
var doAction = _.curry(this.context.executeAction, 2);
// only one parameter gets passed into the curried function,
// so the function passed as the first parameter to _.curry()
// will not be executed until the second parameter is passed
// which happens in the next function that is wrapped in _.debounce()
debouncedOnChange(doAction(myAction), value);
},
debouncedOnChange: _.debounce(function(action, value) {
action(value);
}, 300)
使用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;