在 class 组件中使用防抖/节流,通常使用 debounce/ throttle 包裹需要防抖/节流的函数,即可创建一个防抖或节流的函数:
import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import { Input } from 'antd';
import throttle from 'lodash/debounce';
class Search extends React.Component {
constructor(props) {
super(props)
this.handleSearch = throttle(this.handleOnChange, 200);
}
handleOnChange = (e) => {
console.log(e.target.value)
}
render() {
return (
<Input onChange={this.handleSearch} />
)
}
}
ReactDOM.render(
<Search />,
document.getElementById('container'),
);
当我们在函数式组件中使用防抖/节流函数时,也会自然而然地使用 debounce/ throttle 包裹需要防抖/节流的函数:
import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import { Input } from 'antd';
// import debounce from 'lodash/debounce';
import throttle from 'lodash/throttle';
const Search = () => {
const handleOnChange = (e) => {
console.log(e.target.value)
}
const handleSearch = throttle((e) => handleOnChange(e), 500)
return (<Input onChange={handleSearch} placeholder="Basic usage" />)
}
ReactDOM.render(<Search />, document.getElementById('container'));
却发现做了防抖节流的函数并没有发挥作用,而是仅仅把时间延后了500毫秒而已。这是因为函数式组件每次渲染结束后,内部的变量都会被释放,重新渲染时所有的变量都会被重新初始化,产生的结果就是每一次都注册和执行了 setTimeout 函数。想要得到正确的运行结果,必须以某种方式存储那些会被删除的变量和方法的引用,遗憾的是没办法直接使用 useState 这个 hook 去存储。那么我们通过什么方式存储呢?欣慰的是,useCallback 和 useRef 这两个 hook 可以解决我们的问题。
useCallback
当把一个回调函数以依赖项数组作为参数传入 useCallback,它将返回一个缓存后的函数。
import React, { useCallback } from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import { Input } from 'antd';
import debounce from 'lodash/debounce';
import throttle from 'lodash/throttle';
const Search = () => {
const handleOnChange = (e) => {
console.log(e.target.value)
}
const handleSearch = useCallback(throttle((e) => handleOnChange(e), 500), [])
return (<Input onChange={handleSearch} placeholder="Basic usage" />)
}
ReactDOM.render(<Search />, document.getElementById('container'));
useRef
useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象梓组件的整个生命周期内保持不变。
import React, { useRef } from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import { Input } from 'antd';
import debounce from 'lodash/debounce';
import throttle from 'lodash/throttle';
const Search = () => {
const handleOnChange = (e) => {
console.log(e.target.value)
}
const handleSearch = useRef(throttle((e) => handleOnChange(e), 500)).current
return (<Input onChange={handleSearch} placeholder="Basic usage" />)
}
ReactDOM.render(<Search />, document.getElementById('container'));