Nikhilesh Chhetri
Nikhilesh Chhetri

Reputation: 29

Why am I receiving this Invalid Hooks Call error?

Hi I am trying to create a function that is called when you click add to cart on a product page. This function is in a separate file and is imported to the product page and is called onClick. However, I receive this error that says Invalid Hooks Call. What am I doing wrong?

import {AuthContext} from '../context/auth'
import gql from 'graphql-tag'
import {Button} from 'semantic-ui-react'
import {useMutation} from '@apollo/react-hooks'

const AddtoCart = (id) => {
    console.log(id)                                         //id gets logged into the console here. 
    
    const [errors,setErrors] = useState({})                 ////shows error right here <<
   
    const {user} = useContext(AuthContext);                 
    const[addtoCart,{loading}] = useMutation(ADDTOCART,{
        update(_,result){
            //TODO: remove this alert
            
            alert('success')
        },
        onError(err){
           alert('error')
            
        },
        variables:{
            productID:id
        }

    })
    if(user){
        addtoCart(id)
    }
    else{
      if(localStorage.getItem('cart')){
        cart = JSON.parse(localStorage.getItem('cart'));
        cart.unshift(id);
        localStorage.removeItem('cart');    
        localStorage.setItem('cart', JSON.stringify(cart));

      }else{
          var cart = [id];
          localStorage.setItem('cart', JSON.stringify(cart));
      }

    }
   
}


const ADDTOCART = gql`
    mutation addtoCart($productID: ID!){
        addtoCart(productID: $productID)
    }


`

export default AddtoCart;```

Upvotes: 1

Views: 53

Answers (1)

PileUpOKpull
PileUpOKpull

Reputation: 311

It looks like you are exporting AddToCart and calling that from the onClick? This will not work because useState is being called from the wrong context. The difference is that this function isn't a React component itself. Calling the function inside of a React component isn't sufficient, hook calls need to happen either in a custom hook (called in a component) or in a component.

If you want to have the function you're using modify state, then you can pass the setErrors function to it as an argument, and have the call to useState inside of the component that renders the button. You should do the same thing with the useMutation and useContext.

I would recommend lifting the hooks into the wrapping component, and just pass user to the related logic:

function addToCart(user, id) {
  if(user){
    addtoCart(id)
  }
  else {
    if(localStorage.getItem('cart')) {
      cart = JSON.parse(localStorage.getItem('cart'));
      cart.unshift(id);
      localStorage.removeItem('cart');    
      localStorage.setItem('cart', JSON.stringify(cart));
    } 
    else {
      var cart = [id];
      localStorage.setItem('cart', JSON.stringify(cart));
    }
  }
}

This function could be called in the onClick so long as you move the hooks calls into the scope of the container

I definitely recommend giving the rules of hooks a read. It does a better job than me explaining why you can't have a hook in a nested function.

Upvotes: 1

Related Questions