如何开始搜索只有当用户停止键入?

我需要执行一个搜索当用户停止输入。我知道我应该使用 SetTimeout ()。但是有了 我不知道它是如何工作的。,有人能告诉我如何调用一个方法(将处理搜索)当用户停止输入几秒钟(假设5)。我不知道在哪里编写代码来检查用户是否已停止输入。

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 方法。

142024 次浏览

Typeahead 图书馆问题

由于这里的情况很简单,我可以使用一个快速而肮脏的解决方案:

onChange: (event) ->
if @_timeoutTask?
clearTimeout @_timeoutTask


@_timeoutTask = setTimeout (=>
@sendToParent event.target.value
clearTimeout @_timeoutTask
), 5000

这样,任务将在输入事件之后触发5秒。如果发生新事件,旧任务将被取消,新任务将被安排,那么需要等待的时间将增加5秒。

React 中的不同之处在于存储计算状态(如 _timeoutTask)的位置。文件范围、组件状态或组件实例。

Since _timeoutTask is component level, it should be be store globally. And it does not affect rendering, so not in component state too. So I suggest attaching it to component instance directly.

可以对代码使用 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);
}

您可以只使用 loash 的 deounce 或使用 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>
);
}
}

另一个对我有效的方法是:

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>
);
}
}

我认为我们可以用一种更简单、更干净的方式来完成它,而不必像下面这样突然调用完整组件生命周期的状态参数:

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>

用户 浪荡 javascript 库并使用 [_.debounce][1]

changeName: _.debounce(function (val) {
console.log(val)
}, 1000)

我使用了 lodash 的 deounce 函数

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...'}
/>

使用 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)}
/>
)
}

下面是一个工作组件模板,其中包含一些有用的参数,可以帮助您开始使用。

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}
/>
)
}
}


这个 图书馆(使用-反弹)是好的和简单的。

设置

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-200K 下载/每周)
  • 支持超时、 MaxWait 和其他特性

定制的钩子怎么样?

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); // replace with your code
});


return (
<input className="Search"
onChange={e => setSearchValue(e?.target?.value ?? null)}
/>
);
}

使用反应钩,修改自@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>
);
}

您可以使用 setTimeOut 函数使用反应钩子 使用效果,因为它总是返回计时器 id,并且您可以使用该 id 轻松地清除计时器,如下所示

export const Search = () => {
const [term, setTerm] = useState();
const [results, setResult] = useState([]);


useEffect(() => {
const searchWiki = async () => {
const { data } = await axios.get('https://en.wikipedia.org/w/api.php', {
params: {
srsearch: term,
},
});


setResult(data.query.search);
};
const timerId = setTimeout(() => {
searchWiki();
// make a request after 1 second since there's no typing
}, 1000);


return () => {
clearTimeout(timerId);
};
}, [term]);

对于反应挂钩:

首先,我们将定义一个组件

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>
);
};

我已经使用这个自定义挂钩,它的工作完全没有问题仍然。

export function useSearchDebounce(delay = 350) {
const [search, setSearch] = useState(null);
const [searchQuery, setSearchQuery] = useState(null);


useEffect(() => {
const delayFn = setTimeout(() => setSearch(searchQuery), delay);
return () => clearTimeout(delayFn);
}, [searchQuery, delay]);


return [search, setSearchQuery];
}

在任何地方使用

const [search, setSearch] = useSearchDebounce();


<input onChange={(e) => setSearch(e.target.value)}/>

我自己制作了这样的定制组件。

import React, { useState, useEffect } from 'react'


const InputDebounce = props => {
const { onChange, ...otherProps } = props


const [inputTimeout, setInputTimeout] = useState(null)


useEffect(() => () => clearTimeout(inputTimeout), [inputTimeout])


const inputOnChange = value => {
if (inputTimeout) clearTimeout(inputTimeout)
setInputTimeout(
setTimeout(() => {
if (onChange) onChange(value)
}, 1000)
)
}


return (
<input
{...otherProps}
onChange={e => inputOnChange(e.target.value)}
/>
)
}


export default InputDebounce

在这样的地方使用。

import React from 'react'
import ReactDOM from 'react-dom'


import InputDebounce from './InputDebounce'


const App = () => {
const usernameOnChange = value => {
console.log(value)
}


return (
<div>
<InputDebounce
type='text'
name='username'
placeholder='Username'
onChange={usernameOnChange}
/>
</div>
)
}


ReactDOM.render(<App />, document.getElementById('root'))

下面的代码对我很有用。

const[isReady, setReady]  = useState(true);
const onSearchSet =(event:React.ChangeEvent<HTMLInputElement>) => {


setCriteria(event.target.value);
if(isReady) {
setReady(false);
const delayDebounceFn = setTimeout(() => {
// Send Axios request here
            

props.returnCall(props.RDropID, sortCriteria, event.target.value);


setReady(true);
}, 1000)
        

}
      

};

下面的代码对我很有用:

const [filter, setFilter] = useState()


useEffect(() => {
const search = setTimeout(() => {
getList()
//Your search query and it will run the function after 3secs from user stops typing
}, 3000);
return () => clearTimeout(search)
}, [filter])

并添加如下 HTML:

<input type="text" onInput={(e) => setFilter(e.target.value)} value={filter} />

我可以和佐贺一起用这个代码吗?它将帮助发送最新的请求。可以更改设置的超时时间。我用的是600毫秒。

  const dispatch = useDispatch();
const [searchText, setSearchText] = useState('');


useEffect(() => {
const sendSearchRequest = setTimeout(() => {
if (searchText && searchText.length > 2) {
dispatch(sendRequestToSaga(searchText));
}
}, 600);
return () => clearTimeout(sendSearchRequest);
}, [searchText]);

下面是一种使用函数组件和 useRef 钩子的方法。

import React, { useRef, useEffect } from "react";


function Search() {
const [searchTerm, setSearchTerm] = React.useState("");


const inputRef = useRef<any>()
  

useEffect(() => {
let timer: NodeJS.Timeout | null = null


const sendData = () => {
// If the user keeps on typing then the timeout is cleared and restarted
if(timer) clearTimeout(timer)


timer = setTimeout(() => {
setSearchTerm(inputRef.current.value)
}, 3000)
}


const element = inputRef.current;
// Set listener and start timeout
element.addEventListener('keyup', sendData);


return () => {
// Remove listener wwhen unmounting
element.removeEventListener('keyup', sendData);
};
}, []);


return (
<div>
<input
ref={inputRef}
autoFocus
type="text"
autoComplete="off"
className="live-search-field"
placeholder="Search here..."
        

/>
<p>searchTerm: {searchTerm}</p>
</div>
);
}


export default Search;

这种方法避免了不必要的重新呈现,并利用事件侦听器在用户停止输入时处理搜索提交。