是否可以通过使用 HOC(高阶组件)在类组件中使用 React Hooks?
Posted
技术标签:
【中文标题】是否可以通过使用 HOC(高阶组件)在类组件中使用 React Hooks?【英文标题】:Is it possible to use React Hooks in class component by using HOC(Higher Order Component)? 【发布时间】:2022-01-19 05:22:33 【问题描述】:可以在类组件中使用功能组件吗?我将调用从类组件中的功能组件中提取的函数。但它给出了如下错误。
未处理的拒绝(错误):无效的挂钩调用。钩子只能在函数组件的主体内部调用。这可能是由于以下原因之一
所以我尝试在功能组件中调用它,但是即使在功能组件中,我也遇到了与在类组件中调用它时相同的错误。
功能组件
import React, useEffect from 'react';
import UseWalletProvider, useWallet from 'use-wallet';
import providers from 'ethers';
export function App()
useEffect(() =>
async function GetBlockId()
const wallet = useWallet();
console.log(wallet); // =====> This is not displaying.
const ethereum, connect = wallet;
const ethersProvider = new providers.Web3Provider(ethereum);
const blockNumber = await ethersProvider.getTransaction(hash);
console.log(blockNumber);
;
GetBlockId()
, []);
return <div>
<h1>wallet</h1>
</div>
类组件
import React, Component from 'react'
import GetBlockId from './util'; // =====>> I hope to get result from here.
import hash from './hash'
export default class App extends Component
constructor(props)
super(props)
componentDidMount(): void
const blockNumber: any = GetBlockId(hash);
console.log(blockNumber);
render()
return (
<div>
<h1>test</h1>
</div>
)
util.tsx
import React, useEffect from 'react';
import UseWalletProvider, useWallet from 'use-wallet';
import providers from 'ethers';
// import Container from './styles';
export function GetBlockId()
useEffect(() =>
async function GetBlockId()
const wallet = useWallet();
const ethereum, connect = wallet;
const ethersProvider = new providers.Web3Provider(ethereum);
const blockNumber = await ethersProvider.getTransaction(hash);
return blockNumber;
;
GetBlockId()
, []);
所以最后我希望在类组件中使用“use-wallet”包。那可能吗?如果是,如何在类组件中使用 useWallet 钩子?
【问题讨论】:
将问题重命名为:如何使用组件将在反应功能组件中更新。即您需要使用组件将使用您尝试使用的任何钩子进行更新。而且好像反应不是很像。 看起来你对 React 和 hooks 的工作方式有一个根本性的误解。我建议你回去阅读文档。 reactjs.org/docs/hooks-rules.html 我回应 @Benjamin 评论。从文档中可以清楚地看出,OP 的要求是被禁止的。 【参考方案1】:React hooks 只兼容 React 函数组件,根本不能在类组件中使用。您第一次尝试的问题是您试图在回调中调用 React 挂钩,这违反了挂钩规则之一。
Rules of Hooks
仅在顶层调用 Hooks
不要在循环、条件或嵌套函数中调用 Hooks。 相反,总是在你的 React 函数的顶层使用 Hooks, 在任何提前返回之前。通过遵循此规则,您可以确保 每次渲染组件时,都会以相同的顺序调用挂钩。 这就是让 React 正确保存 Hooks 状态的原因 在多个 useState 和 useEffect 调用之间。 (如果你好奇, 我们将在下面深入解释这一点。)
仅从 React 函数调用 Hooks
不要从常规 javascript 函数中调用 Hooks。相反,您可以:
✅ 从 React 函数组件调用 Hooks。 ✅ 从自定义 Hooks 调用 Hooks(我们将在下一页了解它们)。通过遵循此规则,您可以确保所有有状态的逻辑在一个 组件从其源代码中清晰可见。
您的代码在传递给useEffect
挂钩的回调函数中调用useWallet
。请注意,这与自定义 Hook 调用另一个 Hook 不同。
将useWallet
挂钩调用移出到函数组件主体中。这将关闭渲染范围中的wallet
值,并且将在useEffect
挂钩回调中可用/可访问。我假设您仍然只希望/需要在组件安装时运行一次 useEffect
挂钩,所以我将不理会这方面。
import React, useEffect from 'react';
import UseWalletProvider, useWallet from 'use-wallet';
import providers from 'ethers';
export function App()
const wallet = useWallet();
useEffect(() =>
console.log(wallet);
const ethereum, connect = wallet;
async function GetBlockId()
const ethersProvider = new providers.Web3Provider(ethereum);
const blockNumber = await ethersProvider.getTransaction(hash);
console.log(blockNumber);
;
GetBlockId();
, []);
return (
<div>
<h1>wallet</h1>
</div>
);
更新
要将useWallet
钩子与类组件一起使用,我建议创建一个可以使用它并将wallet
值作为道具传递的高阶组件。
例子:
const withWallet = Component => props =>
const wallet = useWallet();
return <Component ...props wallet=wallet />;
;
装饰类组件并通过this.props.wallet
访问
class App extends Component
constructor(props)
super(props)
componentDidMount(): void
const ethereum, connect = this.props.wallet;
...
render()
return (
...
);
export default withWallet(App);
【讨论】:
感谢您的友好回答。好吧,我的最终目的是希望从这里得到结果。 =>const wallet = useWallet()
。我希望在类组件中使用这个wallet
。那可能吗?我编写了功能组件示例只是为了测试。我需要使用类组件。我想知道如何在类组件中使用useWallet()
。
@SatelBill 你不能在类组件中使用 React 钩子,但你可以创建一个 withWallet
高阶组件,它可以使用钩子并将 wallet
值作为道具传递给你的类零件。如果这听起来对您有用并且您感兴趣,我可以更新我的答案。
如果您可以使用 HOC 重新发布您的答案,我将不胜感激。谢谢。
@SatelBill 当然可以。答案已更新。【参考方案2】:
你不能在类组件中调用 react hook。
根据 ReactJS Doc 可以组合功能。
你不能在类组件中使用 Hooks,但你绝对可以将类和函数组件与 Hooks 混合在一个树中。组件是使用 Hooks 的类还是函数是该组件的实现细节。从长远来看,我们希望 Hooks 成为人们编写 React 组件的主要方式。
【讨论】:
【参考方案3】:GetBlockId 不是 React 函数式组件。没有返回方法;因此它会抛出一个错误,说你不能在非功能组件中使用钩子。将此函数更改为功能组件(通过返回 JSX 组件),它应该可以工作。
请注意,您的 getBlockId 函数是递归的并且会失败。
根据文档。在您的类组件(父组件)中。您将需要使用 UseWalletProvider 并在您的功能组件中使用钩子。 这是一个示例(未经测试),希望它能让您顺利上路。
import React, useState from 'react';
import useWallet, UseWalletProvider from 'use-wallet';
import ethers from 'ethers';
import hash from './hash'
function App()
const wallet = useWallet()
const blockNumber = wallet.getBlockNumber()
const [blockId, setBlockId] = useState('')
useEffect(()=>
const getBlockId = async() =>
const ethereum, connect = wallet;
const ethersProvider = new ethers.providers.Web3Provider(ethereum);
return await ethersProvider.getTransaction(hash);
setBlockId(getBlockId());
,[]);
//Note that now blockId contains the blockId that you get.
//You can use it with child components etc.
return (
<div>
<p>blockId</p>
</div>
);
function Index()
return (
<UseWalletProvider
chainId=1
connectors=
// This is how connectors get configured
portis: dAppId: 'my-dapp-id-123-xyz' ,
>
<App />
</UseWalletProvider>
);
【讨论】:
【参考方案4】:试试下面的代码,你最好不要在函数组件中使用useXXX,
export function App()
const wallet = useWallet();
const getBlockId = useCallback(() =>
console.log(wallet);
const ethereum, connect = wallet;
const ethersProvider = new providers.Web3Provider(ethereum);
const blockNumber = await ethersProvider.getTransaction(hash);
console.log(blockNumber);
, [wallet]);
useEffect(() =>
getBlockId()
, []);
return <div>
<h1>wallet</h1>
</div>
【讨论】:
以上是关于是否可以通过使用 HOC(高阶组件)在类组件中使用 React Hooks?的主要内容,如果未能解决你的问题,请参考以下文章
[react] 使用高阶组件(HOC)实现一个loading组件
高阶函数HOF和高阶组件HOC(Higher Order Func/Comp)