【问题标题】:Function that updates a useState hook when called in jsx it is causing an infinite loop在 jsx 中调用时更新 useState 钩子的函数会导致无限循环
【发布时间】:2022-08-02 19:29:13
【问题描述】:

我有一个获取数据并更新 useState 钩子的函数,但是当我在 jsx 中调用该函数时,它会导致一个无限循环,我曾尝试在 jsx 中放置一个条件,然后再调用该函数以避免无限循环,但随后该函数不会\不能正常工作。下面是我的代码

我的功能

const fetchDataFnc = (booking) => {
  const fleetId = booking.booking_bids_fleet_id
  const bookingId = booking.booking_id
  console.log(\"fleetId\" ,fleetId)
  if(booking.booking_bids_fleet_id){
    firebase.database().ref(\'fleets/\' + 
      fleetId[0]).child(\"booking_bids\").child(bookingId).on(\'value\', (snapshot) => {
      console.log(\"fleet snap\",snapshot.val())
        setFirstPrice(snapshot.val().price[0])
        setAllPrices(snapshot.val().price)
        console.log(\"all the prices\", snapshot.val().price)
        console.log(\"fleet collect\", snapshot.val());
    });
  }
  if(booking.booking_bids_fleet_id){
    firebase.database().ref(\'booking/\' + bookingId).child(\"booking_bids_prices\").set({
      firstPrice
    });
  }
}

我的

{selectedBooking.length > 0 ? selectedBooking.map((booking)=>{
                // showFirstPrice(booking)
                if(Math.random() > 0.5) {
                  fetchDataFnc(booking)
                }
                return( 
                  <>
                  {firstSel &&
                    <SelectedBooking
                      booking_ref={booking.booking_ref}
                      firstPrice={firstPrice}
                      booking={booking}
                      handleSettle={handleSettle}
                      setSettleAmount={setSettleAmount}
                      settleAmount={settleAmount}
                      allPrices={allPrices}
                      handleAccept={handleAccept}
                    />
                  } 
                  </>
                )
              }):
                <></> 
              }
  • 你能完成你的代码,并添加 useState 声明以提供清晰...
  • 您应该在渲染阶段之外调用您的函数。尝试在 useEffect 中调用它,例如:作为选择预订的副作用,如果这有意义:) 这是反应文档的链接

标签: javascript reactjs


【解决方案1】:

不要调用更新状态的函数在每次渲染上.更新状态会触发重新渲染,因此组件将无休止地重新渲染并重新调用该函数。

你是大概寻找useEffect 钩子。例如,当组件调用该函数一次第一的加载然后不再加载,将一个空的依赖数组传递给钩子:

useEffect(() => {
  fetchDataFnc(booking);
}, []);

虽然在这种情况下 booking 是一个依赖项。要在依赖项更改时重新调用该函数,请将其添加到依赖项数组中:

useEffect(() => {
  fetchDataFnc(booking);
}, [booking]);

编辑:Linters 可能还需要您将函数本身添加到依赖数组中:

useEffect(() => {
  fetchDataFnc(booking);
}, [booking, fetchDataFnc]);

这可能会导致下一步使用useCallback 钩子定义函数,因此不会在每次渲染时重新创建函数,而是仅在它的依赖改变:

const fetchDataFnc = useCallback((booking) => {
  //...
}, [/* dependencies */]);

linter 可以帮助您识别要在其中使用的依赖项,但实际上它与 useEffect 的概念相同。任何可以改变的东西,当它改变时,应该更新函数以使用它的新值将在依赖数组中。

(这种做法有时需要重新思考我们如何构建函数,从而更积极地思考依赖关系和闭包,以及更清洁、更稳定的 JavaScript 代码。)


顺便说一句,你也可能不想做这一切在 JSX 内部.组件的逻辑,例如状态和效果以及辅助函数,都发生在 JSX 之前。 JSX 是组件返回的结果,它本身就是一个与其他函数一样的函数。

【讨论】:

  • 根据 lint 规则 AFAIK,他还需要添加 fetchDataFnc 作为依赖项,这可能需要 useCallback
  • @GiorgiMoniava:如果它用useCallback 定义,然后是的。否则,如果它在每个渲染上都按原样定义,那么他们就不想将它添加为依赖项,因为它在每个渲染上都是“不同的”。但是,是的,使用useCallback 肯定是一个很好的下一步。
  • 是的,我的意思是,linter 无论如何都会抱怨fetchDataFnc。并且直接将其作为依赖项通常不是出路,因为它会被重新创建,并且每次都可能触发。
  • 我无法调用 useEffect 上的函数,只是因为它说未定义依赖项,钩子是否进入函数?我需要将整个函数转换为自定义钩子吗?
  • @vnashthebioprophet:它是否告诉您 fetchDataFnc 本身需要添加到依赖数组中?如果是这样,请添加它。您还可以采取下一步并使用 useCallback 挂钩来定义 fetchDataFnc 及其自己的依赖数组,因此不会在每次渲染时重新定义它。
猜你喜欢
  • 2020-03-25
  • 1970-01-01
  • 2020-02-26
  • 2021-10-05
  • 1970-01-01
  • 2021-04-10
  • 1970-01-01
  • 2011-08-23
  • 1970-01-01
相关资源
最近更新 更多