Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/387.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript React Hooks useffect从useCallback调用prop回调_Javascript_Reactjs_React Hooks_Race Condition_Use Effect - Fatal编程技术网

Javascript React Hooks useffect从useCallback调用prop回调

Javascript React Hooks useffect从useCallback调用prop回调,javascript,reactjs,react-hooks,race-condition,use-effect,Javascript,Reactjs,React Hooks,Race Condition,Use Effect,我正在尝试制作一个带有React钩子(和Research Gate React Intersection Observer)的通用无限滚动条。其思想是,父级将传递一个映射的JSX数据数组和一个回调,该回调将异步获取该数组的更多数据,当交叉点观察者触发时,因为您向下滚动到足以显示加载图标,将调用回调并加载更多数据 它工作得很好,除了一件事:esLint告诉我,因为我在useEffect中调用getMore函数(从道具),所以它必须是该效果的依赖项。但因为在父级回调中,我正在访问其数据数组的长度,所

我正在尝试制作一个带有React钩子(和Research Gate React Intersection Observer)的通用无限滚动条。其思想是,父级将传递一个映射的JSX数据数组和一个回调,该回调将异步获取该数组的更多数据,当交叉点观察者触发时,因为您向下滚动到足以显示加载图标,将调用回调并加载更多数据

它工作得很好,除了一件事:esLint告诉我,因为我在useEffect中调用getMore函数(从道具),所以它必须是该效果的依赖项。但因为在父级回调中,我正在访问其数据数组的长度,所以该数组必须依赖于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]);

我将isLoading设置为true以触发效果;但它也会触发,因为当父级加载数据并且函数进行记忆时,getMore的引用会发生变化。这不应该发生。我可以为该行禁用esLint,但我认为有更好的解决方案,我想知道它是什么。

解决方案:根本不使用useEffect。只需直接从观察者调用加载函数,设置isLoading并调用回调,而不是让isLoading触发回调

const loadData = async (observerEntry) => {
    if (observerEntry.isIntersecting && !disabled && !isLoading) {
        setIsLoading(true);
        await getMore();
        setIsLoading(false);
    }
};

为什么
getMore
引用会更改?您可以在定义
getMore
的地方共享代码吗?我认为真正的问题是,您正在使用isLoading bool来控制异步数据加载,而实际情况恰恰相反。您可以在useEffect之外将异步函数设置为自己的函数,并在需要时调用它,即intersectionObserver事件触发时。异步函数将在开始时
setIsLoading(true)
,然后在结束时
setIsLoading(false)
控制
isLoading
变量。@Khauri问题是状态设置器是异步的,观察者可以在短时间内触发多次,具体取决于用户滚动的方式。因此,即使观察者调用的函数立即调用
setIsLoading(true)
,它仍然可以在值更改为
true
之前再次被调用,因此我仍然会得到重复调用:(…或者,至少我发誓我第一次尝试的时候就是这样。但是现在当我重新实现它时,它工作得很好O_O我以前肯定有一个未知的错误…你能把它作为一个官方答案发布出来让我接受吗?:DHmm我一生中只使用过IntersectionObserver一次,所以我不确定它是如何工作的。如果你有类似的错误我有点累了,你应该发布你自己的解决方案,并接受这个答案。
const loadData = async (observerEntry) => {
    if (observerEntry.isIntersecting && !disabled && !isLoading) {
        setIsLoading(true);
        await getMore();
        setIsLoading(false);
    }
};