文章目录
- 普通使用
- 使用防抖节省开销
- 页面功能复杂需要value受控
- 回调需要部分代码立即执行,部分代码防抖延时执行
- useRef
- useCallback
- 小结
普通使用
当我们使用Antd的input或者select进行搜索时,onChange回调会即时执行。
import { Input } from "antd";
export default function HomePage() {
return (
<div>
<Input
onChange={(v) => {
console.log("value", v.target.value);
}}
/>
</div>
);
}
当输入123时,控制台打印了三次
使用防抖节省开销
当我们需要与后台配合使用时,如后台搜索。为了减少接口的调用次数,我们常常使用防抖函数来进行优化。
import { Input } from "antd";
import { debounce } from "lodash-es";
export default function HomePage() {
return (
<div>
<Input
onChange={debounce((v) => {
console.log("value", v.target.value);
}, 500)}
/>
</div>
);
}
当每次的输入间隔小于500ms时,输入123,控制台只打印了一次
页面功能复杂需要value受控
当我们的页面比较复杂时,除自己外,其他的组件或页面也可以操控input的内容显示。这时我们就需要给input一个value来手动控制input的内容。
import { ChangeEvent, useState } from "react";
import { Input } from "antd";
export default function HomePage() {
const [value, setValue] = useState("123");
const handleOnchange = (v: ChangeEvent<HTMLInputElement>) => {
console.log("value", v.target.value);
setValue(v.target.value);
};
return (
<div>
<Input value={value} onChange={handleOnchange} />
</div>
);
}
初始值123,输入666,和第一次一样打印了三次
增加防抖函数
import { ChangeEvent, useState } from "react";
import { Input } from "antd";
import { debounce } from "lodash-es";
export default function HomePage() {
const [value, setValue] = useState("123");
const handleOnchange = debounce((v: ChangeEvent<HTMLInputElement>) => {
console.log("value", v.target.value);
setValue(v.target.value);
}, 500);
return (
<div>
<Input value={value} onChange={handleOnchange} />
</div>
);
}
这里虽然打印了一次,但是value值始终没有改变。
我防抖了value的改变,因此value值没有即时改变,那么onChange的value也不是即时的,所以我的value始终无法改变。
回调需要部分代码立即执行,部分代码防抖延时执行
为了解决上一个问题,我们需要立即执行value的改变,但是接口请求还是需要防抖延时执行。
import { ChangeEvent, useState } from "react";
import { Input } from "antd";
import { debounce } from "lodash-es";
export default function HomePage() {
const [value, setValue] = useState("");
const handleDebounceSearch = debounce((v: string) => {
console.log("vv", v);
}, 500);
const handleOnchange = (v: ChangeEvent<HTMLInputElement>) => {
setValue(v.target.value); // 立即执行
handleDebounceSearch(v.target.value); // 防抖延时
};
return (
<div>
<Input value={value} onChange={handleOnchange} />
</div>
);
}
value可以正常显示了,打印的内容也有明显的延迟,但是还是打印了多次,这是为什么?
状态的改变会刷新组件,这个函数式组件重新渲染,handleDebounceSearch方法重新定义,因此每次onChange执行的handleDebounceSearch方法都不是同一个(引用地址不同)。
将handleDebounceSearch函数的引用地址固定住就可以。
可以使用useRef
或者useCallback
useRef
import { ChangeEvent, useEffect, useRef, useState } from "react";
import { Input } from "antd";
import { debounce } from "lodash-es";
export default function HomePage() {
const [value, setValue] = useState("");
const handleDebounceSearch = useRef(
debounce(async (value: string) => {
console.log("vv", value);
}, 500)
).current;
useEffect(() => {
return () => {
handleDebounceSearch.cancel();
};
}, []);
const handleOnchange = (v: ChangeEvent<HTMLInputElement>) => {
setValue(v.target.value); // 立即执行
handleDebounceSearch(v.target.value); // 防抖延时
};
return (
<div>
<Input value={value} onChange={handleOnchange} />
</div>
);
}
useCallback
import { ChangeEvent, useCallback, useEffect, useState } from "react";
import { Input } from "antd";
import { debounce } from "lodash-es";
export default function HomePage() {
const [value, setValue] = useState("");
const handleDebounceSearch = useCallback(
debounce((v: string) => {
console.log("vv", v);
}, 500),
[]
);
useEffect(() => {
return () => {
handleDebounceSearch.cancel();
};
}, []);
const handleOnchange = (v: ChangeEvent<HTMLInputElement>) => {
setValue(v.target.value); // 立即执行
handleDebounceSearch(v.target.value); // 防抖延时
};
return (
<div>
<Input value={value} onChange={handleOnchange} />
</div>
);
}
注意组件卸载时清除定时器
handleDebounceSearch.cancel()
小结
- 回调函数频繁调用,并且有较大的请求开销
- 可以使用防抖的方法解决次数频繁调用
- 回调的即时处理与防抖处理可分开处理
- 要注意防抖函数的定义,引用地址是否相同。