为什么函数组件不能像类组件一样直接对方法进行节流处理
- 无效代码
import React, {useState} from "react";
import debounce from 'lodash/debounce';
const sendQuery = (query) => console.log(`Querying for ${query}`);
const Search = () => {
const [userQuery, setUserQuery] = useState("");
const delayedQuery = debounce(q => sendQuery(q), 500);
const onChange = e => {
setUserQuery(e.target.value);
delayedQuery(e.target.value);
};
return (
<div>
<label>Search:</label>
<input onChange={onChange} value={userQuery} />
</div>
);
因为函数组件每次重绘都会导致在函数内部定义的变量都会被重新初始化。这就意味着,每次我们调用debounce函数时都会重新注册一个setTimeout回调。这样子做防抖函数并没有发挥作用,仅仅是把反应时间延后了500毫秒。
解决方案
自定义hooks(useDebounce)
- 使用
const callback = useDebounce(fn, [(wait = 0)]);
- 自定义hooks
import { useRef, useCallback, useEffect } from 'react';
export default function useDebounce(fn, wait = 0) {
useEffect(
() => {
return cancel;
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[]
);
const timerRef = useRef(0);
const cancel = useCallback(() => {
if (timerRef.current) {
clearTimeout(timerRef.current);
timerRef.current = 0;
}
}, []);
const callback = useCallback(
(...args) => {
cancel();
timerRef.current = setTimeout(fn, wait, ...args);
},
[cancel, fn, wait]
);
return callback;
}
使用useCallback
const delayedQuery = useCallback(debounce(q => sendQuery(q), 500), []);
使用useRef
const SearchFixed = () => {
const [userQuery, setUserQuery] = useState("");
const delayedQuery = useRef(debounce(q => sendQuery(q), 500)).current;
const onChange = e => {
setUserQuery(e.target.value);
delayedQuery(e.target.value);
};
return (
<div>
<label>Search Fixed:</label>
<input onChange={onChange} value={userQuery} />
</div>
);
};