useEffect вызывает бесконечный цикл

Я просмотрел каждый ответ бесконечного цикла в 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, что заставляет его вообще не устанавливать состояние.

Что мне не хватает?

РЕДАКТИРОВАТЬ:

Я удалил try / catch и [productList] из useEffect

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>
  );
};

person JordoJordo    schedule 02.06.2020    source источник


Ответы (1)


О том, как вы получаете свои данные: я думаю, проблема может быть в том, как вы извлекаете данные:

Как указано в документах Я думаю, вам не следует использовать здесь 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, чтобы быть уверенным

person Diego Segura    schedule 02.06.2020