【问题标题】:state in useEffect second arguement Infinite loopstate in useEffect 第二个参数 无限循环
【发布时间】:2021-03-11 12:18:19
【问题描述】:

我有一小段代码,我想我做错了

const [orders, setOrders] = useState([])

useEffect(() => {
  fetch('/getOrders',{
      headers:{
       "Content-Type":"application/json",
       "Authorization": "Bearer "+localStorage.getItem("jwt")

      }
  }).then(res=>res.json())
  .then(orderList=>{
      setOrders(orderList)
      //console.log("myAdmin",orderList)

    
  }).catch(err=>{
      console.log("Error in Catch",err)
  })
  }, [orders])

这里数据会自行超时更新,我希望每次获取数据与现有状态不同时更新我的​​状态,但无论数据是否不同,状态都会不断更新,使组件无限重新渲染.有解决办法吗?

【问题讨论】:

  • 我不明白orders 是如何依赖的,但基本上任何时候效果都会无条件地更新其依赖数组中的值,它会导致渲染循环。所以基本上你想在每次渲染时获取数据,并且只有当它不同时才更新本地状态?
  • @DrewReese 是的,这就是我想要做的。

标签: reactjs mongodb react-hooks fetch-api mern


【解决方案1】:

问题

任何时候效果无条件地更新其依赖数组中的值,都会导致渲染循环。

useEffect(() => {
  fetch('/getOrders', { ... })
    .then(res=>res.json())
    .then(orderList=>{
      setOrders(orderList); // <-- updates state, triggers rerender
    })
    .catch(err=>{
      ...
    });
}, [orders]); // <-- updated state triggers effect callback

可能的解决方案

您似乎希望在每次组件呈现时获取并在成功响应(200 OK)后检查orders 数组是否实际上不同。如果是则更新状态,否则忽略更新。

  1. 移除依赖数组,以便在每次渲染组件时调用 useEffect 挂钩回调。
  2. 在访问响应 JSON 数据之前检查 fetch 请求响应是否为 ok。
  3. 对照状态检查order 响应数据。如果数组的长度不同,请更新状态,否则您需要逐个元素检查以确定数组是否不同。 *

更新效果挂钩

const [orders, setOrders] = useState([])

useEffect(() => {
  fetch("/getOrders", {
    headers: {
      "Content-Type": "application/json",
      Authorization: "Bearer " + localStorage.getItem("jwt")
    }
  })
    .then((res) => {
      if (!res.ok) {
        throw new Error("Fetch is not OK");
      }
      return res.json();
    })
    .then((orderList) => {
      if (orders.length !== orderList.length) {
        setOrders(orderList);
      } else {
        for (let i = 0; i < orders.length; i++) {
          // *** Your actual equality condition may be different, i.e. if they are objects ***
          if (orders[i] !== orderList[i]) {
            setOrders(orderList);
            return;
          }
        }
      }
    })
    .catch((err) => {
      console.error("Error in Catch", err);
    });
});

* 这是一个O(n) 检查每次,因此可以进行的优化可能是返回并存储一个“更新”哈希。如果哈希值与之前的请求相同,则跳过状态更新。这可能就像在后端为更新生成一个新的 GUID 并将其与数据一起返回一样简单。

【讨论】:

    【解决方案2】:

    您的代码中的 [orders] 基本上意味着:每次订单更改时调用 useEffect 内部的内容,并且每次调用 useEffect 时,它都会再次更新订单...然后您将获得无限循环

      useEffect(() => {
         
      }, [orders])
    

    您应该将[orders] 更改为[]。

    res=&gt;res.json() 将为您的对象创建一个新的引用,更改您对对象的引用意味着它已更改,例如 [1,2,3] 如果您再次通过 [1,2,3] 它不会是同一个对象,即使它看起来相同的。 v=[1,2,3],你传递 v,然后 v[0]=-1,再次传递 v,它会被认为是相同的,因为它具有相同的引用。

    解决此问题的最佳方法是根据您的情况手动比较它们,当它们不一样时,您可以使用 [...orders] 之类的东西,这将创建新的引用并再次调用 useEffect。

    【讨论】:

    • 但是哪里不会比较use Effect中的数据,还是会导致无限循环?假设我在第二次争论中下订单?
    • 不,你不能,使用效果不是问题,最坏的情况是每1分钟使用计时器或其他东西来检查
    • 是的,这至少有助于避免无限循环
    【解决方案3】:

    尝试使用 prevState 参数设置状态,因此您不必包含任何依赖项。

    setOrders((prevState) => ({
       ...prevState, orderList
    }))
    

    【讨论】:

      猜你喜欢
      • 2020-02-22
      • 2021-01-22
      • 2021-01-31
      • 2020-04-14
      • 2021-04-02
      • 1970-01-01
      • 1970-01-01
      • 2021-02-15
      相关资源
      最近更新 更多