8

我有一个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不带去抖动器的效果很好。

4

6 回答 6

16

我最终得到了一个我在 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)}/>

这摆脱了合成事件警告

于 2016-05-19T00:38:10.183 回答
3

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

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 使事件无效,您必须按照React docevent.persist()中的说明调用:

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

因此你可以使用e => e.persist() || e而不是_.clone JSBin

于 2016-02-16T15:08:52.820 回答
2

我结合了小林的回答和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} />;
};
于 2020-03-04T02:34:03.320 回答
0

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

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

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

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

于 2016-02-16T14:57:44.630 回答
0
class HelloWorldComponent extends Component {
    _handleInputSearchChange = (event) => {
        event.persist();
        _.debounce((event) => {
            console.log(event.target.value);
        }, 1000)(event);
    };

    render() {
        return (
            <input onChange={this._handleInputSearchChange}  />
        );
    }
}
于 2017-05-05T19:14:11.337 回答
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 
}
于 2018-05-18T10:52:49.350 回答