我在使用自定义反应钩子方面遇到了一些困难。
我有 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
。
等待另一个钩子然后在第二个钩子中使用该结果的方法是什么?
谢谢!
功能组件是一个同步函数,并且作为组件具有生命周期钩子。异步调用是应该由钩子处理的副作用,而不是通过在函数体中传递 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,
}
)
创建一个钩子然后只从其中返回一个函数是一个坏主意。除此之外,这也是一个承诺。相反,从您的钩子中返回一个对象。然后在您的来电者中等待。
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 组件区分开来
您需要在自定义钩子中使用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;
}
在其他钩子中,检查钱包是否为空并进行相应处理。