如何在事件 onChange 上设置超时

IT技术 javascript reactjs settimeout inputbox
2021-04-28 20:34:23

我有一个显示图像的画廊,我有一个搜索文本框我试图在输入事件上使用超时以防止对我输入的每个字母进行 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>
    );
  }
}
3个回答

首先,为什么需要使用 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>
    );
  }
}

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

请尝试使用以下代码

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;

这是因为您尚未绑定this到您的方法。

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

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

此外,您不需要onChange. 做就是了:

onChange={this.doSearch}

onChange处理程序就好了,但你需要绑定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);
      }