在 useEffect 内部的侦听器中更新状态

Aps*_*wak 7 javascript listener reactjs react-native

我有一个钩子,称为useQueryEvents1) 为用户获取所有过去的交易,2) 侦听网络的传入/传出交易。在这两种情况下,事务都被传递到一个函数中addActionToActivity,该函数只是将其附加到活动数组并在 key 下的上下文状态中更新它activity

我无法让活动正确同步。每当状态更新时,它都没有最后一笔交易,因为它总是落后一步。如果我添加activity依赖项,它会起作用,但随后会启动一个新的侦听器(由于使用新activity值再次调用整个函数),这会导致无限循环,该循环不断切换状态。

function useQueryEvents() {
  const { state: { connectedNetwork, selectedWallet, activity },
  } = useContext(LocalContext);

  useEffect(() => {
    async function bootstrapQueryEvents() {
      // First get all the past transactions
      const transactions = await getAllPastTransactions();
      const contract = await getContract();

      // Now save them to context state via addActionToActivity
      await addActionToActivity(transactions, activity);

      // Now that all the past transactions have been saved
      // listen to all incoming/outgoing transactions and
      // save to context state via addActionToActivity
      contract.on('Transfer', async (from, to, amount, event) => {
        console.log(`${from} sent ${ethers.utils.formatEther(amount)} to ${to}`);
        const transaction = await formatEventToTransaction(event);
        await addActionToActivity(transaction, activity);
      });
    }

    bootstrapQueryEvents();
  }, [selectedAsset, connectedNetwork, selectedWallet]); // <- I've tried adding `activity` here
}
Run Code Online (Sandbox Code Playgroud)

任何想法如何activity启动侦听器的新实例的情况下访问侦听器内的更新值的同时更新状态?或者也许我可以完全采用不同的方法?

提前致谢

Dáv*_*nár 2

我假设您想向对象添加新事务activity。我假设您还以新状态(具有新事务的当前活动)调用setState某个地方。addActionToActivity您需要访问最新的活动,但在您的关闭中,这不是最新的活动。

使用setState并向其传递一个函数,该函数将接收当前状态:

setState(prevState => {
  // add transactions to prevState.activity 
  return { ...prevState, activity: {...prevState.activity, transactions: ... }};
});
Run Code Online (Sandbox Code Playgroud)

所以,在你的例子中:

function useQueryEvents() {
  const { state: { connectedNetwork, selectedWallet },
  } = useContext(LocalContext);

  useEffect(() => {
    async function bootstrapQueryEvents() {
      // First get all the past transactions
      const transactions = await getAllPastTransactions();
      const contract = await getContract();

      // Now save them to context state via addActionToActivity
      await addActionToActivity(transactions);

      // Now that all the past transactions have been saved
      // listen to all incoming/outgoing transactions and
      // save to context state via addActionToActivity
      contract.on('Transfer', async (from, to, amount, event) => {
        console.log(`${from} sent ${ethers.utils.formatEther(amount)} to ${to}`);
        const transaction = await formatEventToTransaction(event);
        await addActionToActivity(transaction);
      });
    }

    bootstrapQueryEvents();
  }, [selectedAsset, connectedNetwork, selectedWallet]); // <- I've tried adding `activity` here
}
...
const addActionToActivity = (transactions) => {
  ...
  setState(prevState => {
  // add transactions to prevState.activity 
  return { ...prevState, activity: {...prevState.activity, transactions: ... }};
});
}
Run Code Online (Sandbox Code Playgroud)