我需要更改状态以维护用户键入的字符串。但是我想延迟一个操作,直到用户停止键入为止。但是我不能完全专注于如何做到这两者。
因此,当用户停止输入时,我希望触发一个动作,而不是之前。有什么建议吗?
答案 0 :(得分:16)
要保留用户输入的字符串,请使用useState
钩子来存储用户输入的文本。然后将该状态赋予输入的值。另外,请确保在输入的setState
事件处理程序上使用onChange
,否则输入值不会更改。
要仅在用户停止键入后的某个时间触发操作,可以将useEffect
钩子与setTimeout
一起使用。在这种情况下,我们想在输入值更改时触发useEffect
,因此我们将创建一个useEffect
钩子,并在其依赖项数组上为其提供具有输入值的变量。给useEffect
的功能应使用setTimeout
在所需的延迟时间后触发动作。同样,赋予useEffect
的函数应返回清除超时设置的清除函数。这样可以避免对不再与用户相关的输入值执行操作。
下面是一个应用程序的小示例,该应用程序使用上述步骤来使用户键入的字符串保持可见,并在用户停止键入500ms后显示完成的字符串。
function App() {
const [query, setQuery] = useState("");
const [displayMessage, setDisplayMessage] = useState("");
useEffect(() => {
const timeOutId = setTimeout(() => setDisplayMessage(query), 500);
return () => clearTimeout(timeOutId);
}, [query]);
return (
<>
<input
type="text"
value={query}
onChange={event => setQuery(event.target.value)}
/>
<p>{displayMessage}</p>
</>
);
}
答案 1 :(得分:6)
使用 React Hooks 和 Function 组件
const [timer, setTimer] = useState(null);
function changeDelay(change) {
if (timer) {
clearTimeout(timer);
setTimer(null);
}
setTimer(
setTimeout(() => {
console.log(change);
}, 3000)
);
}
输入法
<input type="text" onChange={(e) => { changeDelay(e.target.value); }} />
答案 2 :(得分:1)
一种方法是让您的onChange
处理程序执行两个函数:
示例代码:
import debounce from 'lodash.debounce';
class Foo extends React.Component {
constructor() {
super()
this.state = {
value: ''
}
// Delay action 2 seconds
this.onChangeDebounced = debounce(this.onChangeDebounced, 2000)
}
handleInputChange = (e: Event) => {
// Immediately update the state
this.setState({
value: e.target.value
})
// Execute the debounced onChange method
this.onChangeDebounced(e)
}
onChangeDebounced = (e: Event) => {
// Delayed logic goes here
}
render() {
return (
<input onChange={this.handleInputChange} value={this.state.value} />
)
}
}
答案 3 :(得分:1)
用户输入文字后,您将需要使用client.shard.broadcastEval('this.users.size').then(i => console.log(i))
来启动计时器。如果用户输入其他字符,请重新启动计时器。如果用户没有在计时器完成之前再次键入,它将触发切换复选框的操作:
setTimeout
class App extends React.Component {
constructor() {
super();
this.state = {
text: '',
checked: false
};
this.timer = null;
}
componentDidUpdate (prevProps, prevState) {
if(prevState.text !== this.state.text) {
this.handleCheck();
}
}
onChange = e => {
this.setState({
text: e.target.value
});
};
handleCheck = () => {
// Clears running timer and starts a new one each time the user types
clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.toggleCheck();
}, 1000);
}
toggleCheck = () => {
this.setState( prevState => ({ checked: !prevState.checked }));
}
render () {
return (
<div>
<input value={this.state.text} onChange={this.onChange} placeholder="Start typing..." /><br/>
<label>
<input type="checkbox" checked={this.state.checked} onChange={this.toggleCheck} />
Toggle checkbox after user stops typing for 1 second
</label>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));
答案 4 :(得分:0)
您可以在onChange事件上进行反跳(如果用户输入onchange事件将不会执行)
警告-请记住,在渲染上创建函数是一种不好的做法。 我这样做是为了说明解决方案。 一种更安全的解决方案是使用Component类,该类在其构造函数上创建去抖动处理程序。
class DebouncedInput extends React.Component {
constructor() {
super();
// Creating the debouncedOnChange to avoid performance issues
this._debouncedOnChange = _.debounce(
this.props.onChange,
this.props.delay
);
}
render () {
const { onChange, delay, ...rest } = this.props;
return (
<input onChange={this._debouncedOnChange} {..rest} />
)
}
}
以下示例
function DebouncedInput (props) {
const { onChange, delay = 300, ...rest } = props;
return (
<input
{...rest}
onChange={ _.debounce(onChange, delay)}
/>
)
}
function App() {
return (
<div>
<DebouncedInput
type="text"
placeholder="enter"
delay={2000}
onChange={() => console.log('changing')}
/>
</div>
)
}
ReactDOM.render(
<App/>,
document.querySelector('#app')
);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.2/umd/react-dom.production.min.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
答案 5 :(得分:0)
实际上,我遇到了同样的问题,但是有一点setTimeout
可以帮助我进行第一次安装支票ref
:
import React, {useState, useEffect, useRef} from "react";
const Search = () => {
const filterRef = useRef(); // use ref to call the API call all time except first time
const [serpQuery, setSerpQuery] = useState('');
useEffect(() => {
let delayTimeOutFunction;
if(!filterRef.current) {
filterRef.current = true;
} else { // componentDidMount equivalent
delayTimeOutFunction = setTimeout(() => {
console.log('call api: ', serpQuery)
}, 700); // denounce delay
}
return () => clearTimeout(delayTimeOutFunction);
}, [serpQuery]);
return (
<input value={serpQuery} onChange={e => setSerpQuery(e.target.value)} />
);
};
答案 6 :(得分:0)
您可以专门为此目的构建自定义钩子,并像 useState 钩子一样使用它。这更像是 jnforja 的 answer
的扩展import { useEffect, useState } from "react";
const useDebounce = (initialValue = "", delay) => {
const [actualValue, setActualValue] = useState(initialValue);
const [debounceValue, setDebounceValue] = useState(initialValue);
useEffect(() => {
const debounceId = setTimeout(() => setDebounceValue(actualValue), delay);
return () => clearTimeout(debounceId);
}, [actualValue, delay]);
return [debounceValue, setActualValue];
};
export default useDebounce;
使用它就像 useState 钩子和延迟值
const [value, setValue] = useDebounce('',1000)
如果需要,您还可以查看 this 文章,解释实现。
答案 7 :(得分:0)
使用 React Hooks - useRef
const timer = useRef(null)
useEffect(() => {
clearTimeout(timer.current)
timeout.current = setTimeout(() => {
// your logic
},1000)
},[value])