React Hooks 防抖节流正确使用方式~

3,422 阅读3分钟

React 在 16.8 的版本中引入了全新的 API:React Hooks,颠覆了之前 class 的用法。因此,在使用 React Hooks 时我们就需要具备不同的思维方式,特别是对初学者来说,尤为重要。

防抖和节流

关于防抖和节流的介绍和使用,网上有很多相关的文章,本文不再详细介绍,感兴趣的小伙伴可以参考一下 lodashdebounce(防抖)throttle(节流) 。

在这里我们做一个简单的回顾:

  • 防抖 debounce(callback, n):n 秒后执行回调事件,如果在 n 秒内动作被重复触发,将重新计时
  • 节流 throttle(callback, n):n 秒内只执行一次回调事件,即在 n 秒内的多次动作触发中,仅有一次生效

问题产生

目前有这么一个需求:有个搜索框,我们需要对用户键入的内容实时查询。简单说,就是搜索框里面的内容发生变化就会执行一次内容搜索。

不过这样会带来性能消耗:如果用户快速输入 n 个字,就会导致 n 次查询。这时候,我们可以通过防抖来解决这个问题。即用户输入内容结束的 n 秒内,如果停止输入,就执行搜索

我们使用 React Hooks 来实现这一需求:

export default function App() {
    const [value, setValue] = useState('')
    // 使用防抖
    const doSomething = debounce((v) => {
        console.log('do something after 1s: ', v)
    }, 1000)
​
    const onChange = (e) => {
        const inputValue = e.target.value;
        setValue(inputValue);
        doSomething(inputValue)
    }
    return (
        <div className="App">
            <h2>React Hooks 实现防抖节流</h2>
            <div><input value={value} onChange={onChange} /></div>
        </div>
    );
}

我们的本意是,在用户停止输入 1s 后,执行回调函数 doSomething,但输入结果却大相径庭,从结果得知,每当我们输入一个字,防抖函数 doSomething 就会执行一次,显然这并不是我们想要的效果。

这是因为,在 React Hooks 中,doSomething 函数每次被调用时,都会被重新创建,所以每一次调用的 doSomething 都是一个新函数,也就是说每次调用的防抖都会被重新执行。

解决方法

useCallback

问题我们已经找到了,是因为 doSomething 函数在每次被调用时会重新创建,所以我们必须把函数缓存起来,让 Hooks 记住他。而 useCallback 函数就是做这样的事,它可以将包裹函数缓存起来,这样当函数被调用时,Hooks 就不会重新创建它了

加入 useCallback 后,我们想要的结果就奏效了~

const doSomething = useCallback(debounce((v) => {
    console.log('do something after 1s: ', v)
}, 1000), [])

useRef

除了 useCallback 之外,我们还可以利用 useRef 来实现函数的存储,它和 React 类组件中的实例属性相似。

useRef 是一个可修改的对象,我们可以在 useRefcurrent 属性传入最初的值,并且该值会在组件的整个生命周期中保持不变,除非你手动去修改它

所以,使用 useRef 也可以达到我们要的效果:

const doSomething = useRef(
    debounce((v) => {
        console.log("do something after 1s: ", v);
    }, 1000)
);

const onChange = (e) => {
    const inputValue = e.target.value;
    setValue(inputValue);
    doSomething.current(inputValue);
};

最后

当然,并不是说在 React Hooks 使用防抖和节流都必须这么做,这主要看具体的场景,具体的需求,具体的问题具体分析~