进入正题:
现有如下场景:
一个 input 搜索框,一个提交按钮,点击按钮向后端发起查询请求,这个场景我相信大家都不陌生。
直到有一天,大伙有吃有笑的喝着下午茶🍵,产品经理把我叫,说道:这个查询能用确实能用,但每次都要我点查询按钮才真正的搜索,能不能用户边输入边查询呢?🤔
实现起来当然很简单,但是为了让产品不再提过分的要求,,我放下手中的下午茶,假装沉思了一会🤔,笑着说没问题👌。
接下来就是我们前端熟悉的操作了,只需要在onChange及时触发请求事件即可。
const Demo = () => {
const handleChange = () => {
return fetch('https://pagead2.googlesyndication.com/getconfig/sodar?sv=200&tid=gda&tv=r20211207&st=env'); //模拟请求
};
return <Input onChange={handleChange} />;
};
写完提交代码,继续吃着下午茶🍵,继续摸鱼🐟。
过了两天,后端顶着个丧脸过来找我说:你们前端怎么搞的,查询接口一直发,服务器快顶不住了呀😭。
我脑袋一拍,想了想,哦!原来 oncChange 没做防抖,那就加上去呗,这不是小 case 嘛😎。
一行代码搞定😎
const Demo = () => {
const handleChange = () => {
return fetch('https://pagead2.googlesyndication.com/getconfig/sodar?sv=200&tid=gda&tv=r20211207&st=env'); //模拟请求
};
return <Input onChange={debounce(handleChange, 1000)} />;
};
差不多又过了两天,到了要交互的日子了,正在摸着🐟,测试火急火燎的跑过来说,你们前端搜索结果跟输入的对不上啊😭,赶紧给解决一下,解决不了今天不准下班!
我心想,这一个搜索框还能上天不成,不慌不忙的询问怎么复现。
原来是这样,用户依次输入了1,2,3.但请求返回的顺序确不是按这个顺序来的,大致如图:
虽然请求2和请求3后面才发出,但是响应的要比请求1要快,当请求1响应完成时,会重置之前的请求数据,因此页面上会显示请求1的响应结果,与用户期望不符。
那这该怎么解决呢?(该正经起来了!)
解决起来其实方式有很多,笔者这里主要讲一下最佳实践。
通过fetch自带的abort API就可以解决该问题,核心思想是当后面有同样的请求发出时,将前面的请求终止掉,解决响应数据覆盖的问题,
注意:这里的abort并不是真正意义上的中断请求,请求还是会正常发出,只是前端不会处理其响应而已。
大致代码如下:
const Demo = () => {
const [inputVal, setInputVal] = useState('');
const onInputChange = useCallback((e) => setInputVal(e.target.value));
useEffect(() => {
const abortController = new window.AbortController();
const signal = abortController.signal;
fetch('https://pagead2.googlesyndication.com/getconfig/sodar?sv=200&tid=gda&tv=r20211207&st=env', { signal });
return () => {
if (signal && abortController.abort) {
abortController.abort();
}
};
}, [inputVal]);
return <input type="text" value={inputVal} onChange={onInputChange} />;
};
最终效果:
适用场景:搜索框,Tab快速切换等。
最后,以上故事纯属虚构😂,大家有什么更好的想法欢迎留言💬。