我需要设置一个从事件中获取的状态字段,但是当我将一个函数传递给它时它不会被设置。组件和方法如下所示:
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=> ...)
时却没有?
答案 0 :(得分:25)
这是预期的行为,因为event.persist()
并不意味着currentTarget
没有被取消,实际上应该是 - 这符合浏览器的本机实现。
这意味着如果您想以异步方式访问currentTarget,则需要像在答案中一样将其缓存在变量中。
引用其中一个React核心开发人员 - Sophie Alpert。
currentTarget随着事件的冒泡而变化 - 如果你在接收事件的元素上有一个事件处理程序,而在其祖先上有其他人,他们会看到currentTarget的不同值。 IIRC将其归零与本机事件发生的情况一致;如果没有,请告诉我,我们会在这里重新考虑我们的行为。
查看官方React存储库中讨论的the source以及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>
答案 1 :(得分:12)
根据@thirtydot的评论,我得到了一个有效的解决方案。
我认为这是因为setState是“异步”的,所以当你传递给setState的函数被执行(并且访问了事件)时,事件就不再存在了。在第二个版本中,立即访问事件并将其currentTarget传递给setState
所以我将event.currentTarget
存储到变量中并按照ReactJs Event Pooling
看起来像这样并且有效
private toggleFilter = (event: any) => {
let target = event.currentTarget;
this.setState((prevState) => ({
isFiltering: !prevState.isFiltering,
anchor: target
}));
}
然而,这并不能解释为什么event.persist()
无效。我会接受解释它的答案。
答案 2 :(得分:2)
动态填充组件时遇到类似的警告消息,要解决此问题,我只需要用箭头功能包装功能即可。
发件人:
{ text: "Delete item", onClick: deleteItem },
收件人:
{ text: "Delete item", onClick: (id) => deleteItem(id) },
答案 3 :(得分:1)
要解决此问题-在调用表单的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
}
答案 4 :(得分:1)
关于此问题和两种不同的解决方案,都有不错的描述,您可以使用此link
进行检查答案 5 :(得分:0)
您可以使用此类的咖喱函数来处理它。
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)} />
答案 6 :(得分:0)
在你的函数中你应该使用 const event.preventDefault()
或 event.prevent()
示例:
updateSpecs1 = (event) => {
event.preventDefault()