键入时ReactJS延迟onChange

ztyzrc3y  于 2022-11-29  发布在  React
关注(0)|答案(9)|浏览(213)

我需要改变状态以保持用户正在输入的字符串。然而,我想延迟一个动作直到用户停止输入。但我不太清楚如何同时做到这两点。
所以当用户停止输入时,我希望触发一个动作,但不是在此之前。有什么建议吗?

n7taea2i

n7taea2i1#

带React挂钩和函数组件

要保留用户正在键入的字符串,请使用useState挂钩来存储用户正在键入的文本。然后将该状态赋予input的值。还要确保在input的onChange事件处理程序上使用setState,否则input值不会更改。
要想在用户停止输入后的某个时间触发一个动作,可以将useEffect挂钩与setTimeout一起使用,在这种情况下,我们希望在输入值发生变化时触发useEffect,因此我们将创建一个useEffect钩子,并在其依赖数组上为它提供带有input值的变量。指定给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>
    </>
  );
}
bbmckpt7

bbmckpt72#

用户输入文本后,您需要使用setTimeout来启动计时器。如果用户输入另一个字符,则重新启动计时器。如果用户在计时器完成之前没有再次输入,则它将触发一个切换复选框的操作:
第一个

nxowjjhe

nxowjjhe3#

一种方法是让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} />
    )
  }
}
k4aesqcs

k4aesqcs4#

带React挂钩和函数组件

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

vc9ivgsu5#

带React钩-使用参考

const timer = useRef(null)
    
useEffect(() => {
    
    clearTimeout(timer.current)
    timer.current = setTimeout(() => {
     // your logic
    },1000)
    
},[value])
smdncfj3

smdncfj36#

调用除第一次之外的每个状态更新:

实际上,我也有同样的问题,但一点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)} />
    );
};
iovurdzv

iovurdzv7#

您可以专门为此构建一个自定义钩子,并像useState钩子一样使用它。

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文章,其中解释了实现。

lxkprmvk

lxkprmvk8#

您可以对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} />
    )
  }
}

示例如下
第一次

kognpnkq

kognpnkq9#

你可以使用lodash延迟库的debounce和throttle来调用change handler函数,下面的代码是基于debounce的。同样的代码也可以用于throttle函数。Debounce:延迟调用函数,直到X毫秒后。节流:每X毫秒最多调用一次函数
样本代码:

import React,{useEffect, useState, useMemo} from "react"
import debounce from "lodash.debounce";

export default function App() {
  const [search, setSearch] = useState("");
  const handleChangeSearch = ({ target }) => {
    setSearch(target.value);    
  };
  const debouncedChangeHandler = useMemo(
    () => debounce(handleChangeSearch, 500),
    []
  );

  useEffect(() => {
    return () => {
      debouncedChangeHandler.cancel();
    }
  }, []);

  return (
    <div className="App">      
      <label > Search:
      <input sx={{ display: { xs: "none", md: "block" } }}
        onChange={debouncedChangeHandler}
        name="search"
        type="text"
        placeholder="search..."
      />
      </label >
    </div>
  );
}

相关问题