前端场景下的搜索框,你真的理解了吗?

2,575 阅读2分钟

进入正题: image.png

现有如下场景:

一个 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.但请求返回的顺序确不是按这个顺序来的,大致如图:

image.png

虽然请求2和请求3后面才发出,但是响应的要比请求1要快,当请求1响应完成时,会重置之前的请求数据,因此页面上会显示请求1的响应结果,与用户期望不符。

那这该怎么解决呢?(该正经起来了!)

解决起来其实方式有很多,笔者这里主要讲一下最佳实践。

通过fetch自带的abort API就可以解决该问题,核心思想是当后面有同样的请求发出时,将前面的请求终止掉,解决响应数据覆盖的问题,

image.png

注意:这里的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} />;
};

最终效果:

image.png

适用场景:搜索框,Tab快速切换等。

最后,以上故事纯属虚构😂,大家有什么更好的想法欢迎留言💬。