我需要在用户停止输入时执行搜索。我知道我应该使用 setTimeout()。但是使用 Reactjs我无法找到它是如何工作的。有人可以告诉我如何在用户停止键入几秒钟时调用一个方法(将处理搜索)。我想不了。在哪里编写代码以检查用户是否已停止输入。
import React, {Component, PropTypes} from 'react';
export default class SearchBox extends Component {
state={
name:" ",
}
changeName = (event) => {
this.setState({name: event.target.value});
}
sendToParent = () => {
this.props.searching(this.state.name);
}
render() {
return (
<div>
<input type="text" placeholder='Enter name you wish to Search.' onChange={this.changeName} />
</div>
);
}
}
我想在用户停止输入时调用sendToParent方法。
答案 0 :(得分:33)
您可以按照以下方式使用setTimeout
代码,
state = {
name: '',
typing: false,
typingTimeout: 0
}
changeName = (event) => {
const self = this;
if (self.state.typingTimeout) {
clearTimeout(self.state.typingTimeout);
}
self.setState({
name: event.target.value,
typing: false,
typingTimeout: setTimeout(function () {
self.sendToParent(self.state.name);
}, 5000)
});
}
此外,您需要在构造函数中绑定changeName
处理程序函数。
constructor(props) {
super(props);
this.changeName = this.changeName.bind(this);
}
答案 1 :(得分:12)
另一种与我合作的方式:
class Search extends Component {
constructor(props){
super(props);
this.timeout = 0;
}
doSearch(evt){
var searchText = evt.target.value; // this is the search text
if(this.timeout) clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
//search function
}, 300);
}
render() {
return (
<div className="form-group has-feedback">
<label className="control-label">Any text</label>
<input ref="searchInput" type="text" onChange={evt => this.doSearch(evt)} />
</div>
);
}
}
答案 2 :(得分:12)
使用useEffect挂钩执行
function Search() {
const [searchTerm, setSearchTerm] = useState('')
useEffect(() => {
const delayDebounceFn = setTimeout(() => {
console.log(searchTerm)
// Send Axios request here
}, 3000)
return () => clearTimeout(delayDebounceFn)
}, [searchTerm])
return (
<input
autoFocus
type='text'
autoComplete='off'
className='live-search-field'
placeholder='Search here...'
onChange={(e) => setSearchTerm(e.target.value)}
/>
)
}
答案 3 :(得分:3)
你可以使用lodash的debounce或使用setTimeout进行模拟。
import React, {Component, PropTypes} from 'react';
export default class SearchBox extends Component {
constructor(props){
super(props);
this.state={ name:" "}
this.timeout = null;
}
changeName = (event) => {
clearTimeout(timeout);
if(timeout){
setTimeout((event)=> this.setState({name: event.target.value}), 200)
}
}
sendToParent = () => {
this.props.searching(this.state.name);
}
render() {
return (
<div>
<input type="text" placeholder='Enter name you wish to Search.' onChange={this.changeName} />
</div>
);
}
}
答案 4 :(得分:2)
这个library(使用反跳)非常简单。
设置
yarn add use-debounce
或
npm i use-debounce --save
文档中的用法示例
import React, { useState } from 'react';
import { useDebounce } from 'use-debounce';
export default function Input() {
const [text, setText] = useState('Hello');
const [value] = useDebounce(text, 1000);
return (
<div>
<input
defaultValue={'Hello'}
onChange={(e) => {
setText(e.target.value);
}}
/>
<p>Actual value: {text}</p>
<p>Debounce value: {value}</p>
</div>
);
}
此刻我喜欢的东西可能在 未来!:
- 易于设置和使用
- 样板代码少
- 适度的评分(〜1K)和使用情况(npm-每周20万次下载)
- 支持超时,MaxWait和其他功能
答案 5 :(得分:1)
我认为我们可以用更简单,更简洁的方式来做到这一点,而不会破坏调用整个组件生命周期的state参数,
constructor(props) {
super(props);
//Timer
this.typingTimeout = null;
//Event
this.onFieldChange = this.onFieldChange.bind(this);
//State
this.state = { searchValue: '' };
}
/**
* Called on the change of the textbox.
* @param {[Object]} event [Event object.]
*/
onFieldChange(event) {
// Clears the previously set timer.
clearTimeout(this.typingTimeout);
// Reset the timer, to make the http call after 475MS (this.callSearch is a method which will call the search API. Don't forget to bind it in constructor.)
this.typingTimeout = setTimeout(this.callSearch, 475);
// Setting value of the search box to a state.
this.setState({ [event.target.name]: event.target.value });
}
<div className="block-header">
<input
type="text"
name="searchValue"
value={this.state.searchValue}
placeholder="User Name or Email"
onChange={this.onFieldChange}
/>
</div>
答案 6 :(得分:1)
我使用了lodash的去抖功能
onChangeSearchInput = (evt)=> {
this.debouncedSearch(evt.target.value);
};
debouncedSearch = debounce(function (query) {
this.setState({query});
}, 1000);
在我的渲染方法中的某个地方,我有这个输入字段
<input
type='text'
onChange={this.onChangeSearchInput}
className='uk-input'
placeholder={'search by name or email...'}
/>
答案 7 :(得分:1)
如何定制钩子?
import {useEffect, useRef, useState} from "react";
export default function useSearchInputState(searchHandler) {
// to prevent calling the handler on component mount
const didMountRef = useRef(false);
const [searchValue, setSearchValue] = useState(null);
useEffect(() => {
let delayDebounceFn;
if (didMountRef.current) {
delayDebounceFn = setTimeout(searchHandler, 600)
} else {
didMountRef.current = true;
}
return () => clearTimeout(delayDebounceFn);
}, [searchValue]); // eslint-disable-line react-hooks/exhaustive-deps
return [searchValue, setSearchValue];
}
用法:
function MyComponent(props) {
const [searchValue, setSearchValue] = useSearchInputState(() => {
resetData(searchValue ?? null, selectedFilterPos);
});
const onSearchChange = e => {
setSearchValue(e?.target?.value ?? null);
}
return (
<input className="Search"
onChange={onSearchChange}
/>
);
}
答案 8 :(得分:0)
Typeahead库问题https://twitter.github.io/typeahead.js/
由于这里的案例很简单,我可以使用快速而肮脏的解决方案:
onChange: (event) ->
if @_timeoutTask?
clearTimeout @_timeoutTask
@_timeoutTask = setTimeout (=>
@sendToParent event.target.value
clearTimeout @_timeoutTask
), 5000
这样,任务将在输入事件后5s触发。如果发生新事件,将取消旧任务并安排新任务,然后再等待5秒。
React的不同之处在于存储计算状态的位置,如_timeoutTask
。文件范围,组件状态或组件实例。
由于_timeoutTask
是组件级别,因此它应该是全局存储的。它不会影响渲染,因此也不会影响组件状态。所以我建议直接将它附加到组件实例。
答案 9 :(得分:0)
用户lodash javascript库并使用[_.debounce][1]
changeName: _.debounce(function (val) {
console.log(val)
}, 1000)
答案 10 :(得分:0)
我曾在一个项目中工作,我们在其中传递了大量数据以做出反应。键入每个字母后,数据原因滞后。我不能使用不受控制的输入,因为表单分散在5个不同的选项卡上,并且当您切换选项卡时,它失去了输入值。这是我所遇到的情况的排序版本。解决方案是更新状态不是在输入每个字母之后,而是在用户停止输入之后。为此,我们可以使用两种类型的输入,即受控输入和非受控输入,它们可以一起工作。
这可能会帮助下面的某个https://github.com/Pyot/react-update-state-on-stop-typing和代码示例:
import React, { Component } from 'react'
class ForHeavyData extends Component {
state = {
value: ''
}
timer = null
handleChange = (e) => {
clearTimeout(this.timer);
let value = e.target.value;
this.timer = setTimeout(() => { this.triggerChange(value) }, 2000);
}
triggerChange = (targetValue) => {
this.setState({ value: targetValue })
}
render() {
return (
<div className={'container'}>
<div className={'row'}>
<div className={'col-md-6'}>
<div className={"form-group"}>
<label forHtml="exampleInputEmail1"></label>
<input
className={'form-control'}
placeholder={'Please type text...'}
defaultValue={this.state.value}
onChange={this.handleChange}
onKeyDown={this.handleKeyDown} />
<small className={"form-text text-muted"}>You'll see what you type after 2sec when you stop typing below.</small>
</div>
</div>
</div>
<div className={'row'}>
<div className={'col-md-6'}>
<div className={'redborder'}>
{this.state.value !== '' ? this.state.value : 'You will see updated state here'}
</div>
</div>
</div>
</div>
)
}
}
export default ForHeavyData
答案 11 :(得分:0)
这是一个工作组件模板,带有一些有用的参数,可以帮助您入门。
import React, { Component } from 'react'
const initialState = { results: [], value: '' }
export default class SearchBox extends Component {
state = initialState
timeout = null
search_url = "https://example.com/search?q="
min_query_length = 2
timeout_duration = 300
handleSearchChange = (e) => {
let value = e.target.value
clearTimeout(this.timeout);
if (value.length < 1) {
return this.setState(initialState)
} else {
this.setState({ value })
if (value.length>=this.min_query_length) {
this.timeout = setTimeout(this.search, this.timeout_duration);
}
}
}
search = () => {
// assuming your results are returned as JSON
fetch(`${this.search_url}${this.state.value}`)
.then(res => res.json())
.then(data => {
this.setState({
results: data,
})
})
}
render() {
return (
<input
onChange={this.handleSearchChange}
/>
)
}
}
答案 12 :(得分:0)
使用反应钩子,从@anoNewb 的回答中修改。添加:
import React, { useState, useEffect } from "react";
export default function App() {
const [search, setSearch] = useState("");
const [searchTimeout, setSearchTimeout] = useState(null);
useEffect(() => {
if (searchTimeout) {
clearTimeout(searchTimeout);
}
setSearchTimeout(
setTimeout(() => {
loadUsers();
}, 1000),
);
return () => clearTimeout(searchTimeout);
}, [search]);
const loadUsers = () => {
console.log("axios call with query: ", search);
};
return (
<div className="App">
<form
onSubmit={(e) => {
e.preventDefault();
if (searchTimeout) {
clearTimeout(searchTimeout);
}
loadUsers();
}}
>
<input
onChange={(e) => {
setSearch(e.target.value);
}}
/>
</form>
</div>
);
}
答案 13 :(得分:0)
您可以使用 React 钩子 useEffect 和 setTimeOut 函数一起使用,因为它始终返回计时器 ID,您可以按如下方式轻松清除具有该 ID 的计时器
<div className="tableDataContainer">
<div className="stickyHeader">
<Table>
<TableHead></TableHead>
</Table>
</div>
<Table>
<TableHead></TableHead>
<TableBody></TableBody>
</Table>
</div>
答案 14 :(得分:0)
对于 React 钩子:
首先我们将定义一个组件
import React, { useEffect, useState } from "react";
const SearchInputText = ({ value, name, placeholder, onChange }) => {
// state for keepign search text
const [searchText, setSearchText] = useState(value);
// state for keeping the timeout
const [searchTextTimeout, setSearchTextTimeout] = useState(null);
// handler for form submit (pressing enter without waiting for setimeout to trigger)
const handleSubmit = (e) => {
e.preventDefault();
// clear timeout as it'll that would be triggered
if (searchTextTimeout) {
clearTimeout(searchTextTimeout);
}
onChange(searchText);
};
// onChange handler
const handleOnChange = (e) => {
// cancelling previous timeouts
if (searchTextTimeout) {
clearTimeout(searchTextTimeout);
}
// first update the input text as user type
setSearchText(e.target.value);
// initialize a setimeout by wrapping in our searchTextTimeout so that we can clear it out using clearTimeout
setSearchTextTimeout(
setTimeout(() => {
onChange(searchText);
// timeout is 2500ms, change it to less or more.
}, 2500),
);
};
// making sure that we clear the timeout if/when the component unmount
useEffect(() => {
return () => clearTimeout(searchTextTimeout);
}, [searchTextTimeout]);
return (
<form onSubmit={handleSubmit}>
<input
name={name}
placeholder={placeholder}
type="text"
value={searchText}
onChange={handleOnChange}
/>
</form>
);
};
export default SearchInputText;
用法:
const Parent = () => {
const handleChange = (e) => {
// your implementation here
};
return (
<div>
<SortSearchInput name="search" placeholder="Enter Search" onChange={handleChange} />
</div>
);
};