<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: conormdowney</title>
    <description>The latest articles on DEV Community by conormdowney (@conormdowney).</description>
    <link>https://dev.to/conormdowney</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F619285%2Ff90f8ebc-25d2-4032-938d-4d0a21c9da3d.png</url>
      <title>DEV Community: conormdowney</title>
      <link>https://dev.to/conormdowney</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/conormdowney"/>
    <language>en</language>
    <item>
      <title>Invalid hook call.</title>
      <dc:creator>conormdowney</dc:creator>
      <pubDate>Thu, 22 Apr 2021 22:13:32 +0000</pubDate>
      <link>https://dev.to/conormdowney/invalid-hook-call-3lhp</link>
      <guid>https://dev.to/conormdowney/invalid-hook-call-3lhp</guid>
      <description>&lt;p&gt;Hi, &lt;/p&gt;

&lt;p&gt;Im pretty new to react and ive run into the Invalid hook call issue. Googling around i see the most common fix is for when there are two instances of react. When I run npm ls react I only see 1.&lt;/p&gt;

&lt;p&gt;The issue only arose for me after I added a Context to my app but I have no idea what the issue is.&lt;/p&gt;

&lt;p&gt;Im using a custom hook to do server calls. If they fail I want to show the errors in a modal. I have the Modal in my App component but it is not open until there are errors. Below is my code.&lt;/p&gt;

&lt;p&gt;My App.tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
    defaultTheme,
    Grid,
    Provider as ProviderV3,
} from "@adobe/react-spectrum";
import { FC, useState, useEffect, useContext } from "react";

import Toolbar from './components/Toolbar';
import OwnerSearch from './components/OwnerSearch/OwnerSearch';
import NewOwnerSearch from './components/OwnerSearch/NewOwnerSearch';
import GlobalContext, { GlobalContextProvider } from './api/GlobalContext';

import './App.scss';
import Modal from "./components/Modal";

// // Add this in node_modules/react-dom/index.js
// window.React1 = require('react');

// // Add this in your component file
// require('react-dom');
// window.React2 = require('react');
// console.log('Conor: ' + window.React1 === window.React2);

const App: FC = () =&amp;gt; {

    const ctx = useContext(GlobalContext)
    const [isModalOpen, setIsModalOpen] = useState(false);
    const [errors, setErrors] = useState(['']);

    let modal = (
        &amp;lt;Modal
            heading="Warning"
            content={&amp;lt;div&amp;gt;{ctx.errors.join(';')}&amp;lt;/div&amp;gt;}
            buttonList={
                [
                    { label: "OK", clickHandler: () =&amp;gt; { }, closesModal: true },
                    { label: "Cancel", clickHandler: () =&amp;gt; { alert("cancelled") }, closesModal: false }
                ]
            }
            isOpen={isModalOpen}
            setIsOpen={setIsModalOpen} /&amp;gt;
    );

    useEffect(() =&amp;gt; {
        if (ctx.errors.length &amp;gt; 0) {
            setIsModalOpen(true);
        }
    }, [ctx.errors]);

    //
    return (
        &amp;lt;GlobalContext.Provider value={{errors: errors, setErrors: setErrors}}&amp;gt;
            &amp;lt;ProviderV3 theme={defaultTheme}&amp;gt;
                &amp;lt;Toolbar&amp;gt;&amp;lt;/Toolbar&amp;gt;
                &amp;lt;Grid
                    margin='25px'
                    columns='50% 50%'
                    gap='10px'
                    maxWidth='100vw'&amp;gt;
                    &amp;lt;OwnerSearch /&amp;gt;
                    &amp;lt;NewOwnerSearch /&amp;gt;
                &amp;lt;/Grid&amp;gt;
            &amp;lt;/ProviderV3&amp;gt;
            {modal}
            &amp;lt;/GlobalContext.Provider&amp;gt;
    );
};

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;my component that uses my hook to get data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
    TextField,
    ProgressCircle,
    Form,
    Flex,
    Button
} from '@adobe/react-spectrum';
import '@spectrum-web-components/card/sp-card.js';
import { FC, useState, useEffect, useContext } from 'react';
import GlobalContext from '../../api/GlobalContext';
import useHttp from '../../hooks/useHttp';
import React from 'react';

import './OwnerSearch.scss';

declare global {
    namespace JSX {
        interface IntrinsicElements {
            'sp-card': React.DetailedHTMLProps&amp;lt;ModHTMLAttributes&amp;lt;HTMLElement&amp;gt;, HTMLElement&amp;gt;;
        }
    }
}

const NewOwnerSearch: FC = () =&amp;gt; { 
    const ctx = useContext(GlobalContext);
    const [owners, setOwners] = useState([]);
    const [searchText, setSearchText] = useState('msft');   

    const { isLoading, error, sendRequest: setOwnersData } = useHttp({url: 'http://liberate-api.com/api/ownership/' + searchText}, setOwners);

    const handleSubmit = (e: any /*JS Submit event*/) =&amp;gt; {
        e.preventDefault();
        setOwnersData();
    }

    useEffect(() =&amp;gt; 
    {
        setOwnersData();
    }, [setOwnersData]);

    if(error != '')
    {
        //ctx.addError(error);
        ctx.setErrors((prevErrors: string[]) =&amp;gt; 
        {
            //prevErrors.push(err.message)
            let newArray = prevErrors.map((er) =&amp;gt; {return er});
            newArray.push(error);
            return newArray;
        }
    );
    }

    const numberWithCommas = (x: number) =&amp;gt; {
        return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    }

    return (
        &amp;lt;sp-card
            heading='Owner Data'
            subheading='Search Public Owner Data'&amp;gt;
            &amp;lt;div slot='footer'&amp;gt;
                &amp;lt;Flex
                    direction='column'&amp;gt;
                    &amp;lt;Form onSubmit={(e) =&amp;gt; handleSubmit(e)}&amp;gt;
                        &amp;lt;Flex
                            direction='row'&amp;gt;
                            &amp;lt;TextField
                                marginEnd='15px'
                                placeholder='Search Owners'
                                onChange={(a) =&amp;gt; setSearchText(a)} 
                                value={searchText}
                                /&amp;gt;
                            &amp;lt;Button type='submit' variant='cta'&amp;gt;
                                Search Data
                            &amp;lt;/Button&amp;gt;
                        &amp;lt;/Flex&amp;gt;
                    &amp;lt;/Form&amp;gt;
                    {
                        (isLoading) ?
                        (&amp;lt;Flex justifyContent='center'&amp;gt;
                            &amp;lt;ProgressCircle aria-label="Loading…" isIndeterminate /&amp;gt;
                        &amp;lt;/Flex&amp;gt;) :
                        (&amp;lt;Flex
                            direction='column'&amp;gt;
                            {owners.map((x: any, y: number) =&amp;gt; {
                                return (
                                    &amp;lt;div
                                        key={x.ownerId}
                                        className={(y % 2 == 0) ? 'even' : 'odd'}&amp;gt;
                                        &amp;lt;Flex
                                            justifyContent='space-between'&amp;gt;
                                            &amp;lt;p&amp;gt;{x.ownerName}&amp;lt;/p&amp;gt;
                                            &amp;lt;p&amp;gt;{numberWithCommas(x.sharesHeld)}&amp;lt;/p&amp;gt;
                                        &amp;lt;/Flex&amp;gt;
                                    &amp;lt;/div&amp;gt;
                                )
                            })}
                        &amp;lt;/Flex&amp;gt;)
                    }
                &amp;lt;/Flex&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/sp-card&amp;gt;
    );
};

export default React.memo(NewOwnerSearch);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and my custom hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {useCallback, useState} from 'react';

const useHttp = (requestObj: any, setData: Function) =&amp;gt; 
{
    const [isLoading, setIsLoading] = useState(false); 
    const [error, setError] = useState('');

    const sendRequest = useCallback(() =&amp;gt;
    {
        setIsLoading(true);
        setError('');

        fetch(requestObj.url, {
            method: requestObj.method ? requestObj.method: 'GET',
            headers: requestObj.headers ? requestObj.headers : {},
            body: requestObj.body ? JSON.stringify(requestObj.body) : null
        })
        .then(res =&amp;gt; res.json())
        .then(data =&amp;gt; {
            setIsLoading(false);
            setData(data);                
        })
        .catch(err =&amp;gt; 
        {
            setError(err.message);
            setIsLoading(false); 
            console.log('There was an error');
        });
    }, []);

    return {
        isLoading: isLoading,
        error: error,
        sendRequest: sendRequest
    }
} 

export default useHttp;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;finally, here is the error im getting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
    at resolveDispatcher (react.development.js:1476)
    at useContext (react.development.js:1484)
    at useProvider (module.js:239)
    at $bc3300334f45fd1ec62a173e70ad86$var$Provider (module.js:95)
    at describeNativeComponentFrame (react-dom.development.js:946)
    at describeFunctionComponentFrame (react-dom.development.js:1034)
    at describeFiber (react-dom.development.js:1119)
    at getStackByFiberInDevAndProd (react-dom.development.js:1138)
    at createCapturedValue (react-dom.development.js:20023)
    at throwException (react-dom.development.js:20351)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>react</category>
    </item>
  </channel>
</rss>
