我正在尝试使用React Hooks(和ResearchGate React Intersection观察者)制作一个通用的无限滚动器。这个想法是,父级将传递一个映射的JSX数据数组,并传递一个回调,该回调将异步获取该数组的更多数据,并且当交集观察者触发时,因为您向下滚动足以显示加载图标,该回调将调用并加载更多数据。
它工作得很好,除了一件事:esLint告诉我,因为我正在useEffect内调用getMore函数(来自props),所以它必须是该效果的依赖项。但是因为在父级的回调中,我正在访问其数据数组的长度,所以该数组必须是useCallback的依赖项。然后该回调修改数组。
TL; DR:我正在遇到一些种族问题,这些条件会导致异步回调在不应该触发的情况下多次触发,因为回调函数引用正在更改,然后传递给调用它的事物。
这里有一些代码需要澄清。
父级中的回调:
const loadData = useCallback(async () => {
if (hasMore) {
const startAmount = posts.length;
for (let i = 0; i < 20; ++i) {
posts.push(`I am post number ${i + startAmount}.`);
await delay(100);
}
setPosts([...posts]);
setHasMore(posts.length < 100);
}
}, [posts, hasMore]);
posts和hasMore只是状态变量,posts作为props中的数据数组向下传递给子级。该函数将通过props传递给子级,而props具有此子项(getMore是回调的经过分解的prop,isLoading只是布尔状态变量):
useEffect(() => {
if (isLoading) {
(async () => {
await getMore();
setIsLoading(false);
})();
}
}, [isLoading, getMore]);
我将isLoading设置为true以触发效果;但它也会触发,因为当父级加载数据并且该函数进行记忆时,getMore的引用会更改。那不应该发生的。我可以为此行禁用esLint,但我认为有一个更好的解决方案,我想知道它是什么。
答案 0 :(得分:0)
解决方案:根本不使用useEffect。只需直接从观察者调用加载函数,并设置isLoading并调用回调即可,而不是让isLoading触发回调。
const loadData = async (observerEntry) => {
if (observerEntry.isIntersecting && !disabled && !isLoading) {
setIsLoading(true);
await getMore();
setIsLoading(false);
}
};