你如何在React.js中进行去抖动?
我想辩论handleOnChange。
我尝试使用debounce(this.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
}
});
答案 0 :(得分:728)
这是我如何解决此问题的最新版本。我会用:
这是一些初始接线,但你自己组成了原始块,你可以自己创建自定义钩子,这样你只需要做一次。
const useSearchStarwarsHero = () => {
// Handle the input text state
const [inputText, setInputText] = useState('');
// Debounce the original search async function
const debouncedSearchStarwarsHero = useConstant(() =>
AwesomeDebouncePromise(searchStarwarsHero, 300)
);
const search = useAsync(
async text => {
if (text.length === 0) {
return [];
} else {
return debouncedSearchStarwarsHero(text);
}
},
// Ensure a new request is made everytime the text changes (even if it's debounced)
[inputText]
);
// Return everything needed for the hook consumer
return {
inputText,
setInputText,
search,
};
};
然后你可以使用你的钩子:
const SearchStarwarsHeroExample = () => {
const { inputText, setInputText, search } = useSearchStarwarsHero();
return (
<div>
<input value={inputText} onChange={e => setInputText(e.target.value)} />
<div>
{search.loading && <div>...</div>}
{search.error && <div>Error: {search.error.message}</div>}
{search.result && (
<div>
<div>Results: {search.result.length}</div>
<ul>
{search.result.map(hero => (
<li key={hero.name}>{hero.name}</li>
))}
</ul>
</div>
)}
</div>
</div>
);
};
您会发现此示例正在运行here,您应该阅读react-async-hook文档以获取更多详细信息。
我们经常要去除API调用,以避免使用无用的请求充斥后端。
在2018年,使用回调(Lodash / Underscore)感觉不好并且容易出错。由于API调用以任意顺序解析,因此很容易遇到样板和并发问题。
为了解决您的痛苦,我已经创建了一个包含React的小型库:awesome-debounce-promise。
这不应该比那更复杂:
const searchAPI = text => fetch('/search?text=' + encodeURIComponent(text));
const searchAPIDebounced = AwesomeDebouncePromise(searchAPI, 500);
class SearchInputAndResults extends React.Component {
state = {
text: '',
results: null,
};
handleTextChange = async text => {
this.setState({ text, results: null });
const result = await searchAPIDebounced(text);
this.setState({ result });
};
}
debounced函数确保:
this.setState({ result });
最后,如果您的组件卸载,您可以添加另一个技巧:
componentWillUnmount() {
this.setState = () => {};
}
请注意, Observables (RxJS)也非常适合去抖动输入,但它是一种更强大的抽象,可能更难以正确学习/使用。
这里的重要部分是为每个组件实例创建一个去抖(或限制)功能。您不希望每次都重新创建去抖动(或油门)功能,并且您不希望多个实例共享相同的去抖动功能。
我没有在这个答案中定义去抖动功能,因为它并不真正相关,但这个答案对于_.debounce
下划线或lodash,以及任何用户来说都可以完美地运行 - 提供了去抖功能。
由于去抖动功能是有状态的,我们必须为每个组件实例创建一个去抖动功能。
ES6(类属性):推荐
class SearchBox extends React.Component {
method = debounce(() => {
...
});
}
ES6(类构造函数)
class SearchBox extends React.Component {
constructor(props) {
super(props);
this.method = debounce(this.method,1000);
}
method() { ... }
}
<强> ES5 强>
var SearchBox = React.createClass({
method: function() {...},
componentWillMount: function() {
this.method = debounce(this.method,100);
},
});
参见JsFiddle:3个实例每个实例生成1个日志条目(全局生成3个)。
var SearchBox = React.createClass({
method: function() {...},
debouncedMethod: debounce(this.method, 100);
});
它不会起作用,因为在类描述对象创建过程中,this
不是自己创建的对象。 this.method
没有返回您期望的内容,因为this
上下文不是对象本身(实际上它还没有真正存在,因为它刚刚被创建)。
var SearchBox = React.createClass({
method: function() {...},
debouncedMethod: function() {
var debounced = debounce(this.method,100);
debounced();
},
});
这一次,您有效地创建了一个调用this.method
的去抖动功能。问题是你在每次debouncedMethod
次呼叫时重新创建它,所以新创建的去抖功能对以前的呼叫一无所知!您必须重复使用相同的去抖功能,否则不会发生去抖动。
var SearchBox = React.createClass({
debouncedMethod: debounce(function () {...},100),
});
这里有点棘手。
该类的所有已安装实例将共享相同的去抖功能,并且通常这不是您想要的!请参阅JsFiddle:3个实例仅在全球范围内生成1个日志条目。
您必须为每个组件实例创建一个去抖动函数,而不是在每个组件实例共享的类级别的一个去抖动函数。
这是相关的,因为我们经常想要去抖动或限制DOM事件。
在React中,您在回调中收到的事件对象(即SyntheticEvent
)将被合并(现在为documented)。这意味着在调用事件回调之后,您收到的SyntheticEvent将被放回具有空属性的池中以减少GC压力。
因此,如果您与原始回调异步访问SyntheticEvent
属性(如果节流/去抖动可能就是这种情况),则可能会删除您访问的属性。如果您希望永远不会将事件放回池中,则可以使用persist()
方法。
onClick = e => {
alert(`sync -> hasNativeEvent=${!!e.nativeEvent}`);
setTimeout(() => {
alert(`async -> hasNativeEvent=${!!e.nativeEvent}`);
}, 0);
};
第二个(异步)将打印hasNativeEvent=false
,因为事件属性已被清除。
onClick = e => {
e.persist();
alert(`sync -> hasNativeEvent=${!!e.nativeEvent}`);
setTimeout(() => {
alert(`async -> hasNativeEvent=${!!e.nativeEvent}`);
}, 0);
};
第二个(异步)将打印hasNativeEvent=true
因为persist
允许您避免将事件放回池中。
您可以在此处测试这两种行为:JsFiddle
请阅读Julen's answer,了解使用persist()
加油门/去抖功能的示例。
答案 1 :(得分:200)
您可以使用event.persist()
method。
使用下划线的_.debounce()
:
var SearchBox = React.createClass({
componentWillMount: function () {
this.delayedCallback = _.debounce(function (event) {
// `event.target` is accessible now
}, 1000);
},
onChange: function (event) {
event.persist();
this.delayedCallback(event);
},
render: function () {
return (
<input type="search" onChange={this.onChange} />
);
}
});
修改:请参阅this JSFiddle
更新:上面的示例显示了uncontrolled component。我一直使用受控元素,所以这是上面的另一个例子,但没有使用event.persist()
“trickery”。
也是JSFiddle is available。 Example without underscore
var SearchBox = React.createClass({
getInitialState: function () {
return {
query: this.props.query
};
},
componentWillMount: function () {
this.handleSearchDebounced = _.debounce(function () {
this.props.handleSearch.apply(this, [this.state.query]);
}, 500);
},
onChange: function (event) {
this.setState({query: event.target.value});
this.handleSearchDebounced();
},
render: function () {
return (
<input type="search"
value={this.state.query}
onChange={this.onChange} />
);
}
});
var Search = React.createClass({
getInitialState: function () {
return {
result: this.props.query
};
},
handleSearch: function (query) {
this.setState({result: query});
},
render: function () {
return (
<div id="search">
<SearchBox query={this.state.result}
handleSearch={this.handleSearch} />
<p>You searched for: <strong>{this.state.result}</strong></p>
</div>
);
}
});
React.render(<Search query="Initial query" />, document.body);
编辑:更新的示例和JSFiddles到React 0.12
编辑:更新的示例以解决Sebastien Lorber提出的问题
编辑:使用jsfiddle更新,不使用下划线并使用普通的javascript去抖。
答案 2 :(得分:13)
如果您需要从事件对象获取DOM输入元素,那么解决方案就更简单了 - 只需使用ref
即可。请注意,这需要JSFiddle:
class Item extends React.Component {
constructor(props) {
super(props);
this.saveTitle = _.throttle(this.saveTitle.bind(this), 1000);
}
saveTitle(){
let val = this.inputTitle.value;
// make the ajax call
}
render() {
return <input
ref={ el => this.inputTitle = el }
type="text"
defaultValue={this.props.title}
onChange={this.saveTitle} />
}
}
答案 3 :(得分:9)
我发现Justin Tulk的this post非常有帮助。经过几次尝试后,人们会认为反应/减少更正式的方式,它表明它由于React's synthetic event pooling而失败。然后他的解决方案使用一些内部状态来跟踪输入中更改/输入的值,并在setState
之后立即进行回调,该回调调用一个实时显示某些结果的限制/去抖动redux操作。
import React, {Component} from 'react'
import TextField from 'material-ui/TextField'
import { debounce } from 'lodash'
class TableSearch extends Component {
constructor(props){
super(props)
this.state = {
value: props.value
}
this.changeSearch = debounce(this.props.changeSearch, 250)
}
handleChange = (e) => {
const val = e.target.value
this.setState({ value: val }, () => {
this.changeSearch(val)
})
}
render() {
return (
<TextField
className = {styles.field}
onChange = {this.handleChange}
value = {this.props.value}
/>
)
}
}
答案 4 :(得分:9)
尝试了许多不同的方法之后,我发现使用useCallback
是解决debounce
事件中使用onChange
的多重调用问题的最简单,最有效的方法。
useCallback返回存储的回调版本,只有在其中一个依赖项已更改时,该回调版本才会更改。
传递一个空数组作为依赖项,以确保仅调用一次回调。这是一个简单的实现:
import React, { useCallback } from "react";
import { debounce } from "lodash";
const handler = useCallback(debounce(someFunction, 2000), []);
const onChange = (event) => {
// perform any event related action here
handler();
};
希望这会有所帮助!
答案 5 :(得分:7)
在对文本输入进行了一段时间的努力而没有找到完美的解决方案后,我在npm https://www.npmjs.com/package/react-debounce-input找到了这个
这是一个简单的例子:
import React from 'react';
import ReactDOM from 'react-dom';
import {DebounceInput} from 'react-debounce-input';
class App extends React.Component {
state = {
value: ''
};
render() {
return (
<div>
<DebounceInput
minLength={2}
debounceTimeout={300}
onChange={event => this.setState({value: event.target.value})} />
<p>Value: {this.state.value}</p>
</div>
);
}
}
const appRoot = document.createElement('div');
document.body.appendChild(appRoot);
ReactDOM.render(<App />, appRoot);
DebounceInput组件接受您可以分配给普通输入元素的所有道具。在codepen
上试一试我希望它能帮助别人并节省一些时间。
答案 6 :(得分:6)
如果您使用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)
}
}
然后,您可以向操作创建者添加去抖动,例如:
export default debouncedAction = (payload) => ({
type : 'DEBOUNCED_ACTION',
payload : payload,
meta : {debounce : 300}
}
实际上already middleware你可以下午npm为你做这件事。
答案 7 :(得分:6)
使用ES6 CLASS和 React 15.x.x &amp; lodash.debounce 我在这里使用React的 refs ,因为事件在内部损失了这个绑定。
class UserInput extends React.Component {
constructor(props) {
super(props);
this.state = {
userInput: ""
};
this.updateInput = _.debounce(this.updateInput, 500);
}
updateInput(userInput) {
this.setState({
userInput
});
//OrderActions.updateValue(userInput);//do some server stuff
}
render() {
return ( <div>
<p> User typed: {
this.state.userInput
} </p>
<input ref = "userValue" onChange = {() => this.updateInput(this.refs.userValue.value) } type = "text" / >
</div>
);
}
}
ReactDOM.render( <
UserInput / > ,
document.getElementById('root')
);
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.5/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
答案 8 :(得分:5)
这里已经有很多不错的信息,但是要简洁。这对我有用...
import React, {Component} from 'react';
import _ from 'lodash';
class MyComponent extends Component{
constructor(props){
super(props);
this.handleChange = _.debounce(this.handleChange.bind(this),700);
};
答案 9 :(得分:4)
我的解决方案是基于钩子(用Typescript编写)。
我有2个主要的钩子useDebouncedValue
和useDebouncedCallback
第一-useDebouncedValue
假设我们有一个搜索框,但是我们要在用户停止输入0.5秒后向服务器询问搜索结果
function SearchInput() {
const [realTimeValue, setRealTimeValue] = useState('');
const debouncedValue = useDebouncedValue(realTimeValue, 500); // this value will pick real time value, but will change it's result only when it's seattled for 500ms
useEffect(() => {
// this effect will be called on seattled values
api.fetchSearchResults(debouncedValue);
}, [debouncedValue])
return <input onChange={event => setRealTimeValue(event.target.value)} />
}
实施
import { useState, useEffect } from "react";
export function useDebouncedValue<T>(input: T, time = 500) {
const [debouncedValue, setDebouncedValue] = useState(input);
// every time input value has changed - set interval before it's actually commited
useEffect(() => {
const timeout = setTimeout(() => {
setDebouncedValue(input);
}, time);
return () => {
clearTimeout(timeout);
};
}, [input, time]);
return debouncedValue;
}
第二useDebouncedCallback
它只会在您的组件范围内创建一个“去抖动”功能。
比方说,我们有一个带有按钮的组件,在您停止单击它后的500ms内将显示警报。
function AlertButton() {
function showAlert() {
alert('Clicking has seattled');
}
const debouncedShowAlert = useDebouncedCallback(showAlert, 500);
return <button onClick={debouncedShowAlert}>Click</button>
}
实施(请注意,我使用lodash / debounce作为辅助工具)
import debounce from 'lodash/debounce';
import { useMemo } from 'react';
export function useDebouncedCallback<T extends (...args: any) => any>(callback: T, wait?: number) {
const debouncedCallback = useMemo(() => debounce(callback, wait), [callback, wait]);
return debouncedCallback;
}
答案 10 :(得分:4)
我在这个问题下找不到任何提到我正在使用的方法的答案,所以只想在这里提供一个我认为最适合我的用例的替代解决方案。
如果您使用的是流行的名为 react-use
的 react hooks 工具包库,那么有一个名为 useDebounce()
的实用程序钩子,它以一种非常优雅的方式实现了谴责逻辑。
const [query, setQuery] = useState('');
useDebounce(
() => {
emitYourOnDebouncedSearchEvent(query);
},
2000,
[query]
);
return <input onChange={({ currentTarget }) => setQuery(currentTarget.value)} />
详情请直接查看lib的github页面。
https://github.com/streamich/react-use/blob/master/docs/useDebounce.md
答案 11 :(得分:4)
您可以使用Lodash debounce https://lodash.com/docs/4.17.5#debounce方法。它简单而有效。
import * as lodash from lodash;
const update = (input) => {
// Update the input here.
console.log(`Input ${input}`);
}
const debounceHandleUpdate = lodash.debounce((input) => update(input), 200, {maxWait: 200});
doHandleChange() {
debounceHandleUpdate(input);
}
您也可以使用以下方法取消去抖动方法。
this.debounceHandleUpdate.cancel();
希望它对你有所帮助。干杯!!
答案 12 :(得分:3)
有一个use-debounce
包可以与ReactJS挂钩一起使用。
来自软件包的自述文件:
import { useDebounce } from 'use-debounce';
export default function Input() {
const [text, setText] = useState('Hello');
const [value] = useDebounce(text, 1000);
return (
<div>
<input
defaultValue={'Hello'}
onChange={(e) => {
setText(e.target.value);
}}
/>
<p>Actual value: {text}</p>
<p>Debounce value: {value}</p>
</div>
);
}
从上面的示例中可以看到,它设置为每秒仅一次(1000毫秒)更新变量value
。
答案 13 :(得分:3)
您尝试了吗?
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) {
debounce(\\ Your handleChange code , 200);
}
});
答案 14 :(得分:2)
一个不错且干净的解决方案,不需要任何外部依赖项:
它使用了自定义函数以及useEffect React钩子和setTimeout
/ clearTimeout
方法。
答案 15 :(得分:2)
使用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;
参考要点-https://gist.github.com/elijahmanor/08fc6c8468c994c844213e4a4344a709
答案 16 :(得分:2)
仅供参考
这是另一个PoC实现:
我希望这会有所帮助:)
import React, { useState, useEffect, ChangeEvent } from 'react';
export default function DebouncedSearchBox({
inputType,
handleSearch,
placeholder,
debounceInterval,
}: {
inputType?: string;
handleSearch: (q: string) => void;
placeholder: string;
debounceInterval: number;
}) {
const [query, setQuery] = useState<string>('');
const [timer, setTimer] = useState<NodeJS.Timer | undefined>();
useEffect(() => {
if (timer) {
clearTimeout(timer);
}
setTimer(setTimeout(() => {
handleSearch(query);
}, debounceInterval));
}, [query]);
const handleOnChange = (e: ChangeEvent<HTMLInputElement>): void => {
setQuery(e.target.value);
};
return (
<input
type={inputType || 'text'}
className="form-control"
placeholder={placeholder}
value={query}
onChange={handleOnChange}
/>
);
}
答案 17 :(得分:2)
另一个具有最近反应和lodash的变体。
class Filter extends Component {
static propTypes = {
text: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired
}
state = {
initialText: '',
text: ''
}
constructor (props) {
super(props)
this.setText = this.setText.bind(this)
this.onChange = _.fp.debounce(500)(this.onChange.bind(this))
}
static getDerivedStateFromProps (nextProps, prevState) {
const { text } = nextProps
if (text !== prevState.initialText) {
return { initialText: text, text }
}
return null
}
setText (text) {
this.setState({ text })
this.onChange(text)
}
onChange (text) {
this.props.onChange(text)
}
render () {
return (<input value={this.state.text} onChange={(event) => this.setText(event.target.value)} />)
}
}
答案 18 :(得分:2)
这是我想出的一个例子,用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} />
}
}
答案 19 :(得分:1)
我正在寻找同一问题的解决方案并且遇到了这个线程以及其他一些问题,但是他们遇到了同样的问题:如果你正在尝试执行handleOnChange
函数并且需要来自事件目标,您将收到cannot read property value of null
或某些此类错误。在我的情况下,我还需要在去抖动函数中保留this
的上下文,因为我正在执行一个可触发的动作。这是我的解决方案,它适用于我的用例,所以我将它留在这里以防万一有人遇到这个帖子:
// 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)
答案 20 :(得分:1)
至于 2021 年 6 月,您可以简单地实施 xnimorz 解决方案:https://github.com/xnimorz/use-debounce
import { useState, useEffect, useRef } from "react";
// Usage
function App() {
// State and setters for ...
// Search term
const [searchTerm, setSearchTerm] = useState("");
// API search results
const [results, setResults] = useState([]);
// Searching status (whether there is pending API request)
const [isSearching, setIsSearching] = useState(false);
// Debounce search term so that it only gives us latest value ...
// ... if searchTerm has not been updated within last 500ms.
// The goal is to only have the API call fire when user stops typing ...
// ... so that we aren't hitting our API rapidly.
const debouncedSearchTerm = useDebounce(searchTerm, 500);
// Effect for API call
useEffect(
() => {
if (debouncedSearchTerm) {
setIsSearching(true);
searchCharacters(debouncedSearchTerm).then((results) => {
setIsSearching(false);
setResults(results);
});
} else {
setResults([]);
setIsSearching(false);
}
},
[debouncedSearchTerm] // Only call effect if debounced search term changes
);
return (
<div>
<input
placeholder="Search Marvel Comics"
onChange={(e) => setSearchTerm(e.target.value)}
/>
{isSearching && <div>Searching ...</div>}
{results.map((result) => (
<div key={result.id}>
<h4>{result.title}</h4>
<img
src={`${result.thumbnail.path}/portrait_incredible.${result.thumbnail.extension}`}
/>
</div>
))}
</div>
);
}
// API search function
function searchCharacters(search) {
const apiKey = "f9dfb1e8d466d36c27850bedd2047687";
return fetch(
`https://gateway.marvel.com/v1/public/comics?apikey=${apiKey}&titleStartsWith=${search}`,
{
method: "GET",
}
)
.then((r) => r.json())
.then((r) => r.data.results)
.catch((error) => {
console.error(error);
return [];
});
}
// Hook
function useDebounce(value, delay) {
// State and setters for debounced value
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(
() => {
// Update debounced value after delay
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
// Cancel the timeout if value changes (also on delay change or unmount)
// This is how we prevent debounced value from updating if value is changed ...
// .. within the delay period. Timeout gets cleared and restarted.
return () => {
clearTimeout(handler);
};
},
[value, delay] // Only re-call effect if value or delay changes
);
return debouncedValue;
}
答案 21 :(得分:1)
挂钩:
select id_dealer
from mytable
group by id_dealer
having max(created_at) < current_date
并在任何地方使用(在同一文件中,使用标识符防止并发) :
##### Image processing ####
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('/home/pi/Documents/testcode_python/Tractor_actual/Pictures/result2.jpg') #reads as BGR
print(img.shape)
no_blue=img.copy() # copy of img to avoid using the same memory location as img
no_green=img.copy() # copy of img to avoid using the same memory location as img
only_red=img.copy() # similarly to above.
# You also need all three channels of the RGB image to avoid it being interpreted as single channel image.
only_red[:,:,0] = np.zeros([img.shape[0], img.shape[1]])
only_red[:,:,1] = np.zeros([img.shape[0], img.shape[1]])
# Puts zeros for green and blue channels
no_blue[:,:,0]=np.zeros([img.shape[0], img.shape[1]]) #Puts Zeros on Blue channels for "no_blue"
no_green[:,:,1]=np.zeros([img.shape[0], img.shape[1]])
print(no_blue.shape)
cv2.imshow('Original',img)
cv2.imshow('No Blue',no_blue)
cv2.imshow('No Green',no_green)
cv2.imshow('Only Red', only_red)
cv2.waitKey(0)
cv2.destroyAllWindows()
答案 22 :(得分:1)
如果您只需要在用于请求数据的按钮中执行反跳操作,则提供的代码可能对您有帮助:
如果请求为 true或false
,则使用条件语句创建一个防止默认值的函数实施 useState挂钩和 useEffect挂钩
func queryItems(for url: URL, dictionary: [String:String]) -> URL? {
guard var components = URLComponents(url: url, resolvingAgainstBaseURL: false) else { return nil }
components.queryItems = dictionary.map(URLQueryItem.init)
return components.url
}
答案 23 :(得分:1)
此解决方案不需要任何额外的库,并且当用户按下Enter键时,它也可以触发事情:
//div[@class='MEAGs']/button
,输入可能像这样:
const debounce = (fn, delay) => {
let timer = null;
return function() {
const context = this,
args = arguments;
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(context, args);
}, delay);
};
}
const [search, setSearch] = useState('');
const [searchFor, setSearchFor] = useState(search);
useEffect(() => {
console.log("Search:", searchFor);
}, [searchFor]);
const fireChange = event => {
const { keyCode } = event;
if (keyCode === 13) {
event.preventDefault();
setSearchFor(search);
}
}
const changeSearch = event => {
const { value } = event.target;
setSearch(value);
debounceSetSearchFor(value);
};
const debounceSetSearchFor = useCallback(debounce(function(value) {
setSearchFor(value);
}, 250), []);
答案 24 :(得分:1)
late / 2019 中现在有针对React和React Native的另一种解决方案:
<input>
<Debounce ms={500}>
<List/>
</Debounce>
它是一个组件,易于使用,纤巧且支持widley
import React from 'react';
import Debounce from 'react-debounce-component';
class App extends React.Component {
constructor (props) {
super(props);
this.state = {value: 'Hello'}
}
render () {
return (
<div>
<input value={this.state.value} onChange={(event) => {this.setState({value: event.target.value})}}/>
<Debounce ms={1000}>
<div>{this.state.value}</div>
</Debounce>
</div>
);
}
}
export default App;
*我是这个组件的创建者
答案 25 :(得分:1)
为什么不将debo中的handleOnChange包装在debounce()内部,而不是将dejax调用包装在debounce中的回调函数中,从而不会破坏事件对象。所以像这样:
handleOnChange: function (event) {
debounce(
$.ajax({})
, 250);
}
答案 26 :(得分:1)
对于throttle
或debounce
,最好的方法是创建一个函数创建器,以便您可以在任何地方使用它,例如:
updateUserProfileField(fieldName) {
const handler = throttle(value => {
console.log(fieldName, value);
}, 400);
return evt => handler(evt.target.value.trim());
}
您可以使用render
方法:
<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
答案 27 :(得分:0)
使用React Hooks和反应式编程(RxJS)反应ajax去抖动和取消示例解决方案:
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;
答案 28 :(得分:0)
这是使用TS并希望消除async
函数反跳的人的有效TypeScript示例。
function debounce<T extends (...args: any[]) => any>(time: number, func: T): (...funcArgs: Parameters<T>) => Promise<ReturnType<T>> {
let timeout: Timeout;
return (...args: Parameters<T>): Promise<ReturnType<T>> => new Promise((resolve) => {
clearTimeout(timeout);
timeout = setTimeout(() => {
resolve(func(...args));
}, time)
});
}
答案 29 :(得分:0)
您必须使用 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
);
...
}
答案 30 :(得分:0)
如果我们有兴趣将epic.js 与react.js 一起使用,我们可以将debounceTime rxjs/operator 与epic.js 库一起使用。因此,我们可以在epic.js 的帮助下在react.js 中使用observables,而不是使用回调。
答案 31 :(得分:0)
简单有效
https://www.npmjs.com/package/use-debounce
use-debounce
import { useDebouncedCallback } from 'use-debounce';
function Input({ defaultValue }) {
const [value, setValue] = useState(defaultValue);
const debounced = useDebouncedCallback(
(value) => {
setValue(value);
},
// delay
1000
);
return (
<div>
<input defaultValue={defaultValue} onChange={(e) => debounced(e.target.value)} />
<p>Debounced value: {value}</p>
</div>
);
}
答案 32 :(得分:0)
我们需要将 setter
传递给 debounced 方法:
以下是 StackBlitz 示例的片段:
import React from "react";
import debounce from "lodash/debounce";
export default function App() {
const [state, setState] = React.useState({
debouncedLog: ""
});
const debouncedLog = React.useCallback(
debounce((setState, log) => {
setState(prevState => ({
...prevState,
debouncedLog: log
}));
}, 500),
[]
);
const onChange = React.useCallback(({ target: { value: log } }) => {
debouncedLog(setState, log); // passing the setState along...
}, []);
return (
<div>
<input onChange={onChange} style={{ outline: "1px blue solid" }} />
<pre>Debounced Value: {state.debouncedLog}</pre>
</div>
);
}
祝你好运...
答案 33 :(得分:0)
Julen解决方案有点难以阅读,对于任何根据标题而不是问题的微小细节而绊倒他的人来说,这里的代码更清晰,更具针对性。
tl; dr version :当您更新为观察者时,发送调用调度方法而不是反过来实际上会通知观察者(或执行ajax等)
使用示例组件http://jsfiddle.net/7L655p5L/4/
完成jsfiddlevar 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)
}
},
});
答案 34 :(得分:0)
list1 = ['1234', '2345', '3456', '4567']
list2 = ['1', '2']
print( *[x for x in list1 if all([x[:len(l)]!=l for l in list2])],sep="\n")
答案 35 :(得分:0)
这里有点晚,但这应该有所帮助。 创建此类(使用打字稿编写,但易于将其转换为javascript)
export class debouncedMethod<T>{
constructor(method:T, debounceTime:number){
this._method = method;
this._debounceTime = debounceTime;
}
private _method:T;
private _timeout:number;
private _debounceTime:number;
public invoke:T = ((...args:any[])=>{
this._timeout && window.clearTimeout(this._timeout);
this._timeout = window.setTimeout(()=>{
(this._method as any)(...args);
},this._debounceTime);
}) as any;
}
并使用
var foo = new debouncedMethod((name,age)=>{
console.log(name,age);
},500);
foo.invoke("john",31);
答案 36 :(得分:0)
如果您不喜欢添加lodash
或任何其他软件包:
import React, { useState, useRef } from "react";
function DebouncedInput() {
const [isRefetching, setIsRefetching] = useState(false);
const [searchTerm, setSearchTerm] = useState("");
const previousSearchTermRef = useRef("");
function setDebouncedSearchTerm(value) {
setIsRefetching(true);
setSearchTerm(value);
previousSearchTermRef.current = value;
setTimeout(async () => {
if (previousSearchTermRef.current === value) {
try {
// await refetch();
} finally {
setIsRefetching(false);
}
}
}, 500);
}
return (
<input
value={searchTerm}
onChange={(event) => setDebouncedSearchTerm(event.target.value)}
/>
);
}
答案 37 :(得分:0)
您可以使用tlence https://www.npmjs.com/package/tlence
function log(server) {
console.log('connecting to', server);
}
const debounceLog = debounce(log, 5000);
// just run last call to 5s
debounceLog('local');
debounceLog('local');
debounceLog('local');
debounceLog('local');
debounceLog('local');
debounceLog('local');
答案 38 :(得分:0)
今天遇到了这个问题。使用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
答案 39 :(得分:0)
扩展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>
答案 40 :(得分:0)
以下是使用@Abra方法包装在功能组件中的代码段 (我们在用户界面中使用结构,只需将其替换为简单的按钮即可)
import React, { useCallback } from "react";
import { debounce } from "lodash";
import { PrimaryButton, DefaultButton } from 'office-ui-fabric-react/lib/Button';
const debounceTimeInMS = 2000;
export const PrimaryButtonDebounced = (props) => {
const debouncedOnClick = debounce(props.onClick, debounceTimeInMS, { leading: true });
const clickHandlerDebounced = useCallback((e, value) => {
debouncedOnClick(e, value);
},[]);
const onClick = (e, value) => {
clickHandlerDebounced(e, value);
};
return (
<PrimaryButton {...props}
onClick={onClick}
/>
);
}
答案 41 :(得分:0)
避免使用event.persist()
-您想让React回收合成事件。我认为无论您使用类还是钩子,最干净的方法是将回调分为两部分:
课程
handleMouseOver = throttle(target => {
console.log(target);
}, 1000);
onMouseOver = e => {
this.handleMouseOver(e.target);
};
<div onMouseOver={this.onMouseOver} />
功能
const handleMouseOver = useRef(throttle(target => {
console.log(target);
}, 1000));
function onMouseOver(e) {
handleMouseOver.current(e.target);
}
<div onMouseOver={this.onMouseOver} />
请注意,如果您的handleMouseOver
函数使用组件内部的状态,则应使用useMemo
而不是useRef
并将其作为依赖项进行传递,否则您将使用过时的数据(确实当然不适用于课程。
答案 42 :(得分:-2)
你也可以使用自编的mixin,如下所示:
var DebounceMixin = {
debounce: function(func, time, immediate) {
var timeout = this.debouncedTimeout;
if (!timeout) {
if (immediate) func();
this.debouncedTimeout = setTimeout(function() {
if (!immediate) func();
this.debouncedTimeout = void 0;
}.bind(this), time);
}
}
};
然后在你的组件中使用它:
var MyComponent = React.createClass({
mixins: [DebounceMixin],
handleClick: function(e) {
this.debounce(function() {
this.setState({
buttonClicked: true
});
}.bind(this), 500, true);
},
render: function() {
return (
<button onClick={this.handleClick}></button>
);
}
});
答案 43 :(得分:-8)
对于合适的油门功能,人们不需要大量的局部变量。节流功能的目的是减少浏览器资源,而不是应用你正在使用的更多开销。作为这种说法的证据的证据,我设计了一种只有4&#34;悬挂&#34;变量在其范围内。 (A&#34;悬挂&#34;变量是一个永远不会被垃圾收集的变量,因为它总是被一个可以潜在调用的函数引用,从而吸收内存。)少数油门功能通常不会造成任何伤害;但是,如果有数千个节流函数,那么如果使用非常低效的油门功能,内存将开始变得稀缺。我的解决方案如下。
var timenow=self.performance ? performance.now.bind(performance) : Date.now;
function throttle(func, alternateFunc, minInterval) {
var lastTimeWent = -minInterval, freshArguments=null;
function executeLater(){
func.apply(null, freshArguments);
freshArguments = null;
lastTimeWent = 0;
}
return function() {
var newTimeWent = timenow();
if ((newTimeWent-lastTimeWent) > minInterval) {
lastTimeWent = newTimeWent;
return func.apply(null, arguments);
} else {
if (freshArguments === null)
setTimeout(executeLater, minInterval-(newTimeWent-lastTimeWent));
freshArguments = arguments;
if (typeof alternateFunc === "function")
return alternateFunc.apply(null, arguments);
}
};
}
然后,将此限制函数包装在EventTarget中,用于DOM点击,窗口事件,XMLHttpRequests onprogress,FileReader onprogress,[等]等内容,如下所示:
var tfCache = []; // throttled functions cache
function listen(source, eventName, func, _opts){
var i = 0, Len = tfCache.length, cF = null, options = _opts || {};
a: {
for (; i < Len; i += 4)
if (tfCache[i] === func &&
tfCache[i+1] === (options.ALTERNATE||null) &&
tfCache[i+2] === (options.INTERVAL||200)
) break a;
cF = throttle(func, options.ALTERNATE||null, options.INTERVAL||200);
tfCache.push(func, options.ALTERNATE||null, options.INTERVAL||200, cF);
}
source.addEventListener(eventName, cF || tfCache[i+3], _opts);
return cF === null; // return whether it used the cache or not
};
function mute(source, eventName, func, _opts){
var options = _opts || {};
for (var i = 0, Len = tfCache.length; i < Len; i += 4)
if (tfCache[i] === func &&
tfCache[i+1] === (options.ALTERNATE||null) &&
tfCache[i+2] === (options.INTERVAL||200)
) {
source.removeEventListener(eventName, tfCache[i+3], options);
return true;
}
return false;
}
下面是一个按钮的示例,该按钮被限制为每秒仅侦听一次点击。收到此次点击后,它会变为新的随机颜色。
(function(){"use strict";
// The function throttler //
var timenow=self.performance ? performance.now.bind(performance) : Date.now;
function throttle(func, alternateFunc, minInterval) {
var lastTimeWent = -minInterval, freshArguments=null;
function executeLater(){
func.apply(null, freshArguments);
freshArguments = null;
lastTimeWent = 0;
}
return function() {
var newTimeWent = timenow();
if ((newTimeWent-lastTimeWent) > minInterval) {
lastTimeWent = newTimeWent;
return func.apply(null, arguments);
} else {
if (freshArguments === null)
setTimeout(executeLater,minInterval-(newTimeWent-lastTimeWent));
freshArguments = arguments;
if (typeof alternateFunc === "function")
return alternateFunc.apply(this, arguments);
}
};
}
// The EventTarget wrapper: //
var tfCache = []; // throttled functions cache
function listen(source, eventName, func, _opts){
var i = 0, Len = tfCache.length, cF = null, options = _opts || {};
a: {
for (; i < Len; i += 4)
if (tfCache[i] === func &&
tfCache[i+1] === (options.ALTERNATE||null) &&
tfCache[i+2] === (options.INTERVAL||200)
) break a;
cF = throttle(func, options.ALTERNATE||null, options.INTERVAL||200);
tfCache.push(func, options.ALTERNATE||null, options.INTERVAL||200, cF);
}
source.addEventListener(eventName, cF || tfCache[i+3], _opts);
return cF === null; // return whether it used the cache or not
};
function mute(source, eventName, func, _opts){
var options = _opts || {};
for (var i = 0, Len = tfCache.length; i < Len; i += 4)
if (tfCache[i] === func &&
tfCache[i+1] === (options.ALTERNATE||null) &&
tfCache[i+2] === (options.INTERVAL||200)
) {
source.removeEventListener(eventName, tfCache[i+3], options);
return true;
}
return false;
}
// Finally, the color changing button: //
function randHex(){ // weighted towards the ends of the scales for contrast
var rand = Math.random()*2 - 1; // equally offcenter it from one
var sign = rand < 0 ? -1 : 1; // get a sign-ish value
rand = Math.sqrt(rand * sign) * sign; // stretch it further from zero
rand = 128 + rand * 128; // next, recenter it to range from 0 to 255
var str = (rand | 0).toString(16); // make an integer string
while (str.length < 2) str = "0" + str; // pad it
return str; // finally, return it
}
var clickerEle = document.getElementById("clicker");
var dropperEle = document.getElementById("droppedClicks");
var deDs = dropperEle.dataset; // deDs = droperEle DataSet
var dropSkips = 0;
function whenClick(){
if (dropSkips > 10) { // if the user clicked fast enough
mute(clickerEle, "click", whenClick, theOptions);
dropperEle.textContent = "You won with " + dropSkips +
" clicks per second! The button no longer changes color";
}
dropSkips = 0;
deDs ? delete deDs.numdrops : dropperEle.removeAttribute("data-numdrops");
clickerEle.setAttribute("style", "background:#"+randHex()+randHex()+randHex());
}
var theOptions = {
ALTERNATE: function(){
// whenever the main function is skipped:
deDs.numdrops = dropSkips += 1;
},
INTERVAL: 2000,
passive: true
};
listen(clickerEle, "click", whenClick, theOptions);
whenClick(); // to start changing the color
document.body.addEventListener("contextmenu", function(x){x.preventDefault()});
})();
&#13;
#droppedClicks[data-numdrops]::before {
content: "Dropped " attr(data-numdrops) " clicks";
color: green;
}
&#13;
Click the button below as fast as you can! You win when you are able to click the button more than ten times in a single second ().<br />
<br />
<button id="clicker"><h3>Click me</h3></button>
<div id="droppedClicks"></div>
&#13;
保存这个答案后,我发现有毒的SO社区&#39;持久的downvotes阻止此代码段运行。因此,这是一个指向JSFiddle的链接:https://jsfiddle.net/t7ymkzLx/2/
默认情况下,此功能限制为每200ms最多一次调用。要将间隔更改为不同的毫秒数,请在options参数中传递optionsObject.INTERVAL
选项,并将其设置为执行之间所需的最小毫秒数。 (因为定时器并不总是最精确的,)如果你有一个确切的最小间隔,那么我建议你从所需的optionsObject.INTERVAL
中减去一两个,以确保它总是至少应该被执行。如果在受限制的函数执行被延迟(由于过多的调用)时需要对限制的func的参数执行某些操作,则使用optionsObject.ALTERNATE
选项。这&#34;替代&#34;是一个函数,只要删除对主函数的调用,就会立即调用它来代替主函数。例如,如果您在EventTarget上使用限制函数,但想要对已删除的事件preventDefault()
,则使用{ALTERNATE: function(evt){ evt.preventDefault(); }}
作为选项对象。