reactjs - 在没有外部依赖的情况下反应本机去抖钩子
问题描述
我正在研究一个去抖钩子,我可以用它来包装我所有的“OnPress”函数。我不想使用任何外部库(或者如果它非常小,则只使用外部库)。
我的例子就是基于这种方法。还有一种方法似乎更简单一些。在这两种方法中,我看不到它们在组件卸载时清除计时器。
我创建了以下内容,它似乎有效。我将在很多地方使用它,所以我想对我的方法进行一些验证。这是一种可行的方法吗?这种方法会影响性能吗?
import { useState, useEffect } from 'react';
/**
* After calling an action, delay the next call by debounceTimeout.
* Use this function if you do not want an action to be called many times in a row. Use the debounceTimeout to reset,
* and make the action ready to be called again. A typical scenario is to avoid overfloading an api with many calls or
* prevent a navigation library from pushing many navigation stacks; if a user presses the navigation button mulitple times in a row
* @param action A function that should be debounced. E.g an OnClick action for a touchable component
* @param debounceTimeout A timeout for the debounce
* @returns The action wrapped in a debounce function
*
**/
const useDebounceAction = (
action: () => void,
debounceTimeout = 600
): (() => void) => {
let debounceHandler: NodeJS.Timeout;
const [isLoading, setIsLoading] = useState(false);
// useEffect to clean up our debounceHandler when component (using this hook) gets unmonted
useEffect(() => {
return () => {
setIsLoading(false);
clearTimeout(debounceHandler);
};
}, [action]);
const debounceWrappedAction = () => {
if (isLoading) {
return;
}
setIsLoading(true);
action();
debounceHandler = setTimeout(() => {
setIsLoading(false);
}, debounceTimeout);
};
return debounceWrappedAction;
};
export default useDebounceAction;
我将如何使用它的示例:
// 'createNewTaskApi' could be a function that creates a new task on the api for each call
// Could also be a redux action
import { createNewTaskApi } from './src/apiCalls';
import useDebounceAction from './src/common/hooks/useDebounceAction';
import Button from './src/common/Button';
const CreateNewTaskButton = ({ task } : { task: Task }) => {
// We do not want a fast doubble tab on our button to create two tasks.
// Therefore we wrap createNewTaskApi in our useDebounceClickHandler
const debounceOnPress = useDebounceAction(() => createNewTaskApi(task), 300);
return <Button title="Create Task" onPress={debounceOnPress} />
}
编辑1:测试后我有一些问题,如果我用空数组调用我的useEffect以避免触发额外的重新渲染,我将在未安装组件上更新反应状态时收到错误
useEffect(() => {
return () => {
clearTimeout(debounceHandler);
};
}, []);
编辑 2: useCallback 函数解决了我的问题EDIT 1
编辑 3:使用回调函数记住了上下文。所以我在按下按钮时总是会得到初始化的上下文。为了解决这个问题,我添加了[action]
. 因此,如果动作发生变化,将创建一个新函数。但是现在我回到了未安装组件错误的更新状态
const debounceWrappedAction = useCallback(() => {
if (isLoading) {
return;
}
setIsLoading(true);
action();
debounceHandler = setTimeout(() => {
setIsLoading(false);
}, debounceTimeout);
}, [action]);
编辑 4:我还将 [action] 添加到 useEffect 调用中。我认为这解决了我再次更新未安装组件错误状态的问题。我认为clearTimeout(debounceHandler);
有时指的是旧的 debounceHandler。
useEffect(() => {
return () => {
clearTimeout(debounceHandler);
};
}, [action]);
编辑 5:再次删除了 useCallback 函数。因为虽然我没有收到任何更新状态错误,但我的 debounce 也不起作用
解决方案
推荐阅读
- regex - DataStudio 中的正则表达式提取
- javascript - 通过对象传播转换数组赋值
- javascript - 无法访问 Reducer 和状态值
- typescript - 如何从我的 index.ts 文件中的另一个自定义云函数中调用自定义函数?
- ios - 集合视图单元与另一个单元之间的 TVOS 焦点
- c++ - 如何让 C++ 读取文件
- python-3.x - 我在 Pygame 中的评分系统一遍又一遍地重叠
- html - 如何在 chrome 中制作细滚动条?
- reactjs - React Typescript ant design selected drop down disable
- android - 在现代 XIAOMI、华为或三星设备中,前台服务已被终止且未安排警报