Skip to content
This repository has been archived by the owner on Apr 13, 2023. It is now read-only.

"Invalid hook call." error while using Query or useQuery with react-apollo 3 #3454

Closed
osenvosem opened this issue Sep 3, 2019 · 35 comments
Closed

Comments

@osenvosem
Copy link

Intended outcome:
Work without errors.

Actual outcome:

Uncaught Invariant Violation: 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

How to reproduce the issue:
I have an Electron + typescript app that just renders one component.

import React from 'react'
import { render } from 'react-dom'
import { ApolloProvider } from 'react-apollo'

const Test = () => {
  const { data } = useQuery(GET_USERS)
  console.log(data)
  return null
}

render(
  <ApolloProvider client={client}>
    <Test />
  </ApolloProvider>,
  document.getElementById('app')
)

Version
"react-apollo": "3.0.1",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"apollo-client": "^2.6.3",

@hwillson
Copy link
Member

hwillson commented Sep 4, 2019

@osenvosem Have you double checked You might have more than one copy of React in the same app? This is usually the culprit, especially when integrating with projects like React Native; something similar might be happening with Electron. If you still think this is a React Apollo issue though, please provide a small runnable reproduction and we'll take a look. Thanks!

@hwillson hwillson closed this as completed Sep 4, 2019
@osenvosem
Copy link
Author

@hwillson npm ls react shows only one instance of react. React hooks work well, the issue arises only with apollo-client hooks. I'm not sure why this issue is closed.

@seanfoundry
Copy link

+1 Same behavior with import { useQuery } from '@apollo/react-hooks'

@tonnenpinguin
Copy link

tonnenpinguin commented Oct 3, 2019

I've just started seeing the same thing after upgrading to expo sdk35 (React 16.8.3) :(

Interestingly useRef works without any issues just one line above the useQuery call

@clshu
Copy link

clshu commented Oct 17, 2019

I have a freshly installed project with create-react-app and see this problem too.

@tonnenpinguin
Copy link

In our case the issue was due to our umbrella app containing different react versions and I couldn't figure out how to get everything to use the right react versions. In the end we pinned all react versions to the one required by the react native app.

@Kif11
Copy link

Kif11 commented Oct 24, 2019

Hi @tonnenpinguin can you post working package.json please?

@tonnenpinguin
Copy link

@Kif11 it pretty much boils down to setting a specific version for react

    "react": "16.8.3",

@Kenoshen
Copy link

Kenoshen commented Nov 4, 2019

+1 for this, I'm having the same issue as well ( minimal example project ):

import React from "react";
import ReactDOM from "react-dom";
import {ApolloProvider, useQuery} from "@apollo/react-hooks";
import gql from "graphql-tag";
import {InMemoryCache} from "apollo-cache-inmemory";
import {HttpLink} from "apollo-link-http";
import {ApolloClient} from "apollo-client";

const cache = new InMemoryCache();
const link = new HttpLink({
    uri: 'http://localhost:9001/'
});

const client = new ApolloClient({
    cache,
    link
});

const GET_USERS = gql`
    query GetUsers {
        getUsers {
            id
        }
    }
`;

const Test = () => {
    const {data} = useQuery(GET_USERS);
    console.log(data);
    return null
};

ReactDOM.render(<ApolloProvider client={client}><Test/></ApolloProvider>, document.getElementById("app"));

Gets the error:

Uncaught 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://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.
    at resolveDispatcher (:9080/Users/mwingfield/Documents/drapery_software/client/electron/node_modules/react/cjs/react.development.js:1590)
    at useContext (:9080/Users/mwingfield/Documents/drapery_software/client/electron/node_modules/react/cjs/react.development.js:1598)
    at useBaseQuery (:9080/Users/mwingfield/Documents/drapery_software/client/electron/node_modules/@apollo/react-hooks/lib/react-hooks.cjs.js:474)
    at useQuery (:9080/Users/mwingfield/Documents/drapery_software/client/electron/node_modules/@apollo/react-hooks/lib/react-hooks.cjs.js:526)
    at Test (webpack-internal:///./src/renderer/index.tsx:56)
    at renderWithHooks (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:16241)
    at mountIndeterminateComponent (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:18775)
    at beginWork$1 (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:20137)
    at HTMLUnknownElement.callCallback (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:336)
    at Object.invokeGuardedCallbackDev (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:385)
webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:21810 
The above error occurred in the <Test> component:
    in Test
    in ApolloProvider

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://fb.me/react-error-boundaries to learn more about error boundaries.

Here is my package.json

{
  "name": "testname",
  "productName": "testname",
  "version": "0.0.12",
  "scripts": {
    "dev": "electron-webpack dev",
    "compile": "electron-webpack"
  },
  "build": {
    "appId": "com.testname.testname",
    "productName": "testname",
    "copyright": "Copyright © 2019 testname",
    "publish": {
      "provider": "s3",
      "bucket": "testname"
    },
    "win": {
      "target": "nsis"
    },
    "mac": {}
  },
  "dependencies": {
    "@apollo/react-components": "^3.1.3",
    "@apollo/react-hoc": "^3.1.3",
    "@apollo/react-hooks": "^3.1.3",
    "@reach/router": "^1.2.1",
    "apollo-cache": "^1.3.2",
    "apollo-cache-inmemory": "^1.6.2",
    "apollo-client": "^2.6.3",
    "apollo-link": "^1.2.13",
    "apollo-link-http": "^1.5.15",
    "apollo-utilities": "^1.3.2",
    "electron-log": "^3.0.8",
    "electron-updater": "^4.1.2",
    "graphql": "^14.4.2",
    "graphql-tag": "^2.10.1",
    "react": "16.11.0",
    "react-dom": "16.11.0",
    "react-scripts": "^3.2.0",
    "source-map-support": "^0.5.16",
    "spectre.css": "^0.5.8"
  },
  "devDependencies": {
    "@babel/cli": "^7.6.4",
    "@babel/core": "^7.6.4",
    "@babel/preset-env": "^7.6.3",
    "@babel/preset-react": "^7.6.3",
    "@graphql-codegen/cli": "^1.8.2",
    "@graphql-codegen/introspection": "1.8.2",
    "@graphql-codegen/typescript": "1.8.2",
    "@graphql-codegen/typescript-operations": "^1.8.2",
    "@graphql-codegen/typescript-react-apollo": "1.8.2",
    "@types/reach__router": "^1.2.6",
    "@types/react": "^16.9.11",
    "@types/react-dom": "^16.9.3",
    "babel-core": "^6.26.3",
    "babel-loader": "^8.0.6",
    "babel-preset-es2015-node": "^6.1.1",
    "babel-preset-react": "^6.24.1",
    "css-loader": "^3.2.0",
    "electron": "5.0.6",
    "electron-builder": "^21.0.11",
    "electron-webpack": "^2.7.4",
    "eslint": "^6.6.0",
    "eslint-plugin-react-hooks": "^2.2.0",
    "standard": "^14.3.1",
    "standard-loader": "^7.0.0",
    "style-loader": "^1.0.0",
    "ts-loader": "^6.2.1",
    "tslint": "^5.20.0",
    "tslint-config-standard": "^8.0.1",
    "tslint-loader": "^3.5.4",
    "typescript": "^3.6.4",
    "webpack": "^4.41.2",
    "webpack-bundle-analyzer": "^3.6.0",
    "webpack-cli": "^3.3.9",
    "webpack-dev-server": "^3.9.0"
  }
}

@Kenoshen
Copy link

Kenoshen commented Nov 5, 2019

After some testing, I've narrowed it down to a single variable:

package.json
{...
"dependencies":{...
    "react-apollo": "^2.5.8",
...}
...}

works as expected.

package.json
{...
"dependencies":{...
    "react-apollo": "^3.0.0",
...}
...}

Fails with the Invalid Hooks error.

@hwillson thoughts?

@klaaz0r
Copy link

klaaz0r commented Nov 6, 2019

I am having the same issue inside yarn workspaces/lerna where all the apollo logic is within a controllers package. I rewrote the package to only use @apollo/react-hooks@3.1.3 which works perfectly fine inside the web app. Using the exact same package inside the native app gives the hook error.

I tried running the native app detached from lerna/workspaces but still have the error. I also use the exact same code and versions to create the client/provider.

yarn list --pattern react also doesn't show any duplicated versions of react. Also all the react versions are hard set + set in the resolutions field in the root package.

Regular react hooks seem to work fine in the native app, using hooks directly without my own controllers also gives the error.

@klaaz0r
Copy link

klaaz0r commented Nov 14, 2019

@Kenoshen @hwillson Did you guys find a solution?

@traviswimer
Copy link

@klaaz0r I'm using "react-apollo": "^3.0.1" with Yarn Workspaces in a react-native project, and I was able to fix this just by installing @apollo/react-hooks.

One thing I might be doing different from you is using the nohoist Workspace option (https://yarnpkg.com/blog/2018/02/15/nohoist/)

If you haven't tried it, this option allows you to prevent dependencies from being shared across workspaces. In my case, I chose to just completely disable the hoisting feature using this in my root package.json:

{
	"workspaces": {
		"packages": [
			"projects/*"
		],
		"nohoist": [
			"**"
		]
	},
}

@kiro112
Copy link

kiro112 commented Nov 18, 2019

Issue still exists.

import React, { useState } from 'react';

import { 
    FormGroup,
    Label,
    Input,
    Container,
    Button,
} from 'reactstrap';

import { useQuery } from '@apollo/react-hooks';
import {
    ADD_USER,
} from '../Queries';

const Userform = (prop) => {

    const [user, setUser] = useState({
        name: '',
        email: '',
        job_title: ''
    });

    const updateUser = (e) => {
        setUser({
            ...user,
            [e.target.id]: e.target.value
        });
    }

    const SaveUser = () => {
        let result = useQuery(ADD_USER, {
            variables: {
                ...user
            }
        });
    };

    return (
        <Container>
            <FormGroup>
                <Label for="name">Name: </Label>
                <Input type="text" id="name" onChange={updateUser} />
            </FormGroup> <br/>

            <FormGroup>
                <Label for="email">E-mail: </Label>
                <Input type="email" id="email" onChange={updateUser} />
            </FormGroup> <br/>

            <FormGroup>
                <Label for="job-title">Job Title: </Label>
                <Input type="text" id="job_title" onChange={updateUser}  />
            </FormGroup>

            <Button onClick={SaveUser}>Save</Button>
        </Container>
    );
}

export default Userform;

it errors on the useQuery.

with the version

"@apollo/react-hooks": "^3.1.3",
"apollo-boost": "^0.4.4",
"graphql": "^14.5.8",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-router-dom": "^5.1.2",
"react-scripts": "3.2.0",

@aimadnet
Copy link

I got same issue too with both useQuery and useMutation

Error:

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://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.

@alejo-lapix
Copy link

alejo-lapix commented Nov 20, 2019

If this helps anyone I was working with Gatsby and had the same error, but looking in the documentation found this:

Your app is not correctly hydrated, which results in gatsby develop and gatsby build being inconsistent. It’s possible that a change in a file like gatsby-ssr or gatsby-browser has a structure that is not reflected in the other file, meaning that there is a mismatch between client and server output.

I had different output in the gatsby-browser and gatsby-ssr files. I just had to ensure that those files export a similar structure and that solved this error.

@srikanthdasari
Copy link

same issue...please help...

Action

import React from "react";
import * as ACTION_TYPES from "./../constants/action-types";
import { useQuery } from "@apollo/react-hooks";
import gql from 'graphql-tag';

export const getCharactersSuccess = (data) => {
    return {
        type:ACTION_TYPES.LOAD_CHARACTERS_SUCCESS,
        data
    }
}

export const getCharactersInProgress = () => {
    return {
        type:ACTION_TYPES.LOAD_CHARACTERS_INPROGRESS
    }
}

export const getCharactersError = (error) => {
    return {
        type:ACTION_TYPES.LOAD_CHARACTERS_ERROR,
        error
    }
}

const GET_CHARACTERS =gql`
{
    allPersons {
        name
        gender
        homeworld {
            name
        }
        species {
            name
            language
            classification
        }
    }
}`;

export const useGetCharacters= () => {
    const { loading, error, data } = useQuery(GET_CHARACTERS);
    
    if(loading) {
        getCharactersInProgress();
    }

    if(error) {
        getCharactersError(error);
    }

    if(data) {
        getCharactersSuccess(data);
    }
}

Reducer



export const ContextState = (props) => {
    // const [stateReducer, dispatchReducer] = useReduceWithLogger(Reducer.AppLoadingReducer,Reducer.initialState);
    const [stateReducer, dispatchReducer] = useReducer(Reducer.MainReducer,Reducer.initialState);

    const handleDispatchAppLoadingInProgress = () => {
        dispatchReducer(GENERIC_ACTION.appLoadingInprogress());
    }

    const handleDispatchAppLoadingSuccess = () => {
        dispatchReducer(GENERIC_ACTION.appLoadingSuccess());
    }

    // const getCharacters = () => {
    //     dispatchReducer(GET_CHARACTERS_ACTION.useGetCharacters());
    // }

    const graphqlClient = new ApolloClient({
        uri: "https://swapi.graph.cool/"
    });

    return (
        <div>
            <ApolloProvider client={graphqlClient}>
                <Context.Provider
                    value={{
                        // reducer
                        isAppReady: stateReducer.isAppReady,
                        dispatchAppLoading: () => handleDispatchAppLoadingInProgress(),
                        dispatchAppLoaded: () => handleDispatchAppLoadingSuccess(),
                        // get character action
                        getCharacters: () => dispatchReducer(GET_CHARACTERS_ACTION.useGetCharacters())
                    }}
                >
                    
                        {
                            props.children
                        }
                </Context.Provider>
            </ApolloProvider>
        </div>
    )
}

@Knaackee
Copy link

Knaackee commented Dec 17, 2019

Same problem here.

I checked the react version etc. useState does work useSubscriptions gives the following error.

Uncaught 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

Why is this closed?

@rsatoor
Copy link

rsatoor commented Dec 17, 2019

Running into this same issue, some solution/guidance would be appreciated

@sebastienfi
Copy link

sebastienfi commented Dec 30, 2019

Same here. lerna + yarn workspaces + react-apollo

Ends up with an error though, no warnings

TypeError: this.currentObservable.query.getCurrentResult is not a function : 
QueryData.getQueryResult
C:/temp/cra-workspaces-playground/packages/apps/src/data/QueryData.ts:337
  334 |   };
  335 | } else {
  336 |   // Fetch the current result (if any) from the store.
> 337 |   const currentResult = this.currentObservable.query!.getCurrentResult();
      | ^  338 |   const { loading, partial, networkStatus, errors } = currentResult;
  339 |   let { error, data } = currentResult;
  340 | 

@isaiahtaylorhh
Copy link

Same issue.

render() {
    const { loading, error, data } = useQuery(Graphs.LIST_DEVICES);
    if (loading) return <p>Loading...</p>;
    if (error) return <p>Error :(</p>;
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://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.
▶ 5 stack frames were collapsed.
ClientView.render
src/components/Body/ClientView/ClientView.jsx:21
  18 | //   return <div>{props.name} {props.phone}</div>;
  19 | // }
  20 | 
> 21 | render() {
     | ^  22 |   const { loading, error, data } = useQuery(Graphs.LIST_DEVICES);
  23 |   if (loading) return <p>Loading...</p>;
  24 |   if (error) return <p>Error :(</p>;

@frolovdev
Copy link

@isaiahtaylor @sebastienfi @Knaackee try to install @apollo/react-hooks to package not in the root

I have the same problem with monorepo

@traviswimer
Copy link

@isaiahtaylor You are "breaking the Rules of Hooks". https://reactjs.org/docs/hooks-rules.html#only-call-hooks-from-react-functions

You shouldn't be using hooks inside a render function. You should convert your Component to a Function Component.

@traviswimer
Copy link

@sebastienfi To go along with what @Whispers12 said, the nohoist option is likely what you need if you are using Yarn Workspaces. (#3454 (comment))

@Knaackee
Copy link

@Whispers12 already tried that with no success

@Knaackee
Copy link

@traviswimer i am using a functional component

@Knaackee
Copy link

@traviswimer I don't use yarn workspaces. I have all my modules in my package.json of my project

@isaiahtaylorhh
Copy link

@isaiahtaylor You are "breaking the Rules of Hooks". https://reactjs.org/docs/hooks-rules.html#only-call-hooks-from-react-functions

@traviswimer you are correct! That was my issue. Thank you.

@traviswimer
Copy link

@Knaackee My comment wasn't directed at you, but to answer your original question, I think this was closed because its more likely to be a react issue like the error suggests.

I don't really know what to suggest other than the normal silly node fixes like deleting node_modules, upgrading your react dependencies, etc.

You might have better luck if you can post a question with some code on Stackoverflow.

@juicycleff
Copy link

Still having this issue

@Risbot
Copy link

Risbot commented Feb 20, 2020

Some solution? I have same issue in monorepo with react native. React hooks work fine like useEffect or useState

@EladBezalel
Copy link

EladBezalel commented Apr 21, 2020

I also have the same problem with monorepo and react native..
I even tried to create a clean application with only the bare minimum and it doesn't work.. why is this issue closed?

@EladBezalel
Copy link

EladBezalel commented Apr 23, 2020

I fixed it,
Apparently it seems like it is related to two react versions (even though i had only one).
To solve it I had to specifically tell metro bundler from where to resolve react using babel-plugin-module-resolver:

yarn workspace @your/workspace add --dev babel-plugin-module-resolver

in babel.config.js

module.exports = {
    // ...
    plugins: [
        [
            'module-resolver',
            {
                root: ['./mobile'],
                extensions: ['*'],
                alias: {
                    react: './node_modules/react',
                },
            },
        ],
        // ...
    ],
};

@andrewpjames13
Copy link

andrewpjames13 commented May 1, 2020

Hey, I'm having this issue only when trying to test. I am using react-native, apollo, graphql-code-generator and typescript. I am trying to get my tests set up with jest and @testing-library/react-native. The tests work except when I try to test a file using one of the ApolloReactHooks I get this error.

Invariant Violation: 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://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.

      2443 | export function useDashboardQuery(baseOptions?: ApolloReactHooks.QueryHookOptions<DashboardQuery, DashboardQueryVariables>) {
    > 2444 |         return ApolloReactHooks.useQuery<DashboardQuery, DashboardQueryVariables>(DashboardDocument, baseOptions);
           |                                 ^
      2445 |       }
      2446 | export function useDashboardLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions<DashboardQuery, DashboardQueryVariables>) {
      2447 |           return ApolloReactHooks.useLazyQuery<DashboardQuery, DashboardQueryVariables>(DashboardDocument, baseOptions);

      at node_modules/react/cjs/react.development.js:1533:26
      at resolveDispatcher (node_modules/react/cjs/react.development.js:1536:5)
      at useContext (node_modules/react/cjs/react.development.js:1541:20)
      at useBaseQuery (node_modules/@apollo/client/react/hooks/utils/useBaseQuery.js:11:19)
      at Object.useQuery (node_modules/@apollo/client/react/hooks/useQuery.js:4:12)
      at useDashboardQuery (App/generated/graphql.tsx:2444:33)
      at Dashboard (App/screens/Dashboard/index.tsx:117:45)
      at renderWithHooks (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:5762:18)
      at mountIndeterminateComponent (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7996:13)
      at beginWork$1 (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:9140:16)

I am calling it in a function component along side other hooks that are working just fine. I tried all the suggestions in this thread and others around getting the invalid hook error and I have run out of ideas. Again this is working when I run my dev server or a production build. It just is not working when I run tests. Any thoughts or ideas would be appreciated.

Test:

import React from 'react'
import { render } from '@testing-library/react-native'
import { MockedProvider } from '@apollo/client/testing'
import { TestComponent } from './TestComponent'

const mocks = []

function setup() {
  const comp = render(
    <MockedProvider mocks={mocks}>
      <TestComponent testID='test' value={10} />
    </MockedProvider>
  )
  return { ...comp }
}

describe('TestComponent', () => {
  it('renders', () => {
    const { getByTestId } = setup()
    expect(getByTestId('test')).toBeTruthy()
  })
})

Component:

import React, { useState } from 'react'
import { useDashboardQuery } from '../../generated/graphql'
import { NumProps, Num } from './Num'

type TestComponentProps = NumProps

export const TestComponent: React.FC<TestComponentProps> = ({ value, ...props }) => {
  const [state, setState] = useState(true)
  const { data } = useDashboardQuery({ userId: "1" })
  console.log(state)
  console.log(data)
  return <Num value={value} {...props} />
}

babel.config.js:

module.exports = function (api) {
  api.cache(true)

  return {
    presets: [
      'babel-preset-expo',
      'module:react-native-dotenv',
      'module:metro-react-native-babel-preset'
    ],
    plugins: [
      [
        'babel-plugin-inline-import',
        {
          extensions: ['.svg']
        }
      ],
    ]
  }
}

jest.config.js:

module.exports = {
  preset: 'jest-expo',
  clearMocks: true,
  collectCoverage: false,
  collectCoverageFrom: ['App/**/*.[tj]s'],
  moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
  resetMocks: true,
  resetModules: true,
  rootDir: '.',
  transform: {
    '^.+\\.(ts)$': 'ts-jest',
    '^.+\\.tsx?$': 'babel-jest',
    '^.+\\.jsx?$': 'babel-jest'
  },
  verbose: true
}

Oh yea and my apollo version:

"dependencies": {
    "@apollo/client": "^3.0.0-beta.38",

@azimut3
Copy link

azimut3 commented May 13, 2020

Same issue

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests