为什么 ReactJS 在 setTimeout 中调用 setState 时会设置状态?

Why does ReactJS sets state when calling setState inside setTimeout?

在一个简单的 reactJS class 中,this.setState() 实际上并没有设置状态。我知道它是异步调用的,但即使组件再次呈现,状态也没有发生变化。所以 this.state.showModalfalse 当组件被安装时(如预期的那样)那么它是 true "forever".

这是一个简单的例子:

class MyComponent extends Component {
  constructor (props) {
    super(props)

    this.state = {
      showModal: false
    }

    this.showModal = this.showModal.bind(this)
    this.hideModal = this.hideModal.bind(this)
  }
  showModal () {
    this.setState({ showModal: true })
  }
  hideModal () {
    this.setState({ showModal: false })
  }
  render () {
    console.log(this.state.showModal) // Outputs true even after the hideModal() call

    return (
      <Components>
        <div onClick={this.showModal}>
          {
            this.state.showModal === true
            ? <Modal
              handles={handles}
              close={this.hideModal}
            />
            : '+'
          }
        </div>
      </Components>
    )
  }
}

这是模态组件:

class Modal extends Component {
  render () {
    return (
      <div className='configurator-modal'>
        <button className='close' onClick={this.props.close}> x </button>
        Modal
      </div>
    )
  }
}

但是,当我用这样的超时替换 hideModal 函数时:

setTimeout(() => this.setState({ showModal: false }), 0)

状态按预期变化和呈现。

我只是想知道为什么 ReactJS 可能会在内部重置状态或防止状态发生变异?

编辑:添加了对 hideModal 和 showModal 的调用

您在父元素上也有一个 click 处理程序,它调用 showModal 并将状态更改为 true。

当您单击 close 按钮时,将调用 hideModal 函数,这会将状态更改为 false 但该单击也会传播到父元素,这将调用showModal 再次成为 true。因此它始终保持 true.

解决方案: 从父元素中删除 showModal click handler 并把它放在你想要的地方(我想你想要它在 +).

既然没有渣男可以玩,我就来猜一猜。

div 作为 <Modal> 的父级,当在 Modal 上触发点击事件时,它也会传播到 div。因此 showModal 状态由 hideModal() 函数设置为 false 并由 showModal() 函数设置回 true

hideModal() 使用 setTimeout() 时,它在调用 showModal() 之后被调用。

尝试在 hideModal() 函数中添加 event.stopPropagation,它可能会起作用。

或者,您应该添加 showModal() 作为 + 标志的 onClick 处理程序,而不是整个父 div。请在下面找到代码:

<Components>
    <div>
      {
        this.state.showModal === true
        ? <Modal
          handles={handles}
          close={this.hideModal}
        />
        : <div onClick={this.showModal}>'+'</div>
      }
    </div>
  </Components>