我在React中提供了一个简单的通知服务,遇到了一个非常奇怪的问题,我找不到任何提及或解决方案。
我的组件有一系列通知消息。每个“通知”都有一个“ onClick”和“ onAnimationEnd”绑定,它们调用一个函数,该函数将从通知数组中将其删除。基本思想是,通知将消失(使用CSS动画)然后被删除,或者允许用户手动单击通知以将其删除。
有趣的错误如下。如果添加两个通知,则第一个将触发其onAnimationEnd并将其删除。剩余的通知将突然跳到其CSS动画的结尾,并且永远不会触发其自己的onAnimationEnd。
更奇怪的是,如果添加四个通知,则恰好其中两个会出现上述错误,而另外两个则正常运行。
还值得一提的是,如果您创建两个通知,然后单击两个手动将其删除,则剩余的通知将正常运行并触发其自己的onAnimationEnd功能。
因此,我不得不得出这样的结论:除非有人可以指出解决此问题的方法,否则通过数组循环和onAnimationEnd触发器的某种组合在反应中会发生错误。
反应码
class Test extends React.Component {
constructor (props) {
super(props)
this.state = {
notifications: []
}
}
add = () => {
this.setState({notifications: [...this.state.notifications, 'Test']})
}
remove = (notification) => {
let notificationArray = this.state.notifications
notificationArray.splice(notificationArray.indexOf(notification), 1)
this.setState({notifications: notificationArray})
}
render() {
return (
<div>
<button onClick={this.add}>Add Notification</button>
<div className="notification-container">
{this.state.notifications.map(
(notification,i) => {
return (
<div onAnimationEnd={()=>this.remove(notification)}
onClick={() => this.remove(notification)}
className="notification"
key={i}>
{notification}
</div>
)
}
)}
</div>
</div>
);
}
}
ReactDOM.render(
<Test />,
document.getElementById('root')
);
CSS
.notification-container {
position: fixed;
bottom: 20px;
right: 20px;
width: 200px;
}
.notification {
border: 1px solid;
box-shadow: 0 10px 20px rgba(0,0,0,0.2), 0 6px 6px rgba(0,0,0,0.25);
color: white;
background: rgba(0,0,0,0.75);
cursor: pointer;
padding: 10px;
margin-top: 10px;
user-select: none;
animation: fade 7s linear forwards;
}
@keyframes fade {
0% {
transform: translate(100%,0);
}
2% {
transform: translate(-20px, 0);
}
5% {
transform: translate(0,0);
}
20% {
opacity: 1;
}
100% {
opacity: 0.25;
}
}
工作Codepen链接 https://codepen.io/msorrentino/pen/xeVrwz
答案 0 :(得分:1)
您正在使用数组索引作为组件键:
benefit.id
执行此操作时,React无法正确检测何时删除了组件。例如,通过删除索引为0的项目并将其移至索引1的位置,React会认为键0的项目只是被修改而不是删除。这可能会产生各种副作用,例如您所看到的。
如果有,请尝试使用唯一标识符,否则请使用某种增量键。
要在您的码本中真正快速地进行测试,请更改以下位(当然,我实际上不建议您使用消息作为密钥):
{this.state.notifications.map(
(notification,i) => {
return (
<div onAnimationEnd={()=>this.remove(notification)}
onClick={() => this.remove(notification)}
className="notification"
key={i}>
{notification}
</div>
)
}
)}
数组索引只能作为最后的手段用作组件键。