Necesito que cambie el estado para mantener la cadena que el usuario está escribiendo. Sin embargo, quiero retrasar una acción hasta que el usuario deje de escribir. Pero no puedo ubicar mi dedo en cómo hacer ambas cosas.
Entonces, cuando el usuario deja de escribir, quiero que se active una acción, pero no antes. ¿Alguna sugerencia?
Para mantener la cadena que el usuario está escribiendo, use el useState para almacenar el texto que el usuario está escribiendo. Luego dale ese estado al valor de la entrada. También asegúrese de usar setState en el controlador de eventos onChange de la entrada; de lo contrario, el valor de entrada no cambiará.
Para desencadenar una acción solo en algún momento después de que el usuario deja de escribir, puede usar el gancho useEffect junto con setTimeout . En este caso, queremos activar useEffect cuando cambie el valor de entrada, por lo que crearemos un useEffect y en su matriz de dependencias le daremos la variable con el valor de la entrada. La función dada a useEffect debe usar setTimeout para activar una acción después del tiempo de retraso que se desea. Además, la función dada a useEffect debería devolver una función de limpieza que borre el tiempo de espera establecido. Esto evita realizar acciones para valores de entrada que ya no son relevantes para el usuario.
A continuación se muestra un pequeño ejemplo de una aplicación que utiliza los pasos anteriores para mantener visible la cadena que el usuario está escribiendo y para mostrar la cadena terminada 500 ms después de que el usuario deja de escribir.
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> </> ); }Suena que necesitará usar setTimeout para iniciar un temporizador tan pronto como el usuario ingrese texto. Si el usuario ingresa otro carácter, reinicie el temporizador. Si el usuario no vuelve a escribir antes de que se complete el temporizador, se activará una acción que alternará la casilla de verificación:
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')); <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> <div id="root"></div>Una forma de hacer esto sería hacer que su controlador onChange ejecute dos funciones:
Código de ejemplo:
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} /> ) } }