antd的input框onChange事件使用防抖沒法獲取到e.target

最近接觸umi,在使用umi搭建後臺項目時發現,有一個需求是在input框輸入時進行防抖查詢。可是Antd的input框,onChange事件觸發返回的callback若是用防抖函數包裹的話,event對象的target屬性是null。react

效果以下:ajax

<Input
      placeholder="任務ID"
      onChange={debounce(e => {
        console.log(e)
        if (e.target) {
          let q = e.target.value;
          setPendingId(q || undefined)
        }
      }, 500)}
      allowClear
    />
    
複製代碼

打印結果:瀏覽器

很明顯target是null,爲何正常callback能夠獲取到,使用debouce函數就出現如此怪異的現象?bash

查閱一番以後得知,原來是React的合成事件(SyntheticEvent)致使的。異步

合成事件(SyntheticEvent)函數

事件處理程序經過 合成事件(SyntheticEvent)的實例傳遞,SyntheticEvent 是瀏覽器原生事件跨瀏覽器的封裝。SyntheticEvent 和瀏覽器原生事件同樣有 stopPropagation()、preventDefault() 接口,並且這些接口誇瀏覽器兼容。性能

事件池(Event Pooling)ui

SyntheticEvent 是池化的. 這意味着 SyntheticEvent 對象將會被重用,而且全部的屬性都會在事件回調被調用後被 nullified。 這是由於性能的緣由。 所以,你不能異步的訪問事件。this

經過了解事件系統,也就不難理解爲何會報錯了。由於通過 debounce 包裝後的回調函數,變成了一個異步事件,在池化後被 nullified 了。spa

那麼怎樣才能解決這個問題?

  1. 對於class組件:

經過在回調事件頂部加上 e.persist() 就能夠從池中移除合成事件,並容許對事件的引用保留。而且把須要異步執行的回調函數抽離出來封裝,而且在組件初始化話的時候就將其 debounce 化,就能夠獲得咱們想要的效果。

import react, { Component } from 'react';
import { debounce } from 'lodash.debounce';

export default class Debounce extends Component {
  construtor() {
    super();
    this.callAjax = debounce(this.callAjax, 300);
  }
  
  callAjax = (value) => {
    console.log('value :: ', value);
    // call ajax
  }
  printChange(e) {
    e.persist();
    this.callAjax(e.target.value);
  }
  render() {
    return (
      <div>
        <input onChange={this.printChange} />
      </div>
    );
  }
}
複製代碼
  1. 對於Function組件

由於我使用的是Hooks,因此換了個想法,使用ref,直接上代碼

// 使用iseRef
import React, { useState, useEffect, useRef } from 'react';

const fileInputEl: any = useRef(null)

const callAjax = (value) => {
    setPendingId(value || undefined);
}

let printChange = debounce((e) => {
    e.persist()
    console.log(fileInputEl);

    callAjax(fileInputEl.current.input.state.value)
}, 500)

<Input
  placeholder="任務ID"
  ref={fileInputEl}
  onChange={printChange}
  allowClear
/>
複製代碼

打印結果

後面發現只要不直接用debounce包裹回調函數,使用函數調用傳參的方法就能夠拿到e.target了。

const printChange = (e) => {
        taskChange(e.target.value)
    }
    
    const taskChange = debounce((value) => {
        setPendingId(value || undefined);
    }, 500)
    
    <Input
      placeholder="任務ID"
      ref={fileInputEl}
      onChange={printChange}
      allowClear
    />
複製代碼

這裏就能夠拿到input中的value了,哈哈,以爲有用的話就給個贊吧。

相關文章
相關標籤/搜索