Reactjs 产生无限循环的效应

Reactjs 产生无限循环的效应,reactjs,react-hooks,infinite-loop,use-effect,use-state,Reactjs,React Hooks,Infinite Loop,Use Effect,Use State,我已经在SO中查看了每个无限循环的答案,我无法找出我做错了什么 我试图获取一些数据并用这些数据设置我的productList状态,但这会导致无限循环 export default (props) => { const [productsList, setProductsList] = useState([]); const getProducts = async () => { try { await axios .get("https:

我已经在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>
  );
};

导出默认值(道具)=>{
const[productsList,setProductsList]=useState([]);
const getProducts=async()=>{
试一试{
等待axios
.get(“https://api.stripe.com/v1/skus", {
标题:{
“内容类型”:“应用程序/json”,
授权:`Bearer${StripeKey}`,
},
})
。然后({data})=>{
setProductsList(data.data);
});
}抓住{
(错误)=>{
console.log(错误);
};
}
};
useffect(()=>{
getProducts();
},[productList]);
返回(
{props.children}
);
};
我还尝试过在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>
  );
};
import React,{useState,useffect}来自“React”;
从“axios”导入axios;
const StripeKey=“测试密钥”;
export const ProductsContext=React.createContext({products:[]});
导出默认值(道具)=>{
const[productsList,setProductsList]=useState([]);
useffect(()=>{
axios({
方法:“获取”,
url:“https://api.stripe.com/v1/skus",
标题:{
“内容类型”:“应用程序/json”,
授权:`Bearer${StripeKey}`,
},
})
。然后((响应)=>{
setProductsList(response.data.data)
})
.catch((错误)=>{
console.log(错误);
});
}, []);
返回(
{props.children}
);
};

关于如何获取数据: 我认为问题可能在于如何获取数据:

如中所述,我认为您不应该在此处使用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>
    );
  }
}
函数MyComponent(){
const[error,setError]=useState(null);
const[isLoaded,setIsLoaded]=useState(false);
const[items,setItems]=useState([]);
//注意:空的deps数组[]表示
//此useEffect将运行一次
//与componentDidMount()类似
useffect(()=>{
取回(“https://api.example.com/items")
.then(res=>res.json())
.那么(
(结果)=>{
setIsLoaded(真);
设置项(结果项);
},
//注意:这里处理错误很重要
//而不是一个catch()块,这样我们就不会吞咽
//组件中实际错误的例外情况。
(错误)=>{
setIsLoaded(真);
设置错误(错误);
}
)
}, [])
如果(错误){
返回错误:{Error.message};
}否则,如果(!已加载){
返回装载。。。;
}否则{
返回(
    {items.map(item=>(
  • {item.name}{item.price}
  • ))}
); } }
关于useEffect回调:

我认为您不应该使用[productList]作为您正在更新的项目,因此一旦您执行setProducts,它将再次触发。当请求的一个属性发生变化时,或者只是在组件挂载时,您可能希望再次执行抓取(如您所说的空数组)


此外,可能还有其他一些我们在代码示例中看不到的副作用。也许您可以分享一次stackblitz,以确定如何获取数据: 我认为问题可能在于如何获取数据:

如中所述,我认为您不应该在此处使用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>
    );
  }
}
函数MyComponent(){
const[error,setError]=useState(null);
const[isLoaded,setIsLoaded]=useState(false);
const[items,setItems]=useState([]);
//注意:空的deps数组[]表示
//此useEffect将运行一次
//与componentDidMount()类似
useffect(()=>{
取回(“https://api.example.com/items")
.then(res=>res.json())
.那么(
(结果)=>{
setIsLoaded(真);
设置项(结果项);
},
//注意:这里处理错误很重要
//而不是一个catch()块,这样我们就不会吞咽
//组件中实际错误的例外情况。
(错误)=>{
setIsLoaded(真);
设置错误(错误);
}
)
}, [])
如果(错误){
返回错误:{Error.message};
}否则,如果(!已加载){
返回装载。。。;
}否则{
返回(
    {items.map(item=>(
  • {item.name}{item.price}
  • ))}
); } }
关于useEffect回调:

我认为您不应该使用[productList]作为您正在更新的项目,因此一旦您执行setProducts,它将再次触发。当请求的一个属性发生变化时,或者只是在组件挂载时,您可能希望再次执行抓取(如您所说的空数组)

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