user13055593
user13055593

Reputation:

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

i am using material ui and when i Want to use below code (Component) in my reactjs app without below code my app working fine but when i use below code then i get Error: Invalid hook call. Hooks can only be called inside of the body of a function component.. I am using Typescript for reactjs. and i want to use react material-ui components

I want Use this Code (Component)

const [checked, setChecked] = React.useState(true);

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setChecked(event.target.checked);
  };
<div>
      <Checkbox
        checked={checked}
        onChange={handleChange}
        inputProps={{ 'aria-label': 'primary checkbox' }}
      />
</div>

Here i want to use

import React, { Component } from 'react'
import ApiService from "../../service/ApiService";
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 Button from '@material-ui/core/Button';
import CreateIcon from '@material-ui/icons/Create';
import DeleteIcon from '@material-ui/icons/Delete';
import Typography from '@material-ui/core/Typography';
import { Grid } from '@material-ui/core';
import Checkbox from '@material-ui/core/Checkbox';
import FormGroup from '@material-ui/core/FormGroup';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import FormControl from '@material-ui/core/FormControl';
import FormLabel from '@material-ui/core/FormLabel';

class CategoryListUserComponent extends Component<any,any>{

    constructor(props: any){
        super(props)
        this.state = {
            users: [],
            message: null,
            checked: true
        }
        this.deleteUser = this.deleteUser.bind(this);
        this.editUser = this.editUser.bind(this);
        this.addUser = this.addUser.bind(this);
        this.reloadUserList = this.reloadUserList.bind(this);
    }

    componentDidMount() {
        this.reloadUserList();
    }

    reloadUserList() {
        ApiService.fetchUsers()
            .then((res) => {
                this.setState({users: res.data})
            });
    }

    deleteUser(userId: any) {
        ApiService.deleteUser(userId)
           .then(res => {
               this.setState({message : 'User deleted successfully.'});
               this.setState({users: this.state.users.filter((user: { id: any; }) => user.id !== userId)});
           })
    }

    editUser(id: any) {
        window.localStorage.setItem("userId", id);
        this.props.history.push('/edit-user');
    }

    addUser() {
        window.localStorage.removeItem("userId");
        this.props.history.push('/add-user');
    }

    render() {
        return (
            <Grid>
                 <Typography variant="h4" align="left" style={style}>Category List</Typography>
                <Button variant="contained" color="primary" onClick={() => this.addUser()}>
                    Add Category
                </Button>
                <Grid  container   className="listContainer">
                <Table>
                    <TableHead>
                        <TableRow>
                            <TableCell>Id</TableCell>
                            <TableCell>Initiator</TableCell>
                            <TableCell align="left">Category</TableCell>
                            <TableCell align="left">Date</TableCell>
                            <TableCell align="left">Time</TableCell>
                            <TableCell align="left">Status</TableCell>
                            <TableCell align="left"></TableCell>
                            <TableCell align="left"></TableCell>
                        </TableRow>
                    </TableHead>
                    <TableBody>
                        {this.state.users && this.state.users.map((row: { id: {} | null | undefined; name: React.ReactNode; email: React.ReactNode; username: React.ReactNode; age: React.ReactNode; salary: React.ReactNode; }) => (
                            <TableRow>
                                <TableCell scope="row">
                                    {row.id}
                                </TableCell>
                                <TableCell align="left">{row.name}</TableCell>
                                <TableCell align="left">{row.username}</TableCell>
                                <TableCell align="left">13-10-2020</TableCell>
                                <TableCell align="left">10:00 AM</TableCell>
                                <TableCell align="left"><FormControl component="fieldset">
                                <FormGroup aria-label="position" row>
                                    <FormControlLabel
                                    value="top"
                                    control={<Checkbox color="primary" checked />}
                                    label=""
                                    labelPlacement="start"
                                    />

                                </FormGroup>
                                <FormGroup>
                                <Checkbox

  onChange={(event) => {
    this.setState({
      checked: event.target.checked,
    )}
  }}
  inputProps={{ 'aria-label': 'primary checkbox' }}
/>

                                </FormGroup>
                                </FormControl>
                                 </TableCell>
                                <TableCell align="left" onClick={() => this.editUser(row.id)}><CreateIcon /></TableCell>
                                <TableCell align="left" onClick={() => this.deleteUser(row.id)}><DeleteIcon /></TableCell>

                            </TableRow>
                        ))}
                    </TableBody>
                </Table>

            </Grid>
            </Grid>
        );
    }

}

const style ={
    display: 'flex',
    justifyContent: 'center'
}

export default CategoryListUserComponent;

Upvotes: 0

Views: 1449

Answers (2)

Muhammad Haseeb
Muhammad Haseeb

Reputation: 1341

The error is self explanatory as it says Hooks can only be called inside of the body of a function component.

CategoryListUserComponent is currently a class-based componentReact.useState is a hook and can only be used in a functional component.

There are three ways to solve this issue:

  1. Convert your CategoryListUserComponent component into functional component (Recommended).
  2. Rather than including the code (that contains the checkbox) in CategoryListUserComponent , include it as a component in the parent component.
  3. Convert the above code into class-based component.

As mentioned by @wentjun You can convert the above code into to include in a class-based component

Instead of using hook define your check state in the constructor i.e.

this.state = {
  users: [],
  message: null,
  checked: true, // or false
} 

And convert your JSX to :

<Checkbox
  checked={checked}
  onChange={(event) => {
    this.setState({
      checked: event.target.checked,
    )}
  }}
  inputProps={{ 'aria-label': 'primary checkbox' }}
/>

Upvotes: 1

wentjun
wentjun

Reputation: 42526

As stated on the official documentation for React Hooks, hooks (such as useState) can only be used in functional components.

CategoryListUserComponent is a class component.

If you wish to use the useState hook, you should CategoryListUserComponent to a functional component.

Alternatively, you can simply add the checked state to CategoryListUserComponent, such that it is part of the component's state.

this.state = {
  users: [],
  message: null,
  checked: true, // or false
}

And then, you can simply update state by using this.setState() when the Checkbox component is clicked.

<Checkbox
  checked={checked}
  onChange={(event) => {
    this.setState({
      checked: event.target.checked,
    )}
  }}
  inputProps={{ 'aria-label': 'primary checkbox' }}
/>

In addition, I have noticed that you have defined both your props and state as any. It is not recommended, as you will not stand to benefit from TypeScript's typechecking capabilities.

For instance, this is how you can define your interface.

interface ListState {
  users: Something[],
  message: string | null,
  checked: boolean,
}

Upvotes: 0

Related Questions