React 涉及 e.target 时候,使用 debounce 节流函数
关键词: React, input, e.target, debounce
举例场景: 在一个 input 搜索框中输入文本,如果 2s 内可能会有很多次 input 的 onChange 事件,每次都触发一个 API 请求,明显不合理,所以此时需要 debounce 节流函数,2s 之内的所有输入只会请求一次 API,做到交互层面的优化。
为了缩小关注点,示例直接使用 loadsh 的 debounce 函数。也直接使用了类的示例属性方法 (可用过 babel 支持,因为实在不喜欢写过多的 bind)
== 直接上正确代码:==
import React from 'react'
import {debounce} from 'lodash'
export default class InputDebounce extends React.Component {constructor() {super()
this.doSearchAjax = debounce(this.doSearchAjax, 2000)
}
handleInputSearch = e => {this.doSearchAjax(e.target.value)
}
doSearchAjax = value => {console.log('执行 AJAX 搜索', value)
}
render() {
return (
<div>
<h4>e.target 结合 debounce 使用 </h4>
<input type="text" onChange={this.handleInputSearch} />
</div>
)
}
}
再来看常见的错误代码示例
一、直接使用 debounce 函数包裹事件函数
报错: Uncaught TypeError: Cannot read property ‘value’ of null
原因分析: 涉及到 React 中的合成事件,详见 React 合成事件,debounce 包装后的回调函数,是个异步事件,即 e.target 为 null 了
解决方案: 使用 e.persist() 实现对事件的引用保留
import React from 'react'
import {debounce} from 'lodash'
export default class InputDebounce extends React.Component {
handleInputSearch = e => {this.doSearchAjax(e.target.value)
}
doSearchAjax = value => {console.log('执行 AJAX 搜索')
}
render() {
return (
<div>
<h4>e.target 结合 debounce 使用 </h4>
<input type="text" onChange={debounce(this.handleInputSearch, 2000)} />
</div>
)
}
}
二、使用了 e.persist(),但是 debounce 包含的函数并不会执行
import React from 'react'
import {debounce} from 'lodash'
export default class InputDebounce extends React.Component {
handleInputSearch = e => {
// 对原有事件进行保留
e.persist()
debounce(() => {
// 函数并不会执行
this.doSearchAjax(e.target.value)
}, 2000)
}
doSearchAjax = value => {console.log('执行 AJAX 搜索')
}
render() {
return (
<div>
<h4>e.target 结合 debounce 使用 </h4>
<input type="text" onChange={this.handleInputSearch} />
</div>
)
}
}
这时候,需要将异步执行的函数抽离出来,即开头的正确代码。
正确代码里面并未使用 e.persist(),因为没有必要,onChange 函数并非是被 debounce 函数包装的。这里写出来只是为了记录踩坑,估计也有很多小伙伴掉过这个坑吧