使用debouncer与React事件

时间:2016-02-16 14:24:42

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

我有一个需要去抖动的字段的onchange事件,我正在使用下划线,但是当我使用debouncer时,传递给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);
}

我收到此错误:Warning: This synthetic event is reused for performance reasons. If you're seeing this, you're calling preventDefault on a released/nullified synthetic event. This is a no-op. See https://fb.me/react-event-pooling for more information.

使用onchange w / o debouncer工作正常。

6 个答案:

答案 0 :(得分:8)

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

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

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

这摆脱了合成事件警告

答案 1 :(得分: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')

<强> EDITED

为了防止React使活动无效,您必须按照React doc上的说明致电event.persist()

  

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

因此您可以使用e => e.persist() || e代替_.clone JSBin

答案 2 :(得分:2)

我结合了xiaolinuseMemo的答案:

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} />;
};

答案 3 :(得分:0)

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

  1. 事件触发
  2. _.debounce()设置500毫秒超时
  3. React使event对象
  4. 无效
  5. 计时器触发并调用您的事件处理程序
  6. 您在无效事件上致电event.stopPropagation()
  7. 我认为您有两种可能的解决方案:每次事件发生时(在去抖动之外)拨打event.stopPropagation(),或者根本不打电话。

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

答案 4 :(得分:0)

class HelloWorldComponent extends Component {
    _handleInputSearchChange = (event) => {
        event.persist();
        _.debounce((event) => {
            console.log(event.target.value);
        }, 1000)(event);
    };

    render() {
        return (
            <input onChange={this._handleInputSearchChange}  />
        );
    }
}

答案 5 :(得分:0)

这里的想法是我们希望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 
}