Search code examples
reactjsreact-hooksnext.jsdecentralized-applications

Is there a way to write a custom react hook that can injected into a component?


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


Solution

  • 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
            }
        }