简体   繁体   中英

React Hook "useState" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function

I'm new in React Frontend developing. I'm trying to add a temporary drawer to my Material-UI NavBar. I've add a drawer in my code:

class Navbar extends Component {
    render() {
        const { authenticated } = this.props;
        const [open, setOpen] = useState(false);
        const handleDrawer = () =>{
           setOpen(true)
        }
        return (
            <AppBar position="fixed">
                <Toolbar className="nav-container">
                    {authenticated ? (
                        <Fragment>
                            <IconButton edge="start" onClick={handleDrawer} >
                                <Menu/>
                            </IconButton>
                            <Drawer
                                anchor='left'
                                open={open}
                                onClose={()=> setOpen(false)}
                                >
                                    <h3> Drawer</h3>
                            </Drawer>
                            <NewPost/>
                            <Link to="/">
                                <MyButton tip="Home">
                                    <HomeIcon color = "disabled"/>
                                </MyButton>
                            </Link>
                            <Link to="/chats">
                                <MyButton tip="Chats">
                                    <ChatIcon color = "disabled"/>
                                </MyButton>
                            </Link>
                            <Notifications />
                        </Fragment>
                        

                    ):(
                        <Fragment>
                            <Button color="inherit" component={Link} to="/login">Login</Button>
                            <Button color="inherit" component={Link} to="/signup">Singup</Button>
                            <Button color="inherit" component={Link} to="/">Home</Button>
                            {/* <Button color="inherit" component={Link} to="/user">Profile</Button>*/}
                        </Fragment>
                    )}
                </Toolbar>
            </AppBar>

            
        )
    }
}

Navbar.propTypes = {
    authenticated:  PropTypes.bool.isRequired
}

const mapStateToProps = state =>({
    authenticated: state.user.authenticated
})

export default connect(mapStateToProps)(Navbar)

But this error appeared:

React Hook "useState" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function

So, I've create a constructor to handle this (before render):

constructor(props) {
    super(props);
    this.state = {
      open: false
    };
  }

And when I want to change the state, I've use:

this.setState({ open: true })

But, when I triggered the Drawer (clicking the button),It does not open. What can I do?

The state hook (useState) is available with functional React Components, but in your case you are using a Class component. Functional React components normally don't have states out of the box, but useState is a new feature that will let you work around that

You can either change this to functional component, or keep it as a class component and use the state differently Eg:

  • .this.state.open instead of !open and
  • this.setState({open: false}) instead of setOpen(false)

https://reactjs.org/docs/hooks-state.html

Change this line const [open, setOpen] = useState(false); to this.state = { open: false };

and when setting to true just call this.setState({ open: this.state.open: true })

You have to use a functional component. Currently your component is a class component, so instead you should have something like:

const Navbar = (props) => {
  const { authenticated } = props;
  const [open, setOpen] = useState(false);
  const handleDrawer = () =>{
    setOpen(true)
  }
    
  return (
    <AppBar position="fixed">...</AppBar>
  );
};

I also noticed that your class component has the state parts defined in the render method. When using class components, state should be defined in the constructor instead, otherwise your state will be overwritten every render.

What about functional component instead of class component? Functional component is recommended as you know. I think it's easy to code and it improves performance.

const Navbar = () => {
     //useState, define functions here
     return (//the same as render method of your class component) 
}

use function Navbar(props) in place of class Navbar extends Component

Its because, There is a rule that: React Hook "useState" cannot be called in a class component eg class Navbar extends Component . React Hooks must be called in a React function component eg function Navbar(props) or a custom React Hook function

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM