【问题标题】:Using Lodash debounce in React to prevent requesting data as long as the user is typing在 React 中使用 Lodash debounce 来防止在用户输入时请求数据
【发布时间】:2018-06-11 06:41:59
【问题描述】:

只要用户正在输入,我就不想触发请求。我的代码应该限制请求,以便当用户快速键入时,它会使用最新的输入值而不是多个触发一个请求。

现在,当我输入“test”时,它会触发 4 个不同的请求:

  1. “t”
  2. “特”
  3. “特斯”
  4. “测试”

所以我找到了 lodash _.debounce 和 _.throttle ( [https://lodash.com/docs/4.17.4#debounce] ),但我真的不明白如何在我的代码中实现它。谁能帮帮我?

我的代码:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import './style.css';

import { search } from '../../actions/';

class SearchBar extends Component {
  constructor(props) {
    super(props);
    this.state = { searchTerm: '' };
  }

  startSearch(query) {
    const storedTerms = this.props.searchedTerm;
    let foundDuplicate = false;

    if (storedTerms.length === 0 && query) {
      return this.props.search(query);
    }

    if (storedTerms.length !== 0 && query) {
      const testDuplicate = storedTerms.map(term => term === query);
      foundDuplicate = testDuplicate.some(element => element);
    }

    if (storedTerms.length !== 0 && !query) {
      return false;
    }

    if (foundDuplicate) {
      return false;
    }

  return this.props.search(query);
}

handleInputChange(term) {
  this.setState({ searchTerm: term });
  this.startSearch(term);
}

render() {
  return (
    <div className="Search-bar">
      <input
        value={this.state.searchTerm}
        onChange={event => this.handleInputChange(event.target.value)}
      />
    </div>
  );
}


function mapStateToProps(state) {
  return {
    searchedTerm: state.searchedTerm,
    savedData: state.savedData,
  };
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators({ search }, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(SearchBar);

编辑:

感谢 Sagiv b.g,我正在添加一些解释:

好的,所以用户应该输入超过 2 个字母 && 我的应用程序应该在启动 ajax 请求之前至少等待 2 秒


EDIT2: 感谢 Sagiv b.g,提供出色的解决方案!

我已经像这样更改了我的代码:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import _ from 'lodash';
import './style.css';

import { search } from '../../actions/';

class SearchBar extends Component {
  constructor(props) {
    super(props);
    this.state = { inputValue: '' };

    this.startSearch = _.debounce(this.startSearch, 2000);
  }

  startSearch(query) {
    const storedTerms = this.props.searchedTerm;
    let foundDuplicate = false;

    if (storedTerms.length === 0 && query) {
      return this.props.search(query);
    }

    if (storedTerms.length !== 0 && query) {
      const testDuplicate = storedTerms.map(term => term === query);
      foundDuplicate = testDuplicate.some(element => element);
    }

    if (storedTerms.length !== 0 && !query) {
      return false;
    }

    if (foundDuplicate) {
      return false;
    }

    return this.props.search(query);
  }

  onChange = ({ target: { value } }) => {
    this.setState({ inputValue: value });
    if (value.length > 2) {
      this.startSearch(value);
    }
  };

  render() {
    return (
      <div className="Search-bar">
        <input
          placeholder="Type something to search GitHub"
          value={this.state.inputValue}
          onChange={this.onChange}
        />
      </div>
    );
  }
}

function mapStateToProps(state) {
  return {
    searchedTerm: state.searchedTerm,
    savedData: state.savedData,
  };
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators({ search }, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(SearchBar);

要处理的最后一个错误

但它还有最后一个错误,我不知道如何摆脱。当用户想要更改搜索查询并使用退格键擦除搜索字段时,我的应用程序总是会意外触发另一个 API 请求。 这是一个例子:

https://youtu.be/uPEt0hHDOAI

有什么办法可以摆脱这种行为吗?

【问题讨论】:

  • 当您说“只要用户正在输入...”,您能否解释一下您希望如何确定用户何时将要输入另一个字母?一些用户每 0.5 秒输入 1 个字母,而其他用户可能输入速度较慢。您无法确定用户何时完成输入。您可以将 ajax 请求限制在某个时间单位(1.5 秒?)和/或字符串的最小长度,并希望最好。
  • 好的,所以用户应该输入超过 2 个字母 && 我的应用程序应该在启动 ajax 请求之前等待 2 秒
  • @MountainConqueror 你还记得你是如何解决这种意外行为的吗?如果是这样,请告诉我我现在是怎么卡住的

标签: javascript reactjs react-native lodash


【解决方案1】:

这很容易使用 lodash _.debounce
你用它包装你的方法并传递你想要等待的毫秒。
至于输入的最小长度,只要长度大于2才调用新方法。

这是一个运行中的小例子:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      message: '',
      inputValue: ''
    };

    this.updateMessage = _.debounce(this.updateMessage, 2000);
  }


  onChange = ({ target: { value } }) => {
    this.setState({ inputValue: value });
    if (value.length > 2) {
      this.updateMessage(value);
    }
  }


  updateMessage = message => this.setState({ message });

  render() {
    const { message, inputValue } = this.state;
    return (
      <div>
        <input placeholder="type something..." value={inputValue} onChange={this.onChange} />
        <hr/>
        <div>server call >> wait 2 seconds & min length of 2</div>
        <p>{message}</p>
      </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>
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.compat.js"></script>
<div id="root"></div>

【讨论】:

  • 好的,但我还有最后一个错误要处理。我应该接受您的回答并创建新的 StackOverflow 问题吗?这是我的问题 -> youtu.be/uPEt0hHDOAI
  • 似乎它与这个问题没有直接关系(似乎是一个 redux 问题)。所以我认为一个新问题是相关代码示例更好
猜你喜欢
  • 2020-09-05
  • 2018-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-10
  • 1970-01-01
  • 2021-06-15
  • 1970-01-01
相关资源
最近更新 更多