【问题标题】:Using debouncer with React event将 debouncer 与 React 事件一起使用
【发布时间】:2016-05-27 21:08:05
【问题描述】:

我有一个需要去抖动的字段的onchange 事件,我为此使用下划线,但是当我使用去抖动器时,传递给 React 处理程序的事件似乎已过期。

<div className='input-field'>
  <input onChange={_.debounce(this.uriChangeHandler.bind(this), 500)} id='source_uri' type='text' name='source_uri' autofocus required />
  <label htmlFor='source_uri'>Website Link</label>
</div>

uriChangeHandler(event) {
    event.preventDefault();
    let uriField = $(event.target);
    let uri = uriField.val();
    this.setState({
        itemCreateError: null,
        loading: true
    });
    this.loadUriMetaData(uri, uriField);
}

我收到此错误:

警告:出于性能原因,此合成事件会被重复使用。如果您看到这一点,则表示您正在对已发布/无效的合成事件调用 preventDefault。这是一个无操作。有关详细信息,请参阅 https‍://fb‍.me/react-event-pooling。

使用onchange 而不使用去抖器可以正常工作。

【问题讨论】:

  • 不,我用this.debouncedUriChangeHandler = _.debounce(this.uriChangeHandler, 500); 尝试过,但得到了同样的错误

标签: javascript reactjs underscore.js dom-events debouncing


【解决方案1】:

我最终得到了一个我在 github 上看到的对我来说效果很好的解决方案。基本上你将 debounce 函数包装在一个自定义函数 debounceEventHandler 中,它将在返回 debounce 函数之前保持事件。

function debounceEventHandler(...args) {
  const debounced = _.debounce(...args)
  return function(e) {
    e.persist()
    return debounced(e)
  }
}

<Input onChange={debounceEventHandler(this.handleInputChange, 150)}/>

这摆脱了合成事件警告

【讨论】:

  • 像魅力一样工作!我将此添加为全局导出以方便使用。
【解决方案2】:

在你的情况下它可能会有所帮助

class HelloWorldComponent extends React.Component {
  uriChangeHandler(target) {
    console.log(target)
  }

  render() {
    var myHandler = _.flowRight(
      _.debounce(this.uriChangeHandler.bind(this), 5e2),
      _.property('target')
    );
    return (      
      <input onChange={myHandler}  />
    );
  }
}

React.render(
  <HelloWorldComponent/>,
  document.getElementById('react_example')
);

JSBin

如果您想获取完整的事件对象,也可以使用_.clone 代替_.property('target')

已编辑

为防止 React 使事件无效,您必须调用 event.persist(),如 React doc 所述:

如果您想以异步方式访问事件属性,您应该在事件上调用 event.persist(),这将从池中删除合成事件并允许用户代码保留对事件的引用。

因此您可以使用e =&gt; e.persist() || e 而不是_.clone JSBin

【讨论】:

  • 成功了,谢谢!你能解释一下怎么做吗?我使用了_.clone 位而不是_.property
【解决方案3】:

我选择了xiaolin的答案和useMemo的组合:

const MyComponent = () => {
  const handleChange = useMemo(() => {
    const debounced = _.debounce(e => console.log(e.target.value), 1000);
    return e => {
      e.persist();
      return debounced(e);
    };
  }, []);
  return <input onChange={handleChange} />;
};

【讨论】:

    【解决方案4】:

    我认为正在发生的事情是,在实际事件和调用您的方法之间的时间内,该事件被取消了。查看_.debounce source code(并使用我们对去抖动函数的了解)会告诉您,直到事件触发 500 毫秒后才会调用您的方法。所以你有这样的事情发生:

    1. 事件触发
    2. _.debounce() 设置 500 毫秒超时
    3. React 使 event 对象无效
    4. 计时器触发并调用您的事件处理程序
    5. 您在无效事件上调用 event.stopPropagation()

    我认为您有两种可能的解决方案:每次事件触发时(在去抖动之外)调用 event.stopPropagation(),或者根本不调用它。

    旁注:即使使用原生事件,这仍然是一个问题。当您的处理程序实际被调用时,该事件已经传播。 React 只是在警告你做了一些奇怪的事情方面做得更好。

    【讨论】:

      【解决方案5】:
      class HelloWorldComponent extends Component {
          _handleInputSearchChange = (event) => {
              event.persist();
              _.debounce((event) => {
                  console.log(event.target.value);
              }, 1000)(event);
          };
      
          render() {
              return (
                  <input onChange={this._handleInputSearchChange}  />
              );
          }
      }
      

      【讨论】:

      • 这太聪明了
      • 这不是一个合适的解决方案。它在每个 onChange 事件上调用 debounce。 @xiaolin 的解决方案是正确的方法。
      【解决方案6】:

      这里的想法是我们希望 onChange 处理程序首先保持事件,然后立即解除我们的事件处理程序,这可以通过以下代码简单地实现:

      <input
      onChange={_.flowRight(
        _.debounce(this.handleOnChange.bind(this), 300),
        this.persistEvent,
      )}
      </input>
      
      persistEvent = e => {
        e.persist();
        e.preventDefault();
        return e;
      };
      
      handleOnChange = e => {
        console.log('event target', e.target);
        console.log('state', this.state);
        // here you can add you handler code 
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-16
        • 1970-01-01
        • 2016-08-03
        • 1970-01-01
        • 2016-11-20
        • 2018-07-18
        相关资源
        最近更新 更多