Reactjs 反应挂钩(useEffect)无限循环澄清

Reactjs 反应挂钩(useEffect)无限循环澄清,reactjs,react-hooks,use-effect,Reactjs,React Hooks,Use Effect,这个问题与我先前的问题有关。我已经写了两个自定义钩子。第一个是useFetchAccounts,其任务是获取有关用户帐户的一些数据,如下所示: // a fake fetch for the sake of the example function my_fetch(f, delay) { setTimeout(f, delay) } function useFetchAccounts() { const [data, setData] = useState({accounts: [

这个问题与我先前的问题有关。我已经写了两个自定义钩子。第一个是
useFetchAccounts
,其任务是获取有关用户帐户的一些数据,如下所示:

// a fake fetch for the sake of the example
function my_fetch(f, delay) {
  setTimeout(f, delay)
}

function useFetchAccounts() {

  const [data, setData] = useState({accounts: [], loaded: false})

  useEffect(() => {
    my_fetch(() => {setData({accounts: [{id:1},{id:2}], loaded: true})}, 3000)
  }, [])

  return data
}
function useFetchBalanceWithIDs(account_ids, accounts_loaded) {

  const [balances, setBalances] = useState(null)

  useEffect(() => {
    if (!accounts_loaded) return; // only fetch if accounts are loaded
    my_fetch(() => {
      setBalances(account_ids.map(id => 42+id))
    }, 3000)
  }, [account_ids, accounts_loaded])

  return balances
}
function App() {

  const account_data = useFetchAccounts()

  const accounts = account_data.accounts

  const balance = useFetchBalanceWithAccounts(accounts, account_data.loaded)

  console.log(balance)

  return null
}
这个钩子没有什么特别之处,只是获取帐户的ID

现在我有了另一个钩子,
useFetchBalancesWithIDs(account\u id,accounts\u loaded)
,它的意思是获取上一步的id,并在账户已加载的情况下获取这些账户的余额。看起来是这样的:

// a fake fetch for the sake of the example
function my_fetch(f, delay) {
  setTimeout(f, delay)
}

function useFetchAccounts() {

  const [data, setData] = useState({accounts: [], loaded: false})

  useEffect(() => {
    my_fetch(() => {setData({accounts: [{id:1},{id:2}], loaded: true})}, 3000)
  }, [])

  return data
}
function useFetchBalanceWithIDs(account_ids, accounts_loaded) {

  const [balances, setBalances] = useState(null)

  useEffect(() => {
    if (!accounts_loaded) return; // only fetch if accounts are loaded
    my_fetch(() => {
      setBalances(account_ids.map(id => 42+id))
    }, 3000)
  }, [account_ids, accounts_loaded])

  return balances
}
function App() {

  const account_data = useFetchAccounts()

  const accounts = account_data.accounts

  const balance = useFetchBalanceWithAccounts(accounts, account_data.loaded)

  console.log(balance)

  return null
}
如您所见,如果加载的
帐户\u
为false,它将不会执行提取。我将它们结合在一起使用,如下所示:

function App() {

  const account_data = useFetchAccounts()

  const accounts = account_data.accounts
  const account_ids = accounts.map(account => account.id) // extract ids

  const balance = useFetchBalanceWithIDs(account_ids, account_data.loaded)

  console.log(balance)

  return null
}
不幸的是,这会导致无限循环。工作原理是将
useFetchBalancesWithIDs
更改为:

function useFetchBalanceWithAccounts(accounts, accounts_loaded) {

  const [balances, setBalances] = useState(null)

  useEffect(() => {
    if (!accounts_loaded) return; // only fetch if accounts are loaded
    my_fetch(() => {
      setBalances(accounts.map(account => 42+account.id))
    }, 3000)
  }, [accounts, accounts_loaded])

  return balances
}
它在中执行ID提取。我是这样使用它的:

// a fake fetch for the sake of the example
function my_fetch(f, delay) {
  setTimeout(f, delay)
}

function useFetchAccounts() {

  const [data, setData] = useState({accounts: [], loaded: false})

  useEffect(() => {
    my_fetch(() => {setData({accounts: [{id:1},{id:2}], loaded: true})}, 3000)
  }, [])

  return data
}
function useFetchBalanceWithIDs(account_ids, accounts_loaded) {

  const [balances, setBalances] = useState(null)

  useEffect(() => {
    if (!accounts_loaded) return; // only fetch if accounts are loaded
    my_fetch(() => {
      setBalances(account_ids.map(id => 42+id))
    }, 3000)
  }, [account_ids, accounts_loaded])

  return balances
}
function App() {

  const account_data = useFetchAccounts()

  const accounts = account_data.accounts

  const balance = useFetchBalanceWithAccounts(accounts, account_data.loaded)

  console.log(balance)

  return null
}

它运行得很好。因此,问题似乎与从应用程序组件中提取ID有关,这似乎一直在触发
useFetchBalanceWithIDs
,即使
帐户ID
没有改变值。有人能解释一下这种行为吗?我可以使用
useFetchBalanceWithAccounts
,但我想了解为什么
useFetchBalanceWithIDs
不起作用。谢谢大家!

问题是您正在使用map函数获取帐户ID数组。React使用Object.is确定依赖项数组中的值在每个渲染周期中是否已更改。map函数返回一个新数组,因此即使数组中的值相同,比较检查也会计算为false,并运行效果。

引用等式由
useffect
使用,这意味着
[1,2,3]
将不等于
[1,2,3]

const data = [{id:1}];
data.map(d=>d.id)===data.map(d=>d.id);//is false
防止id的数组更改引用的一种方法是在应用程序中结合useState和useEffect:

function App() {
  //store account id's in app state
  const [accountIds, setAccountIds] = useState([]);
  const account_data = useFetchAccounts();
  const accounts = account_data.accounts;
  //only if accounts change re set the id's
  useEffect(() => {
    setAccountIds(accounts.map(a => a.id));
  }, [accounts]);
  const balance = useFetchBalanceWithAccounts(
    accountIds,
    account_data.loaded
  );
  console.log(balance);
  return null;
}

您可以使用
data.accounts.map(x=>x.id)
将帐户id传递给
useFetchBalancesWithIDs
?如果是这种情况,则即使数据没有更改id,id也会更改,因为
[1,2,3]
不等于
[1,2,3]
(参考等式)。您可以对提取ID进行记忆。具有