将 debouncer 与 React 事件一起使用
Posted
技术标签:
【中文标题】将 debouncer 与 React 事件一起使用【英文标题】:Using debouncer with React event 【发布时间】:2016-05-27 21:08:05 【问题描述】:我有一个需要去抖动的字段的onchange
事件,我为此使用下划线,但是当我使用去抖动器时,传递给 React 处理程序的事件似乎已过期。
<div className='input-field'>
<input onChange=_.debounce(this.uriChangeHandler.bind(this), 500) id='source_uri' type='text' name='source_uri' autofocus required />
<label htmlFor='source_uri'>Website Link</label>
</div>
uriChangeHandler(event)
event.preventDefault();
let uriField = $(event.target);
let uri = uriField.val();
this.setState(
itemCreateError: null,
loading: true
);
this.loadUriMetaData(uri, uriField);
我收到此错误:
警告:出于性能原因,此合成事件会被重复使用。如果您看到这一点,则表示您正在对已发布/无效的合成事件调用 preventDefault。这是一个无操作。有关详细信息,请参阅 https://fb.me/react-event-pooling。
使用onchange
而不使用去抖器可以正常工作。
【问题讨论】:
这有帮助吗? ***.com/q/23123138/870769 不,我用this.debouncedUriChangeHandler = _.debounce(this.uriChangeHandler, 500);
尝试过,但得到了同样的错误
【参考方案1】:
我最终得到了一个我在 github 上看到的对我来说效果很好的解决方案。基本上你将 debounce 函数包装在一个自定义函数 debounceEventHandler
中,它将在返回 debounce 函数之前保持事件。
function debounceEventHandler(...args)
const debounced = _.debounce(...args)
return function(e)
e.persist()
return debounced(e)
<Input onChange=debounceEventHandler(this.handleInputChange, 150)/>
这摆脱了合成事件警告
【讨论】:
像魅力一样工作!我将此添加为全局导出以方便使用。【参考方案2】:在你的情况下它可能会有所帮助
class HelloWorldComponent extends React.Component
uriChangeHandler(target)
console.log(target)
render()
var myHandler = _.flowRight(
_.debounce(this.uriChangeHandler.bind(this), 5e2),
_.property('target')
);
return (
<input onChange=myHandler />
);
React.render(
<HelloWorldComponent/>,
document.getElementById('react_example')
);
JSBin
如果您想获取完整的事件对象,也可以使用_.clone
代替_.property('target')
。
已编辑
为防止 React 使事件无效,您必须调用 event.persist()
,如 React doc 所述:
如果您想以异步方式访问事件属性,您应该在事件上调用 event.persist(),这将从池中删除合成事件并允许用户代码保留对事件的引用。
因此您可以使用e => e.persist() || e
而不是_.clone
JSBin
【讨论】:
成功了,谢谢!你能解释一下怎么做吗?我使用了_.clone
位而不是_.property
【参考方案3】:
我选择了xiaolin的答案和useMemo的组合:
const MyComponent = () =>
const handleChange = useMemo(() =>
const debounced = _.debounce(e => console.log(e.target.value), 1000);
return e =>
e.persist();
return debounced(e);
;
, []);
return <input onChange=handleChange />;
;
【讨论】:
【参考方案4】:我认为正在发生的事情是,在实际事件和调用您的方法之间的时间内,该事件被取消了。查看_.debounce
source code(并使用我们对去抖动函数的了解)会告诉您,直到事件触发 500 毫秒后才会调用您的方法。所以你有这样的事情发生:
-
事件触发
_.debounce()
设置 500 毫秒超时
React 使 event
对象无效
计时器触发并调用您的事件处理程序
您在无效事件上调用 event.stopPropagation()
。
我认为您有两种可能的解决方案:每次事件触发时(在去抖动之外)调用 event.stopPropagation()
,或者根本不调用它。
旁注:即使使用原生事件,这仍然是一个问题。当您的处理程序实际被调用时,该事件已经传播。 React 只是在警告你做了一些奇怪的事情方面做得更好。
【讨论】:
【参考方案5】:class HelloWorldComponent extends Component
_handleInputSearchChange = (event) =>
event.persist();
_.debounce((event) =>
console.log(event.target.value);
, 1000)(event);
;
render()
return (
<input onChange=this._handleInputSearchChange />
);
【讨论】:
这太聪明了 这不是一个合适的解决方案。它在每个 onChange 事件上调用 debounce。 @xiaolin 的解决方案是正确的方法。【参考方案6】:这里的想法是我们希望 onChange 处理程序首先保持事件,然后立即解除我们的事件处理程序,这可以通过以下代码简单地实现:
<input
onChange=_.flowRight(
_.debounce(this.handleOnChange.bind(this), 300),
this.persistEvent,
)
</input>
persistEvent = e =>
e.persist();
e.preventDefault();
return e;
;
handleOnChange = e =>
console.log('event target', e.target);
console.log('state', this.state);
// here you can add you handler code
【讨论】:
以上是关于将 debouncer 与 React 事件一起使用的主要内容,如果未能解决你的问题,请参考以下文章
如何将 React Context API 与 useReducer 一起使用以遵循与 Redux 类似的风格 [关闭]
react-autosuggest 与 debounce 和 distinctUntilChanged
无法使 react-hot-loader 和 webpack-dev-server 与 react-router 一起工作