如何在事件 onChange 上设置超时
Posted
技术标签:
【中文标题】如何在事件 onChange 上设置超时【英文标题】:How to set timeout on event 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(() => this.setState(...))
) 替换您传递给 setTimeout
的函数以保留词法范围。
【参考方案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);
【讨论】:
以上是关于如何在事件 onChange 上设置超时的主要内容,如果未能解决你的问题,请参考以下文章
如何将 onchange 事件附加到 CheckBoxList?缺少输入属性?