【问题标题】:How to set timeout on event onChange如何在事件 onChange 上设置超时
【发布时间】:2019-01-22 03:50:24
【问题描述】:

我有一个显示图像的画廊,我有一个搜索文本框 我正在尝试在输入事件上使用超时来防止对我输入的每个字母进行 api 调用: 我尝试使用 doSearch 函数 onChange 处理事件:但现在我无法在文本框上写任何内容,这会导致很多错误 附加到此会话的应用程序和图库组件

提前致谢

class App extends React.Component {
  static propTypes = {
  };

  constructor() {
    super();
    this.timeout =  0;
    this.state = {
      tag: 'art'
    };
  }


  doSearch(event){
    var searchText = event.target.value; // this is the search text
    if(this.timeout) clearTimeout(this.timeout);
    this.timeout = setTimeout(function(){this.setState({tag: event.target.value})} , 500);
  }

  render() {
    return (
      <div className="app-root">
        <div className="app-header">
          <h2>Gallery</h2>
          <input className="input" onChange={event => this.doSearch(event)} value={this.state.tag}/>
        </div>
        <Gallery tag={this.state.tag}/>
      </div>
    );
  }
}

export default App;

这是图库类:

import React from 'react';
import PropTypes from 'prop-types';
import axios from 'axios';
import Image from '../Image';
import './Gallery.scss';

class Gallery extends React.Component {
  static propTypes = {
    tag: PropTypes.string
  };

  constructor(props) {
    super(props);
    this.state = {
      images: [],
      galleryWidth: this.getGalleryWidth()

    };
  }

  getGalleryWidth(){
    try {
      return document.body.clientWidth;
    } catch (e) {
      return 1000;
    }
  }
  getImages(tag) {
    const getImagesUrl = `services/rest/?method=flickr.photos.search&api_key=522c1f9009ca3609bcbaf08545f067ad&tags=${tag}&tag_mode=any&per_page=100&format=json&safe_search=1&nojsoncallback=1`;
    const baseUrl = 'https://api.flickr.com/';
    axios({
      url: getImagesUrl,
      baseURL: baseUrl,
      method: 'GET'
    })
      .then(res => res.data)
      .then(res => {
        if (
          res &&
          res.photos &&
          res.photos.photo &&
          res.photos.photo.length > 0
        ) {
          this.setState({images: res.photos.photo});
        }
      });
  }

  componentDidMount() {
    this.getImages(this.props.tag);
    this.setState({
      galleryWidth: document.body.clientWidth
    });
  }

  componentWillReceiveProps(props) {
    this.getImages(props.tag);
  }

  render() {
    return (
      <div className="gallery-root">
        {this.state.images.map((dto , i) => {
          return <Image key={'image-' + dto.id+ i.toString()} dto={dto} galleryWidth={this.state.galleryWidth}/>;
        })}
      </div>
    );
  }
}

【问题讨论】:

  • 只需用箭头函数 (setTimeout(() =&gt; this.setState(...))) 替换您传递给 setTimeout 的函数以保留词法范围。

标签: javascript reactjs settimeout inputbox


【解决方案1】:

首先为什么需要使用 setTimeout 来设置用户输入的值。我看不出在 doSearch 函数中使用 setTimeout 有什么用处。

你的 doSearch 函数不能工作的原因是你没有绑定它。

您可以通过以下方式直接在doSearch函数中使用setState为标签设置值。

ES5方式

constructor(props){
    super(props);
    this.doSearch = this.doSearch.bind(this);
}

doSearch(event){
    this.setState({
       tag: event.target.value
    });
}

ES6 方式

doSearch = (event) => {
    this.setState({
       tag: event.target.value
    });
}

在 doSearch 函数的 setTimeout 内执行 setState 将不起作用,因为 输入标签已分配值。

ES5方式

constructor(props){
    super(props);
    this.doSearch = this.doSearch.bind(this);
}

doSearch(event){
     if(this.timeout) clearTimeout(this.timeout);
     this.timeout = setTimeout(function(){
       this.setState({
          tag: event.target.value
       }) 
     }.bind(this),500);
}

以 ES6 方式设置超时

doSearch = (event) => {
     if(this.timeout) clearTimeout(this.timeout);
     this.timeout = setTimeout(() => {
       this.setState({
          tag: event.target.value
       }) 
     },500);
}

图库组件:

检查当前 props 的更改与 componentWillRecieveProps 中的先前更改,以避免额外的渲染。

试试下面更新的代码

import React from 'react';
import PropTypes from 'prop-types';
import axios from 'axios';
import Image from '../Image';
import './Gallery.scss';

class Gallery extends React.Component {
  static propTypes = {
    tag: PropTypes.string
  };

  constructor(props) {
    super(props);
    this.state = {
      images: [],
      galleryWidth: this.getGalleryWidth()

    };
  }

  getGalleryWidth(){
    try {
      return document.body.clientWidth;
    } catch (e) {
      return 1000;
    }
  }
  getImages(tag) {
    const getImagesUrl = `services/rest/?method=flickr.photos.search&api_key=522c1f9009ca3609bcbaf08545f067ad&tags=${tag}&tag_mode=any&per_page=100&format=json&safe_search=1&nojsoncallback=1`;
    const baseUrl = 'https://api.flickr.com/';
    axios({
      url: getImagesUrl,
      baseURL: baseUrl,
      method: 'GET'
    })
      .then(res => res.data)
      .then(res => {
        if (
          res &&
          res.photos &&
          res.photos.photo &&
          res.photos.photo.length > 0
        ) {
          this.setState({images: res.photos.photo});
        }
      });
  }

  componentDidMount() {
    this.getImages(this.props.tag);
    this.setState({
      galleryWidth: document.body.clientWidth
    });
  }

  componentWillReceiveProps(nextProps) {
     if(nextProps.tag != this.props.tag){
        this.getImages(props.tag);
     }
  }

  shouldComponentUpdate(nextProps, nextState) {
      if(this.props.tag == nextProps.tag){
          return false;
      }else{
          return true;
      }
  }

  render() {
    return (
      <div className="gallery-root">
        {this.state.images.map((dto , i) => {
          return <Image key={'image-' + dto.id+ i.toString()} dto={dto} galleryWidth={this.state.galleryWidth}/>;
        })}
      </div>
    );
  }
}

我将标签初始值保留为空,因为您没有对价值艺术做任何事情。

请尝试以下代码

class App extends React.Component {
  static propTypes = {
  };

  constructor() {
    super();
    this.timeout =  0;
    this.state = {
      tag: '',
      callGallery: false
    };
  }


  doSearch = (event) => {
    this.setState({tag: event.target.value, callGallery: false});
  }

  handleSearch = () => {
     this.setState({
        callGallery: true
     });
  }

  render() {
    return (
      <div className="app-root">
        <div className="app-header">
          <h2>Gallery</h2>
          <input className="input" onChange={event => this.doSearch(event)} value={this.state.tag}/>
         <input type="button" value="Search" onClick={this.handleSearch} />
        </div>
        {this.state.callGallery && <Gallery tag={this.state.tag}/>}
      </div>
    );
  }
}

export default App;

【讨论】:

  • 您好,首先谢谢您,我不会使用 timout 来防止大量多余的 api 调用。我不知道为什么,但是您的解决方案不适用于这种情况,我仍然无法在输入框中写任何内容:(
  • 是的,您不能输入,因为您在 settimeout 中执行 setState,所以当您输入时它不起作用。所以设置没有超时的状态它会起作用。顺便说一句,多余的 api 调用是什么意思?
  • 我输入的每个字母都会刷新页面,这会使 oage 运行非常缓慢,我希望在 timout pass 之后我会进行搜索
  • 能不能也分享一下你的Gallery组件代码,不然帮到你有点难
  • 我已经在主留言中上传了图库组件,谢谢
【解决方案2】:

这是因为您没有将this 绑定到您的方法。

将以下内容添加到您的构造函数中:

this.doSearch = this.doSearch.bind(this);

另外,onChange 不需要粗箭头符号。做吧:

onChange={this.doSearch}

【讨论】:

    【解决方案3】:

    onChange handler 可以,但是需要绑定setTimeout 来渲染上下文。目前是指窗口上下文。代码如下

       doSearch(event){
            var searchText = event.target.value; // this is the search text
            if(this.timeout) clearTimeout(this.timeout);
            this.timeout = setTimeout(function(){
                             this.setState({
                                 tag: event.target.value
                             }) 
                           }.bind(this),500);
          }
    

    【讨论】:

      猜你喜欢
      • 2019-12-06
      • 2021-02-17
      • 1970-01-01
      • 2011-05-06
      • 2018-09-04
      • 1970-01-01
      • 2016-09-09
      • 2015-10-16
      • 2010-11-19
      相关资源
      最近更新 更多