useEffect 依赖数组的问题

Posted

技术标签:

【中文标题】useEffect 依赖数组的问题【英文标题】:Issue with useEffect dependency array 【发布时间】:2021-10-11 17:44:49 【问题描述】:

我的项目正在使用 useState 和 useEffect 挂钩从 API 获取数据。该请求在我的本地主机上正常工作和呈现,但我收到以下警告:

React Hook useEffect 缺少一个依赖项:'fetchData'。要么包含它,要么移除依赖数组。

警告阻止我部署我的项目。我已经尝试将“fetchData”添加到数组以及完全删除数组。两者都会导致错误。

将 'fetchData' 添加到数组会导致另一个警告:

'fetchData' 函数使 useEffect Hook(第 31 行)的依赖关系在每次渲染时都发生变化。将它移到 useEffect 回调中。或者,将 'fetchData' 的定义包装在它自己的 useCallback() Hook 中。

删除数组会导致此控制台错误:

CORS 策略阻止了从源“http://localhost:3000”获取的访问权限:请求的资源上不存在“Access-Control-Allow-Origin”标头。如果不透明的响应满足您的需求,请将请求的模式设置为“no-cors”以获取禁用 CORS 的资源。

我只需要在加载时渲染一次状态。这是我的代码:

export function Product(Inventory_ID, Cost) 
  const [ data, setData ] = useState("");
  const [ centers, setCenters ] = useState([]);

  const fetchData = async () => 
    try 
      const response = await fetch(`$API_ENDPOINT$Inventory_ID`, REQUEST_OPTIONS);
      const data = await response.json();
      setData(data);

      const centers = await data.fulfillable_quantity_by_fulfillment_center;
      setCenters(centers);
     catch (e) 
      console.error(e);
    
  

  useEffect(() => 
    fetchData();
  , []);

  // Currency formatter
  const formatter = new Intl.NumberFormat('en-US', 
    style: 'currency',
    currency: 'USD',
    maximumFractionDigits: 0,
  )

  return (
    <div className="card">
      <h2>data.name</h2>
      <h3>Total Onhand Quantity</h3>
      <p>data.total_onhand_quantity</p>
      <h3>Total Onhand Value</h3>
      <p>formatter.format(data.total_onhand_quantity * Cost)</p>
      <h3>Quantity by Fulfillment Center</h3>
      centers.map((center) => 
        return (
          <div>
          <h4 key=center.name>center.name</h4>
          <p key=center.onhand_quantity>`Onhand Quantity: $center.onhand_quantity`</p>
          <p key=center.awaiting_quantity>`Awaiting Quantity: $center.awaiting_quantity`</p>
          </div>

        );
      )
      <div>

      </div>
    </div>
  )

知道我在哪里出错以及如何解决吗?

非常感谢。

【问题讨论】:

【参考方案1】:

不确定你之前做了什么来得到这些错误,但你现在的代码看起来是正确的。您现在的问题是,无论 API_ENDPOINT 是什么都没有启用 CORS。这意味着服务器没有将您的域列入“您可以发出请求”的白名单,因此当它访问您的浏览器时,您的浏览器会通过使您的 fetch 调用无效来“保护”您。

为了解决这个问题,您需要在 API 服务器上启用 CORS,并且需要将运行 UI 的域列入白名单。或者您可以创建自己的 API 并从那里提取数据,然后您可以从他们的 API 服务器端获取数据,这样您的浏览器就不会 CORS 拒绝您。

旁注,我不确定我是否正确,但这可能会给您带来问题:

setData(data);
const centers = await data.fulfillable_quantity_by_fulfillment_center;
setCenters(centers);

或者至少它只是非常未优化。 React 将设置状态,重新渲染组件,同时等待第二次 fetch 调用完成,然后再次设置状态并重新渲染。

改为进行所有 fetch 调用,然后设置所有状态,以便 react 可以通过批量更新渲染组件。

【讨论】:

感谢您的回复。我不控制 API 服务器,但我会寻求支持。我仍然不明白为什么会有这么多请求发生,每个唯一的 Inventory_ID 应该只有一个请求,我的应用程序有六个。知道如何将请求限制为仅加载一次吗? 您还可以创建自己的 API 服务器端并在那里获取数据,这样您就不会使 CORS 失效,CORS 只是一个浏览器策略,所以如果您从他们的 API 服务器端获取然后获取从您自己的 API 它将起作用。此外,由于数据返回后状态更新,您的组件一直在重新渲染。您应该在一个地方进行所有状态更新,而不是在每个数据返回之后,您还应该使用useEffect 返回数组来保持状态,即useEffect(() =&gt; , [inventoryId]),以防止它一遍又一遍地呈现。 谢谢。我是一名新开发人员,因此创建自己的 API 服务器端远远超出了我的能力。任何机会您都可以向我展示您的意思是“此外,一旦数据返回,由于状态更新,您的组件一直在重新渲染。您应该在一个地方完成所有状态更新,”我将如何在我的代码中完成此操作?此外,我尝试在 useEffect 依赖数组中包含 prop 'Inventory_ID',但收到关于它缺少依赖项 'fetchData' 的相同警告。我知道我需要更好地了解状态和挂钩的工作原理,因此感谢您的帮助! 每次调用setSomething都会触发组件的重新渲染,所以如果你等待数据,然后设置它,然后等待数据,然后设置它,你在重复重新渲染组件并在每次渲染时触发useEffect。取而代之的是获取您想要的所有数据,然后设置所有状态。除此之外,错误告诉您将fetchData 函数移动到useEffect 中,所以这样做。此外,fetchData 不应添加到数组中,datacenters 应该。 谢谢!我删除了centers 以简化问题,然后将我的fetchData 函数移到useEffect 中。依赖数组调用Inventory_ID(就像您最初建议的那样)而不是data,所以我将Inventory_ID 添加到数组中,它现在可以正常工作而没有任何警告。现在我只需要返回并弄清楚如何在不触发重新渲染的情况下添加回centers。我遇到的问题是 centers 是一个数组,所以我不确定如何在同一个 setState 中处理它

以上是关于useEffect 依赖数组的问题的主要内容,如果未能解决你的问题,请参考以下文章

为啥在组件加载时不调用 useEffect(()=...,[]) ?

为啥 useEffect 之外的函数被调用,而没有依赖数组的 useEffect 内部的函数却没有?

在 useEffect 中,不提供依赖数组和空数组有啥区别?

useEffect 依赖数组

确定哪个依赖数组变量导致 useEffect 钩子触发

react组件初始化接口请求有多个异步依赖参数