苦苦挣扎于异步自定义反应挂钩。我如何等待一个钩子的结果以在另一个钩子中使用?

问题描述 投票:0回答:3

我在使用自定义反应钩子方面遇到了一些困难。

我有 2 个定制挂钩。

第一个钩子用于获取 ID,第二个钩子用于获取具有先前获取的 ID 的配置文件。它取决于该 ID,所以我需要等待这个承诺。

我有以下自定义挂钩:

export const UseMetamask = () => {

    //Todo: Create check if metamask is in browser, otherwise throw error
    const fetchWallet = async (): Promise<string | null> => {
        try {
            const accounts: string[] = await window.ethereum.request(
                {
                    method: 'eth_requestAccounts'
                },
            );

            return accounts[0];

        } catch(e) {
            console.error(e);

            return null;
        }
    }
    
    return fetchWallet();
}

然后在我的第二个钩子中我有:

const wallet = UseMetamask();

然后在反应查询调用中使用,例如:

useQuery(
    ['user', wallet],
    () => getUserByWallet(wallet),

现在它在钱包上抱怨它是

Promise<string | null>
,这当然不适合
getUserByWallet

等待另一个钩子然后在第二个钩子中使用该结果的方法是什么?

谢谢!

javascript reactjs react-hooks promise react-query
3个回答
3
投票

功能组件是一个同步函数,并且作为组件具有生命周期钩子。异步调用是应该由钩子处理的副作用,而不是通过在函数体中传递 Promise 来处理。请参阅此SO答案

选项 1 - 使用

useEffect
useState
:

将 api 调用包装在

useEffect
中,并在 api 调用成功时设置
wallet
状态。从钩子返回
wallet
状态:

export const useMetamask = () => {
  const [wallet, setWallet] = useState<string | null>(null);
  
  useEffect(() => {
    const fetchWallet = async(): Promise<string | null> => {
      try {
        const accounts: string[] = await window.ethereum.request({
          method: 'eth_requestAccounts'
        });

        setWallet(accounts[0]);

      } catch (e) {
        console.error(e);

        return null;
      }
    }
    
    fetchWallet();
  }, []);

  return wallet;
}

用途:

从挂钩中取出

wallet
。这将是
null
或实际值:

const wallet = useMetamask();

enable
wallet
实际存在时调用(不是
null
)。我们将使用
enable
选项(请参阅相关查询),根据
wallet
的值启用/禁用查询:

useQuery(
  ['user', wallet],
  () => getUserByWallet(wallet),
  {
  // The query will not execute until the wallet exists
  enabled: !!wallet,
  }
)

选项 2 - 使用两个

useQuery
挂钩

由于您已经使用了

useQuery
,因此您需要编写一个自定义钩子。只需从另一个
wallet
电话中获取
useQuery

const wallet useQuery('wallet', fetchWallet);

useQuery(
  ['user', wallet],
  () => getUserByWallet(wallet),
  {
  // The query will not execute until the wallet exists
  enabled: !!wallet,
  }
)

0
投票

创建一个钩子然后只从其中返回一个函数是一个坏主意。除此之外,这也是一个承诺。相反,从您的钩子中返回一个对象。然后在您的来电者中等待。

export const useMetamask = () => {

    //Todo: Create check if metamask is in browser, otherwise throw error
    const fetchWallet = async (): Promise<string | null> => {
        try {
            const accounts: string[] = await window.ethereum.request(
                {
                    method: 'eth_requestAccounts'
                },
            );

            return accounts[0];

        } catch(e) {
            console.error(e);

            return null;
        }
    }
    
    return { fetchWallet };
}

然后在你的来电者中

const { fetchWallet } = useMetamask();
const wallet = await fetchWallet();

useQuery(
    ['user', wallet],
    () => getUserByWallet(wallet),

另外,请在钩子中使用小写字母“useSomething”,以将其与 UI 组件区分开来


0
投票

您需要在自定义钩子中使用useState。

// move fetchWallet function to utils and import it here for better code smells

export const useMetamask = () => {
    const [wallet, setWallet] = useState(null);
    // you do not want to fetch wallet everytime the component updates, You want to do it only once.
    useEffect(()=>{
        fetchWallet().then(wallet => setWallet(wallet)).catch(errorHandler);
    }, [])
    return wallet;
}

在其他钩子中,检查钱包是否为空并进行相应处理。

© www.soinside.com 2019 - 2024. All rights reserved.