[英]ReactJS can't set state from an event with event.persist()
我需要设置一个从事件中获取的状态字段,但是当我将函数传递给它时它不会被设置。 组件和方法如下所示:
constructor(props: SomeProps, context: any) {
super(props, context);
this.state = {
isFiltering: props.isFiltering,
anchor: "",
};
}
private toggleFilter = (event: any) => {
event.persist()
this.setState(prevState => ({
isFiltering: !prevState.isFiltering,
anchor: event.currentTarget // does not work, it's null
}));
}
如果我删除event.persist()
然后我收到以下错误:
出于性能原因重用此合成事件。 如果您看到这一点,则表示您正在访问已发布/已取消的合成事件的方法
currentTarget
。 这是一个空操作函数。 如果您必须保留原始合成事件,请使用 event.persist()。 有关详细信息,请参阅https://facebook.github.io/react/docs/events.html#event-pooling 。
由于某种原因,以下代码有效:
private toggleFilter = (event: any) => {
this.setState({anchor:event.currentTarget}) // works fine
this.setState(prevState => ({
isFiltering: !prevState.isFiltering,
}));
}
为什么上面的方法有效,但当我使用this.setState(prevState=>...)
?
这是预期的行为,因为event.persist()
并不意味着currentTarget
没有被取消,事实上它应该是 - 这符合浏览器的本机实现。
这意味着如果您想以异步方式访问 currentTarget ,则需要像您在答案中那样将其缓存在变量中。
引用其中一位 React 核心开发人员 - Sophie Alpert 。
currentTarget 随着事件的冒泡而改变——如果您在接收事件的元素上有一个事件处理程序,而在其祖先上有其他事件处理程序,他们会看到不同的 currentTarget 值。 IIRC 取消它与本地事件发生的情况一致; 如果没有,请告诉我,我们将重新考虑我们的行为。
查看官方 React 存储库中讨论的来源,以及 Sophie 提供的以下片段,我已经稍微触及了一下。
var savedEvent; var savedTarget; divb.addEventListener('click', function(e) { savedEvent = e; savedTarget = e.currentTarget; setTimeout(function() { console.log('b: currentTarget is now ' + e.currentTarget); }, 0); }, false); diva.addEventListener('click', function(e) { console.log('same event object? ' + (e === savedEvent)); console.log('same target? ' + (savedTarget === e.currentTarget)); setTimeout(function() { console.log('a: currentTarget is now ' + e.currentTarget); }, 0); }, false);
div { padding: 50px; background: rgba(0,0,0,0.5); color: white; }
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>JS Bin</title> </head> <body> <div id="diva"><div id="divb"> Click me and see output! </div></div> </body> </html>
通过 @thirtydot 的评论,我得到了一个可行的解决方案。
我认为这是因为 setState 是“异步的”,所以当你传递给 setState 的函数被执行(并且事件被访问)时,事件已经不存在了。 在第二个版本中,立即访问事件并将其 currentTarget 传递给 setState
所以我将event.currentTarget
存储到一个变量并使用它,正如ReactJs 事件池中所解释的那样
看起来像这样并且有效
private toggleFilter = (event: any) => {
let target = event.currentTarget;
this.setState((prevState) => ({
isFiltering: !prevState.isFiltering,
anchor: target
}));
}
然而,这并不能解释为什么event.persist()
不起作用。 我会接受解释它的答案。
要解决此问题 - 在调用表单的 handleSubmit 之前,调用 event.persist() 然后在 handleSubmit() 定义中 - 编写您的逻辑。 例如
<form id="add_exp_form" onSubmit={(event) => {event.persist();this.handleSubmit(event)}}>
handleSubmit(event){
// use event.currentTarget - It will be visible here
}
在您的函数中,您应该使用 const event.preventDefault()
或event.prevent()
例子:
updateSpecs1 = (event) => {
event.preventDefault()
我在动态填充组件时遇到了类似的警告消息,为了解决这个问题,我只需要用箭头函数包装函数。
从:
{ text: "Delete item", onClick: deleteItem },
到:
{ text: "Delete item", onClick: (id) => deleteItem(id) },
关于这个问题有一个很好的描述和 2 个不同的解决方案,您可以查看此链接
您可以像这样使用柯里化函数来处理它。
const persistEvent = (fun: any) => (e: any) => {
e.persist();
fun(e);
};
现在你可以像这样写你的函数
persistEvent(toggleFilter);
它将是这样的:
const persistEvent = (fun: any) => (e: any) => {
e.persist();
fun(e);
};
const delayedFunctionality = (e) => {
setTimeout(()=> {
console.log(e.target.value)
},500
}
<input onChange={persistEvent(delayedFunctionality)} />
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.