Lodash 使用 React 输入去抖动
Posted
技术标签:
【中文标题】Lodash 使用 React 输入去抖动【英文标题】:Lodash debounce with React Input 【发布时间】:2016-07-17 14:08:11 【问题描述】:我正在尝试将使用 lodash 的去抖动添加到从输入 onChange 事件调用的搜索函数中。下面的代码生成一个类型错误'函数是预期的',我理解这是因为 lodash 需要一个函数。这样做的正确方法是什么,可以全部内联吗?到目前为止,我已经尝试了几乎所有关于 SO 的示例,但均无济于事。
search(e)
let str = e.target.value;
debounce(this.props.relay.setVariables( query: str ), 500);
,
【问题讨论】:
试试这个freecodecamp.org/news/debounce-and-throttle-in-react-with-hooks 【参考方案1】:debounce 函数可以在 JSX 中内联传递或直接设置为类方法,如下所示:
search: _.debounce(function(e)
console.log('Debounced Event:', e);
, 1000)
小提琴: https://jsfiddle.net/woodenconsulting/69z2wepo/36453/
如果您使用的是 es2015+,您可以直接在 constructor
或 componentWillMount
之类的生命周期方法中定义您的 debounce 方法。
示例:
class DebounceSamples extends React.Component
constructor(props)
super(props);
// Method defined in constructor, alternatively could be in another lifecycle method
// like componentWillMount
this.search = _.debounce(e =>
console.log('Debounced Event:', e);
, 1000);
// Define the method directly in your class
search = _.debounce((e) =>
console.log('Debounced Event:', e);
, 1000)
【讨论】:
谢谢。我现在看到的是合成事件的控制台日志,我需要 e.target.value 来执行搜索。我试过 e.persist() 但它似乎没有做任何事情。去抖动在技术上是有效的,但如果没有传递一个值,它就不起作用。感谢您的帮助。 我不能完全使用它,但它让我到达了我需要去的地方。我基本上有输入调用 search(e) 然后将该事件传递给另一个具有去抖动功能的函数。我读到了 event.persist() 但我无法完成这项工作。谢谢你的帮助!! @Jeff Wooden fidden 坏了 感谢您推荐 componentWillMount。能够在 debounced 函数中访问 props 函数。如果我放入构造函数,不知何故我无法访问道具功能。 @RajeshMbm 您可以在类构造函数中访问道具,请参阅更新后的示例 - 它可作为第一个参数使用(确保包含 super 调用)。【参考方案2】:这就是我在谷歌搜索一整天后必须这样做的方式。
const MyComponent = (props) =>
const [reload, setReload] = useState(false);
useEffect(() =>
if(reload) /* Call API here */
, [reload]);
const callApi = () => setReload(true) ; // You might be able to call API directly here, I haven't tried
const [debouncedCallApi] = useState(() => _.debounce(callApi, 1000));
function handleChange()
debouncedCallApi();
return (<>
<input onChange=handleChange />
</>);
【讨论】:
useEffect 仅触发一次,因为第一次调用后重新加载将始终为真。 尝试将你的值设置为handleChange,而不是debouncedCallApi,然后callApi -> state,在这个useEffect触发你的函数之后^_^【参考方案3】:使用功能性反应组件尝试使用useCallback
。 useCallback
记住你的去抖动函数,所以当组件重新渲染时它不会一次又一次地重新创建。如果没有useCallback
,去抖动功能将不会与下一个按键同步。
`
import useCallback from 'react';
import _debounce from 'lodash/debounce';
import axios from 'axios';
function Input()
const [value, setValue] = useState('');
const debounceFn = useCallback(_debounce(handleDebounceFn, 1000), []);
function handleDebounceFn(inputValue)
axios.post('/endpoint',
value: inputValue,
).then((res) =>
console.log(res.data);
);
function handleChange (event)
setValue(event.target.value);
debounceFn(event.target.value);
;
return <input value=value onChange=handleChange />
`
【讨论】:
你在导入中有错字: import _debouce from 'lodash/debounce';这不是 _debouce 它是 _debounce 谢谢你! 只是一个警告,useCallback
会将所有带有useState
的变量设置为加载页面的初始值。我遇到了这个错误,现在正试图找到另一种使用去抖动器的方法。
@FiddleFreak 我从未经历过。我认为问题是别的。
@JulesPatry 实际上我通过这样做解决了这个问题 > ***.com/questions/70501416/…【参考方案4】:
这不是那么容易的问题
一方面要解决您遇到的错误,您需要将setVariables
包裹在函数中:
search(e)
let str = e.target.value;
_.debounce(() => this.props.relay.setVariables( query: str ), 500);
另一方面,我认为去抖动逻辑必须封装在 Relay 中。
【讨论】:
【参考方案5】:我发现这里的很多答案都过于复杂或不准确(即实际上并没有去抖动)。这是一个带有检查的简单解决方案:
const [count, setCount] = useState(0); // simple check debounce is working
const handleChangeWithDebounce = _.debounce(async (e) =>
if (e.target.value && e.target.value.length > 4)
// TODO: make API call here
setCount(count + 1);
console.log('the current count:', count)
, 1000);
<input onChange=handleChangeWithDebounce></input>
【讨论】:
【参考方案6】:对于您的情况,应该是:
search = _.debounce((e)
let str = e.target.value;
this.props.relay.setVariables( query: str );
, 500),
【讨论】:
【参考方案7】:class MyComp extends Component
debounceSave;
constructor(props)
super(props);
this.debounceSave = debounce(this.save.bind(this), 2000, leading: false, trailing: true );
save()是要调用的函数
debounceSave() 是您实际调用的函数(多次)。
【讨论】:
【参考方案8】:这对我有用:
handleChange(event)
event.persist();
const handleChangeDebounce = _.debounce((e) =>
if (e.target.value)
// do something
, 1000);
handleChangeDebounce(event);
【讨论】:
我认为它调用了 n 次,并且只是应用了这样的延迟,次,我至少现在尝试过。【参考方案9】:这是正确的 FC 方法 @
Aximili 回答触发器只有一次
import SyntheticEvent from "react"
export type WithOnChange<T = string> =
onChange: (value: T) => void
export type WithValue<T = string> =
value: T
// WithValue & WithOnChange
export type VandC<A = string> = WithValue<A> & WithOnChange<A>
export const inputValue = (e: SyntheticEvent<htmlElement & value: string >): string => (e.target as HTMLElement & value: string ).value
const MyComponent: FC<VandC<string>> = ( onChange, value ) =>
const [reload, setReload] = useState(false)
const [state, setstate] = useState(value)
useEffect(() =>
if (reload)
console.log('called api ')
onChange(state)
setReload(false)
, [reload])
const callApi = () =>
setReload(true)
// You might be able to call API directly here, I haven't tried
const [debouncedCallApi] = useState(() => _.debounce(callApi, 1000))
function handleChange(x:string)
setstate(x)
debouncedCallApi()
return (<>
<input
value=state onChange=_.flow(inputValue, handleChange) />
</>)
【讨论】:
【参考方案10】:有些答案忽略了如果您想使用事件对象 (e) 中的 e.target.value 之类的东西,当您通过 debounce 函数传递它时,原始事件值将为 null。
查看此错误消息:
警告:出于性能原因,此合成事件会被重复使用。如果您看到此内容,则表示您正在访问已发布/无效合成事件上的属性 nativeEvent
。这设置为空。如果您必须保留原始合成事件,请使用 event.persist()。
正如消息所述,您必须在事件函数中包含 e.persist()。例如:
const onScroll=(e) =>
debounceFn(e);
e.persist();
那么当然,你的 debounceFn 需要在 return 语句之外使用,以便使用 React.useCallback(),这是必要的。我的 debounceFn 看起来像这样:
const debounceFn = React.useCallback(
_.debounce((e) =>
calculatePagination(e),
500,
trailing: true,
),
[]
);
【讨论】:
我会避免将useCallback
与去抖器一起使用。这将强制所有 useState
挂钩从页面加载时重置为初始状态。【参考方案11】:
@Aximili
const [debouncedCallApi] = useState(() => _.debounce(callApi, 1000));
看起来很奇怪 :) 我使用 useCallback
提供解决方案:
const [searchFor, setSearchFor] = useState('');
const changeSearchFor = debounce(setSearchFor, 1000);
const handleChange = useCallback(changeSearchFor, []);
【讨论】:
【参考方案12】: const delayedHandleChange = debounce(eventData => someApiFunction(eventData), 500);
const handleChange = (e) =>
let eventData = id: e.id, target: e.target ;
delayedHandleChange(eventData);
【讨论】:
最好解释一下你的答案,它在做什么,它是如何解决OP的问题的,根据需要提供一些参考。仅添加代码块或链接是不够的。 Check *** answer guide以上是关于Lodash 使用 React 输入去抖动的主要内容,如果未能解决你的问题,请参考以下文章
Lodash Debounce 和 Apollo Client 使用LazyQuery 去抖动一次