youngdev
youngdev

Reputation: 607

Unable to use useState in class component React.js

I am trying to create constants in react as follows:

const [firstFocus, setFirstFocus] = React.useState(false);
const [lastFocus, setLastFocus] = React.useState(false);

The constants are being used in the code as follows:

import React, { Component } from 'react'
import axios from 'axios'

import {
    Button,
    Card,
    CardHeader,
    CardBody,
    CardFooter,
    Form,
    Input,
    InputGroupAddon,
    InputGroupText,
    InputGroup,
    Container,
    Col
} from "reactstrap";

class PostForm extends Component {
    constructor(props) {
        super(props)

        this.state = {
            email: '',
            password: ''
        }
    }

    changeHandler = (e) => {
        this.setState({ [e.target.name]: e.target.value })
    }

    submitHandler = (e) => {
        e.preventDefault()
        console.log(this.state)
        axios.post('https://jsonplaceholder.typicode.com/posts', this.state)
            .then(response => {
                console.log(response)
            })
            .catch(error => {
                console.log(error)
            })
    }


    render() {
        const { email, password } = this.state
        **const [firstFocus, setFirstFocus] = React.useState(false);
        const [lastFocus, setLastFocus] = React.useState(false);**
        return (

            <div>
                <Col className="ml-auto mr-auto" md="4">
                    <Card className="card-login card-plain">
                        <Form onSubmit={this.submitHandler} className="form">
                            <CardHeader className="text-center">
                            </CardHeader>
                            <CardBody>
                                <InputGroup
                                    className={
                                        "no-border input-lg"
                                    }
                                >
                                    <InputGroupAddon addonType="prepend">
                                        <InputGroupText>
                                            <i className="now-ui-icons ui-1_email-85"></i>
                                        </InputGroupText>
                                    </InputGroupAddon>
                                    <Input
                                        placeholder="Email"
                                        type="text"
                                        name="email"
                                        value={email}
                                        onChange={this.changeHandler}
                                    // onFocus={() => setFirstFocus(true)}
                                    // onBlur={() => setFirstFocus(false)}
                                    ></Input>
                                </InputGroup>
                                <InputGroup
                                    className={
                                        "no-border input-lg"
                                    }
                                >
                                    <InputGroupAddon addonType="prepend">
                                        <InputGroupText>
                                            <i className="now-ui-icons ui-1_lock-circle-open"></i>
                                        </InputGroupText>
                                    </InputGroupAddon>
                                    <Input
                                        placeholder="Password"
                                        type="password"
                                        name="password"
                                        value={password}
                                        onChange={this.changeHandler}
                                    // onFocus={() => setLastFocus(true)}
                                    // onBlur={() => setLastFocus(false)}
                                    ></Input>
                                </InputGroup>
                            </CardBody>
                            <CardFooter className="text-center">
                                <Button
                                    block
                                    className="btn-round"
                                    color="info"
                                    type="submit"
                                    size="lg"
                                >
                                    Get Started
                    </Button>
                                <div className="pull-right">
                                    <h6>
                                        <a
                                            className="link"
                                            href="#pablo"
                                            onClick={e => e.preventDefault()}
                                        >
                                            Need Help?
                        </a>
                                    </h6>
                                </div>
                            </CardFooter>
                        </Form>
                    </Card>
                </Col>
            </div>
        )
    }
}

export default PostForm

However, when I try to do this I get the following error:

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

I created another constant there for email and password and it worked just fine so I'm not sure why my useState constants aren't working. Any help or guidance is much appreciated as I am very new to react. Thanks!

Upvotes: 38

Views: 94416

Answers (6)

koffster
koffster

Reputation: 418

This worked for me, I just declared index & setIndex as follows. Might be a dirty hack, but hey 🤷‍♂️


    render(){
      const index = this.state.index;
      const setIndex = (params) => this.setState({index: params});
      return {
        <Tab value={index} onChange={setIndex}>
          <Tab.Item title="recent" />
          <Tab.Item title="favorite" />
          <Tab.Item title="cart" />
        </Tab>

        <TabView value={index} onChange={setIndex} >
          <TabView.Item style={{ backgroundColor: 'red', width: '100%' }}>
            <Text h1>recent</Text>
          </TabView.Item>
          <TabView.Item style={{ backgroundColor: 'blue', width: '100%' }}>
            <Text h1>Favorite</Text>
          </TabView.Item>
          <TabView.Item style={{ backgroundColor: 'green', width: '100%' }}>
            <Text h1>Cart</Text>
          </TabView.Item>
        </TabView>
      }
    }

Upvotes: 2

GorvGoyl
GorvGoyl

Reputation: 49180

Another way is to use hooks in a functional component and then import this functional component in a class component.

export default class LikeButton extends Component {
  render() {
    return <Like />;
  }
}

function Like() {
  const [like, setLike] = useState(100);
  const [liked, toggleLike] = useState(false);
  const handleLike = () => {
    if (liked == false) {
      setLike(like + 1);
      toggleLike(true);
    } else {
      setLike(like - 1);
      toggleLike(false);
    }
  };
  return (
    <>
      <div>
        <h2>Like Button</h2>
        <button
          onClick={() => handleLike()}
          className={`like-button ${liked == true ? "liked" : ""}`}
        >
          Like | <span className="likes-counter">{like}</span>
        </button>
      </div>
    </>
  );
}

Upvotes: 0

ESI
ESI

Reputation: 2047

In react, we have 2 ways to build components: classes and functions.

DOCS

Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class.

Using the State Hook:

import React, { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

Equivalent Class Example:

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

Upvotes: 84

Nadiar Syaripul
Nadiar Syaripul

Reputation: 504

Officially you can't use hook on class component. But of course there is some trick if you want use useState on class component

example, you can't do this

class Example extends React.Component {

  _renderCounter = () => {
    //
    // YOU CAN'T DO THIS
    // REACT WONT ALLOW YOU
    //
    const [count, setCount] = useState(0);
    return <div>{ count }</div>
  }

  render() {
    return(
      <div>{ this._renderCounter() }</div>
    );
  }
}

But, with small trick you can do this. React will allow you

class Example extends React.Component {

  _renderCounter = () => () => {
    const [count, setCount] = useState(0);

    return <div>{ count }</div>
  }

  render() {
    const MyInlineHook = this._renderCounter();

    return(
      <div><MyInlineHook /></div>
    );
  }
}

With this trick, you can access to this and props of the class component. :)

Upvotes: 13

Hasan Zahran
Hasan Zahran

Reputation: 1442

Hooks can only be used in functional components, you're using class component.

For more information and how to implement it please check this article Link

Upvotes: 2

Edgar Cuarezma
Edgar Cuarezma

Reputation: 125

You are trying to use useState, which is a React hook, inside a class component. This won't work. Hooks can only be used in functional components.

Upvotes: 5

Related Questions