最好先看看我的代码:
import React, { Component } from 'react';
import _ from 'lodash';
import Services from 'Services'; // Webservice calls
export default class componentName extends Component {
constructor(props) {
super(props);
this.state = {
value: this.props.value || null
}
}
onChange(value) {
this.setState({ value });
// This doesn't call Services.setValue at all
_.debounce(() => Services.setValue(value), 1000);
}
render() {
return (
<div>
<input
onChange={(event, value) => this.onChange(value)}
value={this.state.value}
/>
</div>
)
}
}
只是一个简单的输入。在constructor中,它从props(如果可用)中获取value
,为组件设置本地状态。
然后,在input
的onChange
函数中,我更新了状态,然后尝试调用Web服务端点来使用Services.setValue()
设置新值。
如果我直接通过输入的onChange
设置debounce
,就可以这样做:
<input
value={this.state.value}
onChange={_.debounce((event, value) => this.onChange(value), 1000)}
/>
但是this.setState
每1000毫秒才被调用一次,并更新视图。因此,在文本字段中键入内容最终看起来很奇怪,因为您键入的内容仅在一秒钟后显示。
在这种情况下我该怎么办?
6条答案
按热度按时间xqk2d5yq1#
出现问题的原因是您没有调用去抖动函数,您可以按以下方式执行操作
fd3cxomn2#
为那些因为throttle / debounce不适用于
FunctionComponent
而来到这里的人提供的解决方案-您需要通过useRef()存储debounce函数:This medium article完美地解释了发生了什么:
函数中的局部变量在每次调用后都会过期。每次重新计算组件时,局部变量都会再次初始化。Throttle和debounce在幕后使用
window.setTimeout()
工作。每次计算函数组件时,都注册一个新的setTimeout
回调。因此,我们将使用useRef()
钩子,因为useRef()
返回的值不会在每次执行函数组件时重新计算。唯一的不便之处是您必须通过.current
属性访问存储的值。我已经用
lodash.throttle
和lodash.debounce
两个小包创建了sandbox,这样您就可以试验这两个包并选择合适的行为ahy6op9u3#
对于React功能组件,默认情况下去抖动不工作。您必须执行以下操作才能使其工作:
useCallback使用debounce返回的函数,并按预期工作。虽然,当你想在去抖动函数中使用状态变量时,这有点复杂(通常是这种情况)。
react.useCallback的第二个参数是依赖项。如果你想在debbounced函数中使用state或prop变量,默认情况下,它使用旧版本的state变量,这将导致你的函数使用变量的历史值,而这不是你需要的。为了解决这个问题,你必须像在React.useEffect中那样包含状态变量,如下所示:
这个实现可能会解决你的目的。但是您会注意到,每次作为依赖项传递的状态变量(stateVariable1,stateVariable2)发生变化时,都会调用debounced函数。这可能不是您所需要的,尤其是在使用输入字段等受控组件时。
我意识到的最佳解决方案是花一些时间将功能组件更改为基于类的组件,并使用以下实现:
nx7onnlm4#
我为那些使用react函数组件的人写了一个钩子。
它是typescript,但是你可以忽略在你的JavaScript应用程序中使用的类型注解。
我的天| use-debounce.ts |
我的天|使用方法:|
mpbci0fu5#
功能组件解决方案-useCallback
jgwigjjp6#
基于类的组件的Lodash去抖动解决方案