【问题标题】:preactjs, onclick toggler firing twicepreactjs,onclick 切换器触发两次
【发布时间】:2018-10-23 13:57:12
【问题描述】:

我在使用 preactjs 时遇到了一个奇怪的行为,这很奇怪,因为我从来没有在 react 中遇到过这种情况。看看这个小提琴:

http://jsfiddle.net/8s4vhknt/

这是一个超级简单的组件,带有一个用作切换器的按钮。 请打开浏览器控制台并查看控制台日志。

最初活动状态属性为假 -> 不活动。 当您第一次单击问号时,正如预期的那样,调用切换功能,目标是按钮(注意,在我的本地环境中,事件目标结果是“.help-overlay”元素(应该仅在状态更改后才呈现),有什么想法吗?

然后将state active prop设置为true,再次渲染组件->控制台中的ACTIVE,按钮发生变化。

现在点击按钮将触发onclick 事件两次,显然没有任何变化。

我知道,这东西在某种程度上与事件传播有关,事实上,在切换函数的开头添加 e.stopPropagation() 就可以了

但我不明白为什么!我的意思是,事件应该通过 dom 向上传播,为什么要在同一个元素上再次触发相同的 onclick 处理程序?

这就是为什么我不寻求解决方案,而是寻求对我无法理解的情况的解释。

我这里贴出小提琴中组件广告的代码。

const { h, render, Component } = preact;    // normally this would be an import statement.

class Help extends Component {
  constructor () {
    super()
    this.state = {active: false}
    this.toggle = this.toggle.bind(this)
  }

  toggle (e) {
    console.log('ONCLICK', new Date().getTime(), e.target)
    this.setState(state => ({active: !state.active}))
  }

  render () {
    if (!this.state.active) {
      console.log('NOT ACTIVE')
      return (
        <div class='help-btn' onClick={this.toggle}>?</div>
      )
    } else {
      console.log('ACTIVE')
      return (
        <div class='help-overlay'>
          <div class='help-btn' onClick={this.toggle}>✕</div>
        </div>
      )
    }
  }
}

// render an instance of Clock into <body>:
render(<Help />, document.body);

【问题讨论】:

  • 这与&lt;div class='help-overlay'&gt; 元素有关。如果您使用 &lt;div class='help-overlay'&gt; 包装这两个元素或将其完全删除,它将按预期工作。不知道为什么,可能是因为内部元素在 VDOM 中并没有真正改变,而是在 DOM 中重新注册?
  • 嗨@Sagivb.g,谢谢。我想你可以在这里找到重点。但我会说相反:一个真实的两个虚拟dom元素,因为否则我无法想象不同真实dom事件的两个处理程序如何触发两次。虽然绑定到同一个 dom 元素的两个虚拟 dom 元素可能会在这个 dom 元素被触发时做出反应(啊哈)。但无论如何,这对我来说听起来像是一个错误(react 的行为不是这样,证明了)。而且我不明白为什么 stopPropagation 调用会修复这些东西。再见!
  • 不要忘记,这些是反应中的合成事件,而不是 preact 中的合成事件(据我所知)。如果您在此处发布问题并将其链接到此处会很好,以便我们跟进。
  • 也许你可以添加你的例子in this issue
  • 我会提出问题,谢谢

标签: javascript dom-events preact


【解决方案1】:

在一个 dom 中而不在其他 dom 中具有覆盖类的 div 创建一个 vdom 差异,它将启动重新渲染触发器。 我已经用父 div 包装了两个 div,包含条件覆盖类,它按预期工作。

.help-btn {
  background: #000;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
}

.help-overlay {
  background: rgba(0, 0, 0, .7);
  height: 100%;
  left: 0;
  position: absolute;
  top: 0;
  width: 100%;
  z-index: 9;
}

/** @jsx h */
const { h, render, Component } = preact;    // normally this would be an import statement.

class Help extends Component {
  constructor () {
    super()
    this.state = {active: false};
  }

  toggle (e,isActive) {
    console.log('ONCLICK', new Date().getTime(), e.target)
    this.setState({active:!isActive});
  }

  render (props,{active}) {
        return (
        <div class={active ? "help-overlay" : "" }>
        {!active && <div class='help-btn' onClick={e => this.toggle(e,false)}>?</div>}
        {active && <div class='help-btn' onClick={e => this.toggle(e,true)}>✕</div>}
        </div>
      )
  }
}

// render an instance of Clock into <body>:
render(<Help />, document.body);

jsfiddle - http://jsfiddle.net/nhkz4feq/

【讨论】:

  • 嗨@front_end_dev,感谢您的回答。我知道我可以解决问题,但我的问题仍然存在。 “一个 dom 而不是其他 dom 中的覆盖类创建一个 vdom 差异,它将启动重新渲染的触发器”,我认为这不是重点。 dom因为它的不同而没有重新渲染,直到它重新渲染它才存在,它是因为状态改变而重新渲染的。我认为 Savig b.g 可能已经找到了重点。
猜你喜欢
  • 2022-09-03
  • 1970-01-01
  • 1970-01-01
  • 2013-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
相关资源
最近更新 更多