lwin
lwin

Reputation: 4460

Invalid hook call. Hooks can only be called inside of the body of a function component

I want to show some records in a table using React but I got this 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 for tips about how to debug and fix this problem.
import React, { Component } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';

const useStyles = makeStyles(theme => ({
  root: {
    width: '100%',
    marginTop: theme.spacing(3),
    overflowX: 'auto'
  },
  table: {
    minWidth: 650
  }
}));

class allowance extends Component {
  constructor() {
    super();
    this.state = {
      allowances: []
    };

  }

  componentWillMount() {
    fetch('http://127.0.0.1:8000/allowances')
      .then(data => {
        return data.json();
      })
      .then(data => {
        this.setState({
          allowances: data
        });
        console.log('allowance state', this.state.allowances);
      });
  }

  render() {
    const classes = useStyles();
    return (<Paper className={classes.root}>
        <Table className={classes.table}>
          <TableHead>
            <TableRow>
              <TableCell>Allow ID</TableCell>
              <TableCell align="right">Description</TableCell>
              <TableCell align="right">Allow Amount</TableCell>
              <TableCell align="right">AllowType</TableCell>
            </TableRow>
          </TableHead>
          <TableBody> {
            this.state.allowances.map(row => (<TableRow key={row.id}>
                <TableCell component="th" scope="row">{row.AllowID}</TableCell>
                <TableCell align="right">{row.AllowDesc}</TableCell>
                <TableCell align="right">{row.AllowAmt}</TableCell>
                <TableCell align="right">{row.AllowType}</TableCell>
              </TableRow>
            ))
          }
          </TableBody>
        </Table>
      </Paper>
    );
  }

}

export default allowance;

Upvotes: 345

Views: 1042658

Answers (30)

Zhu
Zhu

Reputation: 31

After several rounds of debugging, I discovered the true cause of the issue in my project. It was related to a method being moved into the component where it was previously defined outside. The method in question is makeStyles, commonly used like this :

  const allStyles = makeStyles((theme) => ({
    popupDialogContainer: {
      borderRadius: 8,
      padding: 24,
      rowGap: 10,
      backgroundColor:theme.colors.primary
    },
  }))();

The makeStyles method, from the React-Native-Element library, is used for configuring styles with global theme settings.

What Happened:

  • The error did not occur during the app’s runtime.
  • Instead, it occurred when fast refreshing the app after editing the component that used this method.

Upvotes: 0

Vinay Upadhyay
Vinay Upadhyay

Reputation: 118

if you're still getting this error by applying above all the solution, then you can do one more try by remove the node_modules Pods directory podfile.lock file yarn.lock file or package-lock.json file and delete the app and reinstall the app.

(In my case this issue arises when I switch the branch).

Upvotes: 0

XXIV
XXIV

Reputation: 61

My Noob Brain wrote curly braces for useState()

const {loading, setLoading} = useState(true)

Fix :

const [loading, setLoading] = useState(true)

Upvotes: 0

Олег Colt_ain
Олег Colt_ain

Reputation: 325

We have encountered an issue with folder linking through yarn where yarn fails to remove the links completely. This problem arose while working with the React Map Library build, and it looks like what's shown in the screenshot.

To fix this build error, follow these steps:

Run yarn unlink react && yarn unlink react-dom, and your other libraries. Ideally, this command should remove all linked library folders. You can also use the command yarn unlink --all. Next, delete the node_modules folder in all linked repositories.

IMPORTANT!!! If rebuilding the dev server and relinking didn't solve the issue, it's possible that Yarn didn't completely clean up the links. You can manually delete them with the command rm -rf ~/.config/yarn/link/*. Then, relink the necessary folders (react, react-dom), and everything should work again. Hope this helps!

Upvotes: 0

Giang Le
Giang Le

Reputation: 7044

You can only call hooks from React functions. Read more here.

Just convert the Allowance class component to a functional component.

Working CodeSandbox demo.

const Allowance = () => {
  const [allowances, setAllowances] = useState([]);

  useEffect(() => {
    fetch('http://127.0.0.1:8000/allowances')
      .then(data => {
        return data.json();
      })
      .then(data => {
        setAllowances(data);
      })
      .catch(err => {
        console.log(123123);
      });
  }, []);

  const classes = useStyles();
  return (<Paper className={classes.root}>
      <Table className={classes.table}>
        <TableHead>
          <TableRow>
            <TableCell> Allow ID </TableCell>
            <TableCell align="right"> Description </TableCell>
            <TableCell align="right"> Allow Amount </TableCell>
            <TableCell align="right"> AllowType </TableCell>
          </TableRow>
        </TableHead>
        <TableBody>{
          allowances.map(row => (<TableRow key={row.id}>
              <TableCell component="th" scope="row">{row.AllowID}</TableCell>
              <TableCell align="right"> {row.AllowDesc}</TableCell>
              <TableCell align="right"> {row.AllowAmt}</TableCell>
              <TableCell align="right">{row.AllowType}</TableCell>
            </TableRow>
          ))
        }
        </TableBody>
      </Table>
    </Paper>
  );
};

export default Allowance;

Upvotes: 116

Lojith Vinsuka
Lojith Vinsuka

Reputation: 1051

enter image description here

In my Next.js app, I encountered the same issue. In my case, I believe it was a cache-related problem. Running the project after removing the ".next" folder resolved the issue. I hope that removing the build folder in React will have the same effect.

Upvotes: 4

user1207289
user1207289

Reputation: 3253

In my case , the issues was because somehow , I was generating two react trees because I had two ReactDOM.render calls . One in index.js and other one in a component. Error goes away , after I removed one of the ReactDOM.render call like this

export const RenderTopMenuResultPage = (props) => {

    ReactDOM.render(    
        <CreateTopMenuResultPage />, 
        document.getElementById('result-page-sort-menu')
    )
} 

to

export const RenderTopMenuResultPage = (props) => {
    return <CreateTopMenuResultPage />;
};

Upvotes: 0

Darpan
Darpan

Reputation: 5795

In my case, I called the functional component as a function myComponent() instead of using it as a component, i.e. <myComponent />, and that solved my issue.

Upvotes: 0

androbin
androbin

Reputation: 1759

I was using microfrontend architecture. The problem was that the react dependencies were not shared during the compilation in Webpack.

Example nx config:

module.exports = {
  name: 'mfe',
  remotes: ['mfe-remote'],
  additionalShared: ['react', 'react-dom', /* 'any-react-library' used by both module */],
}

Upvotes: 0

Nabeel Zanabeet
Nabeel Zanabeet

Reputation: 61

For those who have a Monorepo setup (whether it's multiple React projects or a combination of React and React Native):

I encountered an error after updating my React Native project to RN 70 and React 18 while executing the app via the Metro bundler:

1- Ensure a unified version of react, react-dom, and react-redux is used across all packages.

2- (ignore if you don't have a react native package) Verify that both react and react-redux aren't hoisted for the mobile (React Native package). This means both packages should be present in the node_modules directory of the mobile package. Learn more about nohoist here.

A useful tip:

yarn why react

This command displays which packages have react as a dependency. Additionally:

yarn list react

This command presents the versions of react in your project. Ideally, there should only be one version.

The same applies for react-redux and react-thunk.

Upvotes: 0

Patrik Rikama-Hinnenberg
Patrik Rikama-Hinnenberg

Reputation: 1600

Be aware of import issues- For me the error was about failing imports / auto imports on components and child components. Had nothing to do with Functional classes vs Class components.

  • This is prone to happen as VS code auto importing can specify paths that are not working.
  • if import { MyComponent } is used and export default used in the component the import should say import MyComponent
  • If some Components use index.js inside their folder, as a shotcut for the path, and others not the imports might break. Here again the auto import can cause problems as it merges all components from same folder like this {TextComponent, ButtonComponent, ListComponent} from '../../common'

Try to comment out some components in the file that gives the error and you can test if this is the problem.

Upvotes: 2

Haneen
Haneen

Reputation: 1146

This might also occur because your hook is called below any asynchronous or nested functions. You need to move the hook to the top level of the function body.

In your case, it looks like you're using a hook for class component. Consider changing the class component to a function component and then using the hook inside the top-level of the function component.

Upvotes: 0

krishnaacharyaa
krishnaacharyaa

Reputation: 24950

There are many reasons for this to happen. One of which is , when the installation of the packages are done out of scope. It tends to get confused between two react apps.

Explanation:

The packages shouldn't be installed in different levels.

The mistake

app
 |node_modules          <-- some packages installed here
 |package.json
node_modules
package.json            <-- some packages installed here

Correct Way

app
 |node_modules
 |package.json          <-- install all the packages at the same heirarchy

Upvotes: 2

Philip Sopher
Philip Sopher

Reputation: 783

This occured for me when improperly destructuring the response from an axios.get server call. I changed:

const { retrievedUser } = await axios.get('www.mysite.com/user/userid')

to:

const { data: retrievedUser } = await axios.get('www.mysite.com/user/userid')

Upvotes: 0

KARTHIKEYAN.A
KARTHIKEYAN.A

Reputation: 20088

In mycase i have used useCallback hook inside class component due to this i had a error mentioned in the question

Error:

import React, { useCallback } from 'react'
import { FormControlLabel, Switch, withStyles } from '@material-ui/core'


const styles = {
    root: {
        alignItems: 'center',
        display: 'flex',
        height: '50px',
        justifyContent: 'center',
        padding: 0,
        width: '90px',
    },
    switchBase: {
        '& + $track': {
            backgroundColor: 'lightblue',
        },
        '&$checked': {
            color: 'lightblue',
            transform: 'translateX(40px)',
        },
    },
    thumb: {
        borderRadius: '0px',
        height: '15px',
        marginTop: '8px',
        transform: 'translateX(19px)',
        width: '15px',
    },
    track: {
        borderRadius: '0px',
        height: '20px',
        width: '40px',
    },
}

class SwitchLabels extends React.Component {
    state = {
        checked: false,
    }

    handleChange = React.usecallback(event => { // here i have used useCallback hook
        this.props.changeStatus(event.target.checked)
        this.setState({ checked: event.target.checked })
    }, [])

    render() {
        return (
            <FormControlLabel
                control={
                    <Switch
                        classes={this.props.classes}
                        checked={this.state.checked}
                        onChange={this.handleChange}
                        disableElevation
                        disableRipple
                        style={{ backgroundColor: 'transparent' }}
                        value={this.state.checked}
                        color='primary'
                    />
                }
                labelPlacement='start'
                label={'Show inactive'}
            />
        )
    }
}

export default withStyles(styles)(SwitchLabels)

Solution:

import React from 'react'
import { FormControlLabel, Switch, withStyles } from '@material-ui/core'


const styles = {
    root: {
        alignItems: 'center',
        display: 'flex',
        height: '50px',
        justifyContent: 'center',
        padding: 0,
        width: '90px',
    },
    switchBase: {
        '& + $track': {
            backgroundColor: 'lightblue',
        },
        '&$checked': {
            color: 'lightblue',
            transform: 'translateX(40px)',
        },
    },
    thumb: {
        borderRadius: '0px',
        height: '15px',
        marginTop: '8px',
        transform: 'translateX(19px)',
        width: '15px',
    },
    track: {
        borderRadius: '0px',
        height: '20px',
        width: '40px',
    },
}

class SwitchLabels extends React.Component {
    state = {
        checked: false,
    }

    handleChange = event => { // after removing useCallback working fine
        this.props.changeStatus(event.target.checked)
        this.setState({ checked: event.target.checked })
    }

    render() {
        return (
            <FormControlLabel
                control={
                    <Switch
                        classes={this.props.classes}
                        checked={this.state.checked}
                        onChange={this.handleChange}
                        disableElevation
                        disableRipple
                        style={{ backgroundColor: 'transparent' }}
                        value={this.state.checked}
                        color='primary'
                    />
                }
                labelPlacement='start'
                label={'Show inactive'}
            />
        )
    }
}

export default withStyles(styles)(SwitchLabels)

Upvotes: 0

windmaomao
windmaomao

Reputation: 7671

In my case, it's come from the Chrome Extension: Loom. But it can come from any extension written via React. Crazy world, isn't it? Just disable the extension resolves the error.

Upvotes: 0

Justin Herrera
Justin Herrera

Reputation: 653

Happens to me when I used to call useNavigate() on a certain function upon onClick.

Upvotes: 4

Alisha Irshad
Alisha Irshad

Reputation: 64

with NPM npm install react@latest react-dom@latest with YARN yarn add react@latest react-dom@latest

Upvotes: 2

Mohammad Tbeishat
Mohammad Tbeishat

Reputation: 1066

I had the same issue, and it got resolved after editing launch.json file for vscode and changing the configurations type by removing 'pwa-' from the type:

So, instead of:

"type": "pwa-node",

It should be:

"type": "node",

Upvotes: 0

Johan Maes
Johan Maes

Reputation: 1442

For me this issue was caused by the webpack setting resolve.symlinks (https://webpack.js.org/configuration/resolve/#resolvesymlinks), which was set to false:

  resolve: {
    symlinks: false,

Because of this the symlink to React from another package couldn't be resolved and caused the Invalid Hook Call error.

Setting it to true or simply omitting it (apparently it defaults to true) solved the problem:

  resolve: {
    symlinks: true,

Upvotes: 0

Muhammad Talha
Muhammad Talha

Reputation: 832

In my case, I was using navigation in App.js where I have Stack Navigator & assigning all my screens. Please remove below line if you have that.

const navigation = useNavigation()

Upvotes: 2

Julian K
Julian K

Reputation: 2001

I'm using Electron. I tested all the answers above, even stripping down to the base app, and found it was still happening.

Turns out if you are using electron (specifically expo-electron, in my case), it has it's own webpack configuration, and you need to white-list redux in the webpack config. My electron-webpack.js file looks like this:

const { withExpoAdapter } = require("@expo/electron-adapter");

// Provide any overrides for electron-webpack: https://github.com/electron-userland/electron-webpack/blob/master/docs/en/configuration.md
module.exports = withExpoAdapter({
  projectRoot: __dirname,
  whiteListedModules: ["react-redux"],
});

Upvotes: 0

Adrian
Adrian

Reputation: 122

Bad:

import { useDispatch } from 'react';

Good:

import { useDispatch } from 'react-redux';

I remember It happened to me once that I imported useDispatch from ‘react’ as opposed to import it from ‘react-redux’ It was very difficult to figure out, because code seamed right from every angle, I just could not guess it for hours lol

Upvotes: 0

KARTHIKEYAN.A
KARTHIKEYAN.A

Reputation: 20088

I had same problem while I use useLocation hook in class component

Error:

import React from "react";
import { useLocation } from "react-router-dom";

class ShowTheLocation extends React.Component {
  const location = useLocation();
  render() {
    return <div>You are now at {location.pathname}</div>;
  }
}

Solution: I have converted class component to function component then issue resolved

import React from "react";
import { useLocation } from "react-router-dom";

const ShowTheLocation = () => {
  const location = useLocation();

  return <div>You are now at {location.pathname}</div>;
}

Upvotes: 0

Saurabh
Saurabh

Reputation: 375

Another reason this error could happen is if you have declared your functional components with an arrow function signature instead of a function signature.

Ex: Change your functional component declaration from an arrow function

export const Counter = (props) => {}

TO function declaration

export function Counter (props) {}

And that will help resolve the issue. At least in my case, it did.

Upvotes: 1

Thanaruby Nanthagopal
Thanaruby Nanthagopal

Reputation: 614

I got this error when I linked a local library. The following solved my problem.

  1. In the library:
  • remove "react" and "react-dom" from dependancies and added them to peerDependencies.
  • install dependencies, build
  1. Restart the main project.

Upvotes: 1

Aindri&#250;
Aindri&#250;

Reputation: 3730

My error was with the export at the end, I had the following:

enter image description here

I should have removed the brackets:

enter image description here

Upvotes: 1

Egidius
Egidius

Reputation: 1459

If your front-end work is in its own folder you might need to install @material-ui/core @material-ui/icons inside that folder, not in the backend folder.

npm i @material-ui/core @material-ui/icons

Upvotes: 2

Khaled Rakhisi
Khaled Rakhisi

Reputation: 325

To anybody who might looking for a FAST solution to this issue :

You might be breaking the Rules of Hooks. To Solve this Problem move the :

👉const [x, setX] = useState(0);

to the TOP-LEVEL of the function that calling it And not outside of the function.

function App() {
   👉const [t, setTime] = useState("");

   return (
      <div>
         <h1>{t}</h1>
         <button onClick={() => setTime(t+1)}>Get Time</button>
      </div>
 );
}

👍 https://reactjs.org/warnings/invalid-hook-call-warning.html

Upvotes: 1

Michael Guild
Michael Guild

Reputation: 834

I ran into this same issue while working on a custom node_module and using npm link for testing within a cra (create react app).

I discovered that in my custom node package, I had to add a peerDependencies

"peerDependencies": {
    "@types/react": "^16.8.6 || ^17.0.0",
    "react": "^17.0.0",
    "react-dom": "^17.0.0"
  },

After added that into my package.json, I then re-built my custom package. Then in the CRA, I blew away node_modules, re npm install, Re-do the npm link <package>, and then start the project.

Fixed everything!

Upvotes: 2

Related Questions