如果我在调用setState
之后添加一个事件监听器,我希望只有在我再次触发该事件时才会调用该事件监听器。但是,从下面的示例中,当我单击div时,在状态更改后调用事件侦听器。
如果我删除了addEventListener
或者我在evt.stopPropagation()
内调用了toggleOpen
,就不会发生这种情况,但我想知道为什么事件监听器会被调用我改变状态后设置它。
不会setState
异步更改状态,这意味着在事件传播后会调用回调吗?
import React from 'react';
import classNames from 'classnames';
import css from './Dropdown.scss';
export class Dropdown extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false,
}
}
toggleOpen = (evt) => {
window.removeEventListener('click', this.toggleOpen);
this.setState({
open: !this.state.open,
}, () => {
window.addEventListener('click', this.toggleOpen);
});
}
render() {
const dropdownContentClasses = classNames(css.dropdownContent, {
[css.dropdownContent_open]: this.state.open,
});
console.log(this.state.open)
return (
<div className={css.dropdownContainer}>
<div onClick={this.toggleOpen}>
{this.props.title}
</div>
<div className={dropdownContentClasses}>
{this.props.children}
</div>
</div>
)
}
}
答案 0 :(得分:1)
2件事。首先,从https://reactjs.org/docs/react-component.html#setstate开始,您希望使用prevState
属性来计算新状态:
toggleOpen = evt => {
this.setState((prevState, props) => {
return { open : ! prevState.open };
});
}
其次,最好在componentDidMount()
阶段添加事件处理程序,并在componentWillUnmount()
阶段删除它:
componentDidMount() {
window.addEventListener('click', this.toggleOpen);
}
componentWillUnmount() {
window.removeEventListener('click', this.toggleOpen);
}
答案 1 :(得分:1)
似乎传播到达窗口时,会添加侦听器,然后调用eventListener。添加event.stopPropagation应该解决它。
答案 2 :(得分:1)
答案 3 :(得分:0)
我建议您使用componentDidMount
检查在state.open
内添加事件,而不是在toggleOpen上添加窗口事件。
componentDidMount() {
window.addEventListener('click', (e) => {
this.state.open && this.toggleOpen(e);
});
}
我在这里添加了一个小提琴:https://jsfiddle.net/69z2wepo/87489/