使用 react/redux 去抖动 textarea 输入

IT技术 javascript reactjs redux lodash
2021-04-27 10:38:38

我正在尝试使用 react/redux 去抖动 textarea 值并在其中显示去抖动值,div#preview但在第一次函数调用后我收到合成事件警告。

我有用于处理按预期工作的 textarea 值状态的 reducer,但为简单起见,我在此代码段中编写了本地状态。

如果除了debounce避免在每次之后重新渲染之外还有更好的方法keypress我很想知道。提前致谢。

class TextArea extends React.Component {
  constructor(props){
    super(props);
    this.state = {foo: ''}
  }
  
  handleInputChange = _.debounce((e) => {
    e.persist();
    let value = e.target.value;
    this.setState({foo: value});
  }, 300);

  render() {
    return (
      <div>
       <textarea onChange={(e)=>this.handleInputChange(e)} value={this.state.foo}></textarea>
       <p id="preview">{this.state.foo}</p>
      </div>
    );
  }
}


ReactDOM.render(
  <TextArea />,
  document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

3个回答

您收到此错误是因为您尝试.persist()debounce的超时内处理事件当超时调用回调时,合成事件已经被释放。因此,您必须在去抖动之外保留该事件。

但是,您的想法还有另一个问题。由于文本框是一个受控组件,对更新的值进行去抖动会导致文本框仅在用户停止输入后呈现(部分)文本。

为防止发生这种情况,您需要立即更新受控元素的状态,并对显示状态(或 redux 动作调度)的更新进行去抖动。

例如:

class TextArea extends React.Component {
  constructor(props){
    super(props);
    this.state = { foo: '', controlled: '' }
  }
  
  updateFoo = _.debounce((value) => { // this can also dispatch a redux action
    this.setState({foo: value});
  }, 300);
  
  handleInputChange = (e) => {
    const value = e.target.value;
    
    this.setState({
      controlled: value
    });
    
    this.updateFoo(value);
  }

  render() {
    return (
      <div>
       <textarea onChange={ this.handleInputChange }
       value={this.state.controlled} />
       <p id="preview">{this.state.foo}</p>
      </div>
    );
  }
}


ReactDOM.render(
  <TextArea />,
  document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="react"></div>

另一个答案已经涵盖了持久化事件的问题。对于输入去抖动方面,您可能需要阅读我的博客文章Practical Redux,第 7 部分:表单更改处理在那篇文章中,我展示了一个可重用的组件,它可以处理应用程序其余部分的文本输入更新去抖动,同时允许它们立即使用当前值重新渲染。

我为此苦苦挣扎,无法自己取得令人满意的结果。最终,我使用了https://github.com/nkbt/react-debounce-input,它运行良好,而且比我之前失败的尝试简单得多。

  /**
   * Updates the current node "text" value.
   *
   * @param event
   */
  const onTextInputValueChange = (event: any) => {
    const newValue = event.target.value;
    patchCurrentNode({
      data: {
        text: newValue,
      },
    } as InformationNodeData);
  };
    

  <DebounceInput
          element={'textarea'}
          debounceTimeout={500}
          placeholder={'Say something here'}
          onChange={onTextInputValueChange}
          value={node?.data?.text}
        />

patchCurrentNode 写入我的 Recoil 商店。

DebounceInput组件处理一个内部状态以显示最新值,同时只偶尔更新存储中的值。

实现不是 Recoil 特有的,使用 Redux 可能会像魅力一样工作。