useEffect 导致死循环

useEffect causing infinite loop

我已经查看了 SO 中的每个无限循环答案,但我无法弄清楚我做错了什么。

我正在尝试获取一些数据并使用这些数据设置我的 productList 状态,但它会导致无限循环。

export default (props) => {
  const [productsList, setProductsList] = useState([]);

  const getProducts = async () => {
    try {
      await axios
        .get("https://api.stripe.com/v1/skus", {
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${StripeKey}`,
          },
        })
        .then(({ data }) => {
          setProductsList(data.data);
        });
    } catch {
      (error) => {
        console.log(error);
      };
    }
  };

  useEffect(() => {
    getProducts();
  }, [productList]);

  return (
    <ProductsContext.Provider value={{ products: productsList }}>
      {props.children}
    </ProductsContext.Provider>
  );
};

我也试过在 useEffect 的末尾有一个空数组,这导致它根本不设置状态。

我错过了什么?

编辑:

我从 useEffect

中删除了 try/catch 和 [productList]
import React, { useState, useEffect } from "react";
import axios from "axios";

const StripeKey = "TEST_KEY";

export const ProductsContext = React.createContext({ products: [] });

export default (props) => {
  const [productsList, setProductsList] = useState([]);

  useEffect(() => {
    axios({
      method: "get",
      url: "https://api.stripe.com/v1/skus",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${StripeKey}`,
      },
    })
      .then((response) => {
        setProductsList(response.data.data)
      })
      .catch((error) => {
        console.log(error);
      });
  }, []);

  return (
    <ProductsContext.Provider value={{ products: productsList }}>
      {props.children}
    </ProductsContext.Provider>
  );
};

关于您获取数据的方式: 我认为问题可能出在您获取数据的方式上:

docs 中所述,我认为您不应该在这里使用 try catch,而是像这样:

function MyComponent() {
  const [error, setError] = useState(null);
  const [isLoaded, setIsLoaded] = useState(false);
  const [items, setItems] = useState([]);

  // Note: the empty deps array [] means
  // this useEffect will run once
  // similar to componentDidMount()
  useEffect(() => {
    fetch("https://api.example.com/items")
      .then(res => res.json())
      .then(
        (result) => {
          setIsLoaded(true);
          setItems(result.items);
        },
        // Note: it's important to handle errors here
        // instead of a catch() block so that we don't swallow
        // exceptions from actual bugs in components.
        (error) => {
          setIsLoaded(true);
          setError(error);
        }
      )
  }, [])

  if (error) {
    return <div>Error: {error.message}</div>;
  } else if (!isLoaded) {
    return <div>Loading...</div>;
  } else {
    return (
      <ul>
        {items.map(item => (
          <li key={item.name}>
            {item.name} {item.price}
          </li>
        ))}
      </ul>
    );
  }
}

关于useEffect回调:

我认为您不应该使用 [productList] 作为您正在更新的项目,所以一旦您执行了 setProducts,它就会再次触发。当请求的道具发生变化或者只是在组件上挂载时,您可能想再次进行获取(如您所说的空数组)

此外,该代码示例可能还存在我们看不到的其他副作用。也许你可以分享一个 stackblitz 来确定