0

I have a project that runs when using npm run dev which is next dev in the package.json file since we use the React framework Next.js. When I run npm run build or next build there are multiple errors surrounding React Hooks.

Example error in npm run build:

36:23  Error: React Hook "useEtherBalance" is called in function "connectClick" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter.  react-hooks/rules-of-hooks

From my current research into this issue, it seems that Higher-Order Components could be a solution to the problem the project faces. Essentially, I am looking to inject a custom hook into the components that make up the project.

File Structure:

  • Root Folder
    • .next
    • components
      • TopNavBar
        • TopNavLanding.jsx
      • Other Components...
    • contracts (Soldity Smart Contracts)
    • pages
      • api
      • hooks
      • _app.js
      • index.js
      • ambulance.js + more pages related to the application
    • public
    • styles

Current Code:

import React, { useEffect, useState } from 'react';
import Router from 'next/router';
import { Button } from 'reactstrap';
import styles from '../../styles/TopNavbar.module.css';
import '../../public/logo_P_1.png';
import MetaMaskOnboarding from '@metamask/onboarding';
import { useEtherBalance, useEthers } from '@usedapp/core';

export default function TopNavbar() {
    const [buttonText, setButtonText] = useState("Connect");
    const [buttonDisabled, setButtonDisabled] = useState(false);
    const [connected, setConnected] = useState(false);
    const { activateBrowserWallet, account } = useEthers();
    const balance = useEtherBalance(account);

    useEffect(() => {
        initialize();
    })

    const connectClick = async () => {
        if (buttonText === "Connect") {
            activateBrowserWallet();
            setConnected(true);
        } else if (buttonText === "Click here to install MetaMask!") {
            setButtonText("Onboarding in progress");
            setButtonDisabled(true);
            const forwarderOrigin = 'http://localhost:9010';
            // Creating a new MetaMask onboarding object
            const onboarding = new MetaMaskOnboarding({ forwarderOrigin });
            // Starts onboarding for our und user
            onboarding.startOnboarding();
        } else if (buttonText === "Sign In") {
            const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
            const accountNum = accounts[0];
            // TODO: Getting the Ether balance causes issues
            balance = useEtherBalance(accountNum);
        }
    }

    const initialize = () => {
        // Checking the ethereum binding on the window object to see if it's installed
        const isMetaMaskInstalled = () => {
            const { ethereum } = window;
            return (ethereum && ethereum.isMetaMask);
        }
        const MetaMaskClientCheck = () => {
            // If it isn't installed we ask the user to click to install it
            if (!isMetaMaskInstalled()) {
                setButtonText('Click here to install MetaMask!');
                setButtonDisabled(false);
            } else {
                // If it is installed we change our button text
                setButtonText('Sign In');
                setButtonDisabled(false);
            }
        };
        MetaMaskClientCheck();
    }

    return (
        <div className={styles.topNavbar}>
            <div className={styles.topbarWrapper}>
                <div>
                    <!-- Logo placeholder -->
                </div>
                <div className={styles.topbarRight}>
                    {(!!account && !!balance) ?
                        // <p className={styles.walletBalance}>Wallet Balance {formatUnits(balance.toString())}ETH</p> :
                        <Button className={styles.connectButton} onClick={() => Router.push('/home')}>Continue</Button> :
                        <Button disabled={buttonDisabled} className={styles.connectButton} onClick={() => connectClick()}>{buttonText}</Button>
                    }
                </div>
            </div>
        </div>
    )
}

Error Message enter image description here

Matt Blackert
  • 25
  • 1
  • 1
  • 5

1 Answers1

0

Remove call hook in connectClick function,

Remove it

balance = useEtherBalance(accountNum);

Currect function form:

const connectClick = async () => {
        if (buttonText === "Connect") {
            activateBrowserWallet();
            setConnected(true);
        } else if (buttonText === "Click here to install MetaMask!") {
            setButtonText("Onboarding in progress");
            setButtonDisabled(true);
            const forwarderOrigin = 'http://localhost:9010';
            // Creating a new MetaMask onboarding object
            const onboarding = new MetaMaskOnboarding({ forwarderOrigin });
            // Starts onboarding for our und user
            onboarding.startOnboarding();
        } else if (buttonText === "Sign In") {
            const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
            const accountNum = accounts[0];
            // TODO: Getting the Ether balance causes issues
        }
    }
Erfan HosseinPoor
  • 1,049
  • 7
  • 9
  • Hello Erfan, the issue is that balance is undefined. I am looking to fix other errors that are similar to this one and so removing the call hook destroys the functionality. I am wondering if I can put the call hook in a custom hook? – Matt Blackert Apr 18 '22 at 17:18
  • Hi Matt, you must change your functionality, the main rule of use hooks is: Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns. By following this rule, you ensure that Hooks are called in the same order each time a component renders. https://reactjs.org/docs/hooks-rules.html#:~:text=Don't%20call%20Hooks%20inside,each%20time%20a%20component%20renders. – Erfan HosseinPoor Apr 19 '22 at 03:54