React自定义hook优雅实现debounce

1,130 阅读1分钟

1、未使用debounce

import React, { useEffect, useRef, useState } from 'react';
import { Input, message } from 'antd';
import styled from '@emotion/styled'

const UseDebounce = () => {
  const [inputVal, setInputVal] = useState('')

  useEffect(() => {
    message.info(`参数为${inputVal},请求数据。。。`)
  }, [inputVal])

  return (
    <div>
      <InputWrap value={inputVal} onChange={e => setInputVal(e.target.value)} />
    </div>
  )
}

const InputWrap = styled(Input)`
  width: 200px;
  margin-top: 30px;
  margin-left: 30px;

当连续输入时,效果如下图所示: image.png

2、自定义hook

新建useDebounce.ts文件,内容如下:

import { useEffect, useState } from 'react'

export const useDebounce = <T>(value: T, delay: number) => {
  const [param, setParam] = useState(value)
  useEffect(() => {
    const timeout = setTimeout(() => setParam(value), delay)
    return () => clearTimeout(timeout)
  }, [value, delay])
  return param
}

父组件中引入

import React, { useEffect, useRef, useState } from 'react';
import { Input, message } from 'antd';
import styled from '@emotion/styled'
import { useDebounce } from 'src/hooks/useDebounce';

const UseDebounce = () => {
  const [inputVal, setInputVal] = useState('')
  const debounceParam = useDebounce(inputVal, 300)

  useEffect(() => {
    message.info(`参数为${inputVal},请求数据。。。`)
  }, [debounceParam])

  return (
    <div>
      <InputWrap value={inputVal} onChange={e => setInputVal(e.target.value)} />
    </div>
  )
}

const InputWrap = styled(Input)`
  width: 200px;
  margin-top: 30px;
  margin-left: 30px;
`

export default UseDebounce

连续输入后,效果如下: image.png

3、总结

实现debounce方案有很多,自定义hook的方式更加直观且简单。其原理主要运用了useEffect执行机制。每次value值变化,开始设置一个定时器,当依赖变化时,就清除上一个定时器,并新建一个定时器。