React搜索框的防抖及异步操作访问事件target为null

2,735 阅读2分钟

React搜索框实现防抖、onChange及清空

我们经常会用到搜索框元素,需求一般是这样的:

获取实时输入并请求结果渲染到列表,以及允许用户清空input框

这样需求在react里实现,需要考虑以下几点:

  • 输入防抖
  • 异步操作中获取onChange的input的值
  • 将input的value设置为state的值,实现清空输入框

那么,我们首先把这个input元素写出来

// search.tsx
import React, { useState, useEffect, useContext } from 'react'
const Search: React.FC = (props: any) => {
    const [listInput, setListInput] = useState({
        text: '',
        holder: '您要去哪儿',
        focus: false,
        suggestionIndex: 0,
        suggestion: [
          {text: '',list: []},
          {text: '',list: []}
        ],
        show: false,
        suggestionNoResult: false
      })
    
    // 这里实行onChange
    const addressOnchange: React.ChangeEventHandler<HTMLInputElement> = (e: React.ChangeEvent<HTMLInputElement>) => {
        // 将input中的value拿去查询
        // 实时设置value
        setListInput({...listInput, text: e.target.value})
    }
  
    return (
        <input type="text" value={listInput.text}   placeholder={listInput.holder} placeholder-style="color:#B7B9BE;" onChange={(e) => addressOnchange(e) } />
    )
}

这时候,我们将需求中的第三点,也就是允许用户清空输入框的基础已经实现了,清空的操作只需要

setListInput({...listInput, text: ''})

但是作为输入框,用户输入随时变化,如果根据这个变化频率来请求接口,不仅增加许多无谓的性能损耗,还可能把api搞崩,所以防抖是必须的。

// 由于实时设置input的value导致state刷新 初始化timeout一定要放在const Search的组件定义外部
let timeout: any

// 这里实行onChange
const addressOnchange: React.ChangeEventHandler<HTMLInputElement> = (e: React.ChangeEvent<HTMLInputElement>) => {
    if (timeout) clearTimeout(timeout)
    timeout = setTimeout(() => {
      console.log(e.target.value)
      // api request
    }, 800)
}

就这样,我们就实现了防抖,但是细心的小朋友会发现一个问题,那就是e.target变成了空,拿不到了。 原来我们打印这个值是在异步函数里面执行,在react中,异步函数对函数事件访问需要使用
e.persist()
加上之后

const addressOnchange: React.ChangeEventHandler<HTMLInputElement> = (e: React.ChangeEvent<HTMLInputElement>) => {
    e.persist()
    setListInput({...listInput, text: e.target.value})
    // 防抖
    if (timeout) clearTimeout(timeout)
    timeout = setTimeout(() => {
      console.log(e.target.value)
      // api request
    }, 800)
}

就这样,我们完美实现了搜索框的防抖,异步请求及清空input需求的基础