在 React es6 中去抖动
Debounce in React es6
我的一个页面中有一个搜索输入,我试图确保它不会在用户键入速度过快的情况下在一秒钟内发出 10 个请求。
似乎去抖动是可行的方法。我已经阅读了多篇博客文章和 SO 问题。我正在尝试使用 lodash 的去抖动。我一定是做错了什么,因为发生的事情是我所有的电话都通过了,只是稍后。
这是我的组件代码:
const Partners = (props: any) => {
const [query, setQuery] = useState("");
const { partners, totalPages, currentPage } = props.partnersList;
useEffect(() => {
props.getPartners();
}, []);
useEffect(() => debounce(() => props.getPartners(query), 10000), [query]);
const handleQueryChange = (e: any) => {
setQuery(e.target.value);
};
const handlePageChange = (e: React.ChangeEvent<unknown>, value: number) => {
props.getPartners(query, value);
};
return (
<React.Fragment>
<Sidebar />
<MainContent className="iamSearchPartners">
<h1>Partners</h1>
<TextField
className="iamSearchPartners__search_input"
variant="outlined"
size="small"
onChange={handleQueryChange}
value={query}
/>
<PartnersList partners={partners} />
{totalPages > 1 && (
<Pagination
currentPage={currentPage || 1}
totalPages={totalPages}
handlePageChange={handlePageChange}
/>
)}{" "}
</MainContent>
</React.Fragment>
);
};
如您所见,我有一个 useEffect 监听查询的更改。
老实说,我最终还是手动完成了这件事。查看 debouncing and throttling 之间的差异。我想你想限制请求。如果你去抖动,在计时器结束之前什么都不会发生。
如果您想像您的示例中那样等待 10 秒,那么如果用户至少每 10 秒键入一次,直到最后一次键入 10 秒后才不会发生任何事情。与限制请求每 10 秒发出一次相反。
这种方法是一种混合方法,因为我们要确保最后一个仍然熄灭(就像去抖动一样),而节流可能不会,但我们仍在用户键入时发送请求。
const timer = useRef<number>(0);
const lastEventSent = useRef(Date.now());
useEffect(() => {
if (Date.now() - lastEventSent.current < 500) {
// The event was fired too recently, but we still want
// to fire this event after the timeout if it is the last
// one (500ms in this case).
timer.current = setTimeout(() => {
lastEventSent.current = Date.now();
props.getPartners(query)
}, 500);
} else {
// An event hasn't been fired for 500ms, lets fire the event
props.getPartners(query)
lastEventSent.current = Date.now();
// And if the user was typing, there is probably a timer, lets clear that
clearTimeout(timer.current);
}
// Cleanup the timer if there was one and this effect is reloaded.
return () => clearTimeout(timer.current);
}, [query]);
debounce
创建作为参数传递的函数的去抖动版本。在这种特定情况下,在 useEffect
中调用它会在每个渲染器上创建一个新的去抖动版本的函数。
为了缓解这种情况,可以在渲染函数之外创建去抖动版本,因此不会在每次渲染时都重新创建。
const myDebouncedFunction = debounce((handler, query) => handler(query), 10000);
const Partners = (props: any) => {
// omitted ...
useEffect(() => {
myDebouncedFunction(props.getPartners, query);
}, [query]);
// omitted ...
useMemo
或将其放入 useState
中也可以。
另一件事:useEffect
只调用了 returned 去抖动版本,因为它是一个没有大括号的箭头函数,使它成为 return 评估的结果。 useEffect
利用其功能的 return
成为某种“取消订阅”处理程序,see React docs about "Effects with cleanup"。所以每当 query
改变时(第二次之后),效果就是调用函数。每次查询更改时都应调用上面的版本。
就个人而言,我会尝试在 handleQueryChange
中而不是 useEffect
中处理函数的去抖动版本的调用,以使“它应该何时发生”更加清晰。
我的一个页面中有一个搜索输入,我试图确保它不会在用户键入速度过快的情况下在一秒钟内发出 10 个请求。
似乎去抖动是可行的方法。我已经阅读了多篇博客文章和 SO 问题。我正在尝试使用 lodash 的去抖动。我一定是做错了什么,因为发生的事情是我所有的电话都通过了,只是稍后。
这是我的组件代码:
const Partners = (props: any) => {
const [query, setQuery] = useState("");
const { partners, totalPages, currentPage } = props.partnersList;
useEffect(() => {
props.getPartners();
}, []);
useEffect(() => debounce(() => props.getPartners(query), 10000), [query]);
const handleQueryChange = (e: any) => {
setQuery(e.target.value);
};
const handlePageChange = (e: React.ChangeEvent<unknown>, value: number) => {
props.getPartners(query, value);
};
return (
<React.Fragment>
<Sidebar />
<MainContent className="iamSearchPartners">
<h1>Partners</h1>
<TextField
className="iamSearchPartners__search_input"
variant="outlined"
size="small"
onChange={handleQueryChange}
value={query}
/>
<PartnersList partners={partners} />
{totalPages > 1 && (
<Pagination
currentPage={currentPage || 1}
totalPages={totalPages}
handlePageChange={handlePageChange}
/>
)}{" "}
</MainContent>
</React.Fragment>
);
};
如您所见,我有一个 useEffect 监听查询的更改。
老实说,我最终还是手动完成了这件事。查看 debouncing and throttling 之间的差异。我想你想限制请求。如果你去抖动,在计时器结束之前什么都不会发生。
如果您想像您的示例中那样等待 10 秒,那么如果用户至少每 10 秒键入一次,直到最后一次键入 10 秒后才不会发生任何事情。与限制请求每 10 秒发出一次相反。
这种方法是一种混合方法,因为我们要确保最后一个仍然熄灭(就像去抖动一样),而节流可能不会,但我们仍在用户键入时发送请求。
const timer = useRef<number>(0);
const lastEventSent = useRef(Date.now());
useEffect(() => {
if (Date.now() - lastEventSent.current < 500) {
// The event was fired too recently, but we still want
// to fire this event after the timeout if it is the last
// one (500ms in this case).
timer.current = setTimeout(() => {
lastEventSent.current = Date.now();
props.getPartners(query)
}, 500);
} else {
// An event hasn't been fired for 500ms, lets fire the event
props.getPartners(query)
lastEventSent.current = Date.now();
// And if the user was typing, there is probably a timer, lets clear that
clearTimeout(timer.current);
}
// Cleanup the timer if there was one and this effect is reloaded.
return () => clearTimeout(timer.current);
}, [query]);
debounce
创建作为参数传递的函数的去抖动版本。在这种特定情况下,在 useEffect
中调用它会在每个渲染器上创建一个新的去抖动版本的函数。
为了缓解这种情况,可以在渲染函数之外创建去抖动版本,因此不会在每次渲染时都重新创建。
const myDebouncedFunction = debounce((handler, query) => handler(query), 10000);
const Partners = (props: any) => {
// omitted ...
useEffect(() => {
myDebouncedFunction(props.getPartners, query);
}, [query]);
// omitted ...
useMemo
或将其放入 useState
中也可以。
另一件事:useEffect
只调用了 returned 去抖动版本,因为它是一个没有大括号的箭头函数,使它成为 return 评估的结果。 useEffect
利用其功能的 return
成为某种“取消订阅”处理程序,see React docs about "Effects with cleanup"。所以每当 query
改变时(第二次之后),效果就是调用函数。每次查询更改时都应调用上面的版本。
就个人而言,我会尝试在 handleQueryChange
中而不是 useEffect
中处理函数的去抖动版本的调用,以使“它应该何时发生”更加清晰。