我在搜索页面上有一个组件,在该组件内部,有一个 useEffect ,当搜索词(城市、帖子中的单词、帖子数量)发生变化时,会触发帖子过滤并从数据库中获取代码。当我输入一个单词然后将其删除时,代码会继续运行。如果我输入另一个单词,这两个函数基本上是并行运行的。我想这样做,以便当输入或添加新单词时,先前的过滤过程将被重置并重新开始。例如,如果我输入一个单词并且代码开始(开始迭代并过滤帖子),然后我立即删除该单词并添加另一个单词,则正在进行的代码将停止并以新条件重新开始。
React.useEffect(() => {
const loadAndFilterPosts = async () => {
let postsToLoad = 300; // first count posts for loading
let allLoadedPosts:any = []; // array for all loading posts
let filteredPosts= [];
let keys:string[] = []; // keys from redis
let i = 0;
// if chosen category => get keys from refdis
if (chosenCategory && chosenCategory.id) keys = await getKeys(chosenCategory?.id)
while (allLoadedPosts.length < postsToLoad) {
let newPosts = await loadPostsFromRedis(i, keys); // loading posts from Redis
if (!newPosts.length) {
break;
}
// if free period
if (infoUser && infoUser?.categoriesFreePeriod?.length > 0 && !infoUser?.endFreePeriod) {
const currentDate = new Date();
currentDate.setDate(currentDate.getDate() - 3);
newPosts = newPosts.filter((item: any) => new Date(item.post_date_publish*1000).getTime() < currentDate.getTime());
}
allLoadedPosts = [...allLoadedPosts, ...newPosts];
filteredPosts = applyFilters(allLoadedPosts); // add filter (keywords)
setFilteredPosts(filteredPosts.sort((a:any, b:any) => a.data - b.data))
if (filteredPosts.length >= postsToLoad) {
break;
}
postsToLoad += 300;
i++;
}
};
loadAndFilterPosts()
setPage(1)
}, [keyWords, keyCityWords, social, postsCount, chosenCategory])
您描述的过程称为
debouncing
。您可以使用 underscore
或 lodash
提供的实用程序,但这里是一个自定义示例:
const runDebouncedSearch = useMemo(
() => debounce((term: string) => searchSomething(term), 400),
[]
);
useEffect(() => {
runDebouncedSearch(inputSearchTerm); // when input changes, schedule search in 400 ms. Cancel previous searches if typing rapidly
return () => runDebouncedSearch.cancel(); // cancel pending searches, when detaching component
}, [runDebouncedSearch, inputSearchTerm]);
和实施:
type DebounceOptions = XOR<
{ leading?: boolean },
{ leadingOnce?: boolean }
>;
export const debounce = <A = void>(
func: (arg: A) => void,
delay: number,
{ leading, leadingOnce }: DebounceOptions = {}
): CancellableFunction<A> => {
let timerId: NodeJS.Timeout | undefined;
let isLeadingRan = false;
const debounced = (arg: A) => {
const shouldRunLeadingOnce = leadingOnce && !isLeadingRan;
const shouldRunLeading = leading || shouldRunLeadingOnce;
if (!timerId && shouldRunLeading) {
isLeadingRan = true;
func(arg);
}
if (timerId) {
clearTimeout(timerId);
}
timerId = shouldRunLeadingOnce
? undefined
: setTimeout(() => func(arg), delay);
};
debounced.cancel = () => {
timerId && clearTimeout(timerId);
timerId = undefined;
};
return debounced;
};