1

I have a component which has a logic for following and unfollowing people. On button click, a function should be called which incudes the query logic. But when I press the button, it gives me "error: invalid hook call, hooks and only be called inside of the body of the function component"

These are my 2 functions for following and unfollowing logic:

function onFollowingClick() {
        const {isLoading: deleteFollowerLoading} = useQuery(["deleteFollower", myFollowerId], () => {
            deleteFollower(myFollowerId)
        })
        console.log("following call")
}

function onFollowClick() {
    const {isLoading:createFollowerLoading} = useQuery("createFollower",
        createFollower()
    )

    console.log("follower call")
}

This is the button where I have called the functions, and it is inside a map function, you can see it in onclick:

return (
    <div className={root}>
        <div className={body}>
                {                       
                    myFollowers && myFollowings && !followerLoading && (
                        followersData.map((e) => {
                        return(<>
                            <div className="data">
                            <Grid  templateColumns="repeat(2, 1fr)" width="100%" alignContent="center">
                            <GridItem w="100%" >
                            <Flex 
                            mt="10px">
                                <Avatar
                                size={isTabletOrMobile ? "xs" : "sm"}
                                src={e.requested_profile.s3PicURL}
                                />
                                
                                <Text
                                w="100%"
                                wrap="off"
                                ml="5px"
                                isTruncated
                                fontSize={isTabletOrMobile ? "sm" : "md"}
                                >
                                    {e.requested_profile.Userlink}
                                </Text>
                            </Flex>
                            </GridItem>
                            <GridItem>
                                <Flex justifyContent="flex-end">
                                <Button
                                w="100px"
                                h="30px"
                                mt="8px"
                                onClick = { () => {
                                    if(myFollowings.includes(e.requested_profile.Userlink)){
                                        onFollowingClick()
                                    }
                                    else{
                                        onFollowClick()
                                    }
                                } }
                                variant={myFollowings.includes(e.requested_profile.Userlink) ? "outline" : "solid"}
                                width={isTabletOrMobile ? "50px" : "60px"}>
                                    {
                                        myFollowings.includes(e.requested_profile.Userlink) ? "Following" : "Follow"
                                    }
                                </Button>
                                </Flex>
                            </GridItem>
                            </Grid>
                            </div>
                            </>
                        ) 
                    })
                    )
                }
        </div>
    </div>

    
)

please tell me how do I solve this error.

1 Answer 1

2

There are several issues here:

  1. You cannot use hooks anywhere unless it's at a top component level (https://reactjs.org/docs/hooks-overview.html#rules-of-hooks).

  2. You using react-query and trying to mutate state using useQuery. This hook is used to fetch the data. If you want to do mutations, you should use useMutation hook. But please note these hooks should be at a top level too, you cannot call it from a click handler as we call regular functions.

So, your steps are:

  • define useMutation hooks with the callbacks and the backend interaction logic
  • when you click buttons you call mutationFollow.mutate({ id: item.id })
  • to invalidate your state after mutations you should use onSuccess callback:
onSuccess: () => {
   queryClient.invalidateQueries('followers')
},

One of options to do what you want could be:

const queryClient = useQueryClient()

const Component = () => {
  const { isLoading, data: followers } = useQuery('followers')
  const mutationFollow = useMutation(
    follower => {
      return axios.post('/follow', follower)
    },
    {
      onSuccess: () => {
        queryClient.invalidateQueries('followers')
      },
    },
  )

  const mutationUnfollow = useMutation(
    follower => {
      return axios.post('/unfollow', follower)
    },
    {
      onSuccess: () => {
        queryClient.invalidateQueries('followers')
      },
    },
  )

  if (isLoading) {
    return <div>Loading...</div>
  }

  return followers.map(item => (
    <div>
      <button
        onClick={() => {
          mutationFollow.mutate({ id: item.id })
        }}
      >
        Follow
      </button>
      <button
        onClick={() => {
          mutationUnfollow.mutate({ id: item.id })
        }}
      >
        Unfollow
      </button>
    </div>
  ))
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.