useEffect 和 dispatch with useCallback 导致无限循环

时间:2021-04-18 21:39:01

标签: reactjs

如果 isLoading is true,则尝试加载产品, 但是,请求可能会返回空数组作为结果。 所以我无法根据产品将 isLoading 设置为 false

  const [products] =  useSelector((state) => [
        state.application.products
    ]);

但是,如果我将 setIsLoading(false) 放在 dispatch 的回调中。

这会导致使我困惑的 inf 循环。

如何以好的模式解决这个问题?谢谢

const Products = () => {
  const [isLoading, setIsLoading] = React.useState(true)
  const [products] =  useSelector((state) => [
        state.application.products
    ]);


    const fetchProductsUpHandler = useCallback(async () => {
        const params = {}
        // should I call setIsLoading(false) here?
        // setIsLoading is local context, loadProducts is defined in reducers.
        dispatch(loadProducts()).then(function(){            
            setIsLoading(false)
        });
    }, []);

    useEffect(() => {
        if (isLoading){
            fetchProductsUpHandler();
        }
    }, [isLoading]);


    return (
// is this part causing error?
        <>
                <ProductTable
                    isLoading={isLoading}
                    products={products}
                />

        </>
    );
  

}

3 个答案:

答案 0 :(得分:0)

我发现的一个常见模式是在您的 redux 状态中有 isLoading 标志。所以你的代码应该是这样的:

const [isLoading] =  useSelector((state) => [
  state.application.isLoading
]);

我假设您的 loadProducts() 正在执行操作,因此将有逻辑将您的 isLoading 设置为 truefalse

答案 1 :(得分:0)

您的 useEffect() 函数设置为在更新 isLoadingproducts 时运行。你没有分享你的所有代码,所以我看不到幕后发生了什么,但我想知道你是否也在某个时候更新产品状态?我怀疑是这样的:

  1. 应用加载,isLoading = true 为默认值
  2. useEffect() 触发器,isLoading 为真所以我们调用 fetchProductsUpHandler()
  3. dispatch(loadProducts()) 运行并更新 products(这是我看不到的部分,我正在猜测)
  4. useEffect() 由于 product 变化而触发
  5. 返回第 3 步,因为 isLoading 仍然为真

如果这是正确的,解决方案是将 productuseEffect() 钩子中取出

答案 2 :(得分:0)

您必须问自己的问题是,为什么将 isLoading 作为 fetchProductsUpHandler 的依赖项?

useEffect(() => {
    if (isLoading){
        fetchProductsUpHandler();
    }
}, [isLoading]);

你可以把它完全放到一个你 setIsLoading(true) 的函数中,这样你就可以避免循环。

const onClick = async () => {
   setIsLoading(true)
   await fetchProductsUpHandler()
   setIsLoading(false)
}

如果它不是触发事件并且您只是加载了一次,那么您可以删除依赖项。

useEffect(() => {

        fetchProductsUpHandler();

}, []);