javascript 键入时 ReactJS 延迟 onChange

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/53071774/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 10:06:57  来源:igfitidea点击:

ReactJS delay onChange while typing

javascriptreactjs

提问by chris

I need the state to change to maintain the string the user is typing. However I want to delay an action until the user stops typing. But I can't quite place my finger on how to do both.

我需要更改状态以维护用户键入的字符串。但是我想延迟一个动作,直到用户停止输入。但我不能完全确定如何做到这两点。

So When the user stops typing I want an action to be triggered, but not before. Any suggestions?

所以当用户停止打字时,我希望触发一个动作,但不是之前。有什么建议?

回答by richardgirges

One way to do this would be to have your onChangehandler execute two functions:

一种方法是让您的onChange处理程序执行两个函数:

  • Function for immediately updating state
  • Debounced function
  • 立即更新状态的函数
  • 去抖函数

Example code:

示例代码:

import debounce from 'lodash.debounce';

class Foo extends React.Component {
  constructor() {
    super()

    this.state = {
      value: ''
    }

    // Delay action 2 seconds
    this.onChangeDebounced = debounce(this.onChangeDebounced, 2000)
  }

  handleInputChange = (e: Event) => {
    // Immediately update the state
    this.setState({
      value: e.target.value
    })

    // Execute the debounced onChange method
    this.onChangeDebounced(e)
  }

  onChangeDebounced = (e: Event) => {
    // Delayed logic goes here
  }

  render() {
    return (
      <input onChange={this.handleInputChange} value={this.state.value} />
    )
  }
}

回答by Chase DeAnda

Sounds you are going to need to use setTimeoutto start a timer as soon as the user enters text. If the user enters another character, restart the timer. If the user does not type again before the timer completes, it will fire an action that toggles the checkbox:

setTimeout一旦用户输入文本,您将需要使用声音来启动计时器。如果用户输入另一个字符,则重新启动计时器。如果用户在计时器完成之前没有再次输入,它将触发一个切换复选框的动作:

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      text: '',
      checked: false
    };
    this.timer = null;
  }
  
  componentDidUpdate (prevProps, prevState) {
    if(prevState.text !== this.state.text) {
      this.handleCheck();
    }
  }
  
  onChange = e => {
    this.setState({
      text: e.target.value
    });
  };
  
  handleCheck = () => {
    // Clears running timer and starts a new one each time the user types
    clearTimeout(this.timer);
    this.timer = setTimeout(() => {
      this.toggleCheck();
    }, 1000);
  }
  
  toggleCheck = () => {
    this.setState( prevState => ({ checked: !prevState.checked }));
  }
  
  render () {
    return (
      <div>
        <input value={this.state.text} onChange={this.onChange} placeholder="Start typing..." /><br/>
        <label>
          <input type="checkbox" checked={this.state.checked} onChange={this.toggleCheck} />
          Toggle checkbox after user stops typing for 1 second
        </label>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
<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="root"></div>

回答by jnforja

With React Hooks and Function components

使用 React Hooks 和 Function 组件

To keep the string the user is typing, use the useStatehook to store the text the user is typing. Then give that state to the value of the input. Also be sure to use setStateon the onChangeevent handler of the input, otherwise the input value won't change.

要保留用户正在键入的字符串,请使用useState钩子来存储用户正在键入的文本。然后将该状态赋予输入的值。还要确保在输入setStateonChange事件处理程序上使用,否则输入值不会改变。

To trigger an action only sometime after the user stops typing, you can use the useEffecthook together with setTimeout. In this case, we want to trigger useEffectwhen the input value changes, so we'll create a useEffecthook and on its dependency array give it the variable with the value of the input. The function given to useEffectshould use setTimeoutto trigger an action after the delay time that is desired. Also, the function given to useEffectshould return a cleanup function that clears the timeout set. This avoids doing actions for input values which are no longer relevant to the user.

要仅在用户停止输入后的某个时间触发操作,您可以将useEffect钩子与setTimeout. 在这种情况下,我们希望useEffect在输入值更改时触发,因此我们将创建一个useEffect钩子并在其依赖数组上为其提供具有输入值的变量。给定的函数useEffect应该用于setTimeout在所需的延迟时间后触发操作。此外,给定的函数useEffect应该返回一个清除超时设置的清理函数。这避免了对不再与用户相关的输入值执行操作。

Below is a little example of an app that uses the above steps to keep the string the user is typing visible and to show the finished string 500ms after the user stops typing.

下面是一个应用程序的小例子,它使用上述步骤来保持用户输入的字符串可见,并在用户停止输入 500 毫秒后显示完成的字符串。

function App() {
  const [query, setQuery] = useState("");
  const [displayMessage, setDisplayMessage] = useState("");

  useEffect(() => {
    const timeOutId = setTimeout(() => setDisplayMessage(query), 500);
    return () => clearTimeout(timeOutId);
  }, [query]);

  return (
    <>
      <input
        type="text"
        value={query}
        onChange={event => setQuery(event.target.value)}
      />
      <p>{displayMessage}</p>
    </>
  );
}

回答by AngelSalazar

You can debounce on the onChange event (if the user is typing the onchange event will not execute)

您可以在 onChange 事件上去抖动(如果用户正在输入 onchange 事件将不会执行)

Warning - Keep in mind that creating functions on render is a bad practice. I did it in order to illustrate the solution. A more safe solution is to use a class Component that creates the debounced handler on its constructor.

警告 - 请记住,在渲染时创建函数是一种不好的做法。我这样做是为了说明解决方案。更安全的解决方案是使用类 Component 在其构造函数上创建去抖动处理程序。

class DebouncedInput extends React.Component {
  constructor() {
    super();

    // Creating the debouncedOnChange to avoid performance issues

    this._debouncedOnChange = _.debounce(
      this.props.onChange, 
      this.props.delay
    );
  }

  render () {
    const { onChange, delay, ...rest } = this.props;
    return (
      <input onChange={this._debouncedOnChange} {..rest} />
    )
  }
}

Example below

下面的例子

function DebouncedInput (props) {
  const { onChange, delay = 300, ...rest } = props;
 
  
  return (
    <input 
      {...rest}
      onChange={ _.debounce(onChange, delay)}
    />
  )
}

function App() {
  return (
    <div>
      <DebouncedInput 
        type="text"
        placeholder="enter"
        delay={2000}
        onChange={() => console.log('changing')}
      />
    </div>
  )
}

ReactDOM.render(
  <App/>,
  document.querySelector('#app')
);
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.2/umd/react.production.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.2/umd/react-dom.production.min.js"></script>
</head>
<body>
 <div id="app"></div>
</body>
</html>