cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.

[Solved] Running a mutation from an event handler triggers hook errors

I'm using GrandStack, and grandstack has inferred an UpdateUser mutation. Unfortunately, there are NO examples of using mutations in the Grandstack Starter inside a deeper function, and mutations are almost never mentioned in forum posts.

I initialize some variables via query and I have a dropdown box that needs to trigger a Mutation, and a function that should trigger the mutation.

It seems to me that while I can run queries from my functions with no problem, I can't get a mutation to run (rules of hooks) despite all my efforts. The mutation SET_DOMAIN runs fine in Playground.

It IS inside of a function. I've tried instead of { } in const { setDomain } = useMutation .

What am I missing?

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
import React, { Fragment, useContext } from "react";
import ChooserCompetency from "./ChooserCompetency";
import ChooserPlan from "./ChooserPlan";
import { SITREP, GET_DOMAINS, SET_DOMAIN } from "../queries";
import { useQuery, useMutation } from "@apollo/react-hooks";
import { graphql } from "react-apollo";

function ChooserDomain(props) {
  const { domainId } = useQuery(SITREP);

  const { loading, data, error } = useQuery(GET_DOMAINS, {
    variables: {
    }
  });

function UpdateSelectedDomain(domain) {
    localStorage.setItem("SelectedPlan", "-1");
    localStorage.setItem("SelectedDomain", domain);
    localStorage.setItem("SelectedMilestone", "-1");

    // FIXME: Write this as a mutation.
    const [setDomain] = useMutation(SET_DOMAIN, {
      variables: {
        user: "1",
        Name: "Matthew",
        chosenDomain: domain
      }
    });
  }

  return (
    <div>
      {loading && !error && <p>Loading...</p>}
      {error && !loading && <p>Error</p>}
      {data && !loading && !error && (
        <Fragment>
          <div className="gravity-right">
            <select
              id="DomDrop"
              name="progress"
              value={domainId}
              onChange={e => UpdateSelectedDomain(e.currentTarget.value)}>
              <option key="-1" value="-1">
                Not Selected
              </option>
              {data.Domain.map(dom => (
                <option key={dom.id} value={dom.id}>
                  {dom.label}
                </option>
              ))}
            </select>
            {parseInt(domainId) >= 0 && props.subElement === "chooseComp" && (
              <ChooserCompetency domainId={domainId} />
            )}
            {parseInt(domainId) >= 0 && props.subElement === "choosePlan" && (
              <ChooserPlan subElement="none" domainId={domainId} />
            )}
          </div>
        </Fragment>
      )}
    </div>
  );
}

export default ChooserDomain;

export const SET_DOMAIN = gql`
  mutation UpdateDomain(
    $user: String!
    $chosenDomain: String!
    $Name: String!
  ) {
    UpdateUser(
      id: $user
      chosenDomain: $chosenDomain
      chosenDomain: "-1"  \\\This was the main problem.
      chosenPlan: "-1"
      chosenMilestone: "-1"
      Name: $Name
    ) {
      chosenDomain
    }
  }
`;

EDIT. For future readers, I removed the duplicated chosenDomain variable in the mutation, and used the mutation format suggested by Boots and the docs. I just needed confirmation that I was getting the syntax here to encourage me to look into the secondary "Bad Request" error.

3 REPLIES 3

MuddyBootsCode
Graph Steward

Take a look at the docs for @apollo/react-hooks https://www.apollographql.com/docs/react/api/react-hooks/#usemutation
In their example you'd write this as:

const [setDomain] = useMutation(SET_DOMAIN)

and then call it in your component like:

setDomain({variables: {
        user: "1",
        Name: "Matthew",
        chosenDomain: domain
      }})

I'm also not sure based on their example that you need to have graphql imported but there may be some other use I'm not seeing. Give their way a shot and see it works for you.

Thanks again, Boots!

In some configurations I was getting the hook error, and in other configurations I was getting a 400 error.

After you confirmed the right syntax, I returned back to the 400 error. I looked into the 400 error and realized that a field was accidentally duplicated in the current copy of my mutation. I fixed my request and it works now!

MuddyBootsCode
Graph Steward

No worries. I've got an application that makes a lot of use of mutations, etc. and it took awhile to figure out how to stack them before the latest version of apollo hooks.

Nodes 2022
Nodes
NODES 2022, Neo4j Online Education Summit

All the sessions of the conference are now available online