jeddeloh / rescript-apollo-client

ReScript bindings for the Apollo Client ecosystem
MIT License
126 stars 18 forks source link

Useing ApolloClient.useMutation() #51

Closed idkjs closed 4 years ago

idkjs commented 4 years ago

I am trying to use onCompleted on useMutation. Maybe this is equivalent to some other method in the library?

This compiles but doesnt not look right and cause an invalid hook call error.

  let loginFn = () => {
    let variables: LoginUser.t_variables = {email: "me@me.com"};
    let _ =
      ApolloClient.React.useMutation(
        ~mutation=(module LoginUser),
        ~onCompleted=
          ({login}) => {
            Js.log2("TOKEN_LOGIN", login);
            let token =
              login.token
              ->Belt.Option.map(t => t)
              ->Belt.Option.getWithDefault("");
            Dom.Storage.(localStorage |> setItem("token", token));
            Dom.Storage.(localStorage |> setItem("userId", login.id));
          },
        LoginUser.serializeVariables(variables)->ignore,
        // variables
      )->ignore;
    ();
  };

error:

Uncaught 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
See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.`

Being called like this since its the only way i can get it to compile:

module LoginUser = [%graphql
  {|
  mutation LoginUser($email: String!) {
    login(email: $email) {
      id
      token
    }
  }
|}
];
[@react.component]
let make = () => {
  let loginFn = () => {
    let variables: LoginUser.t_variables = {email: "me@me.com"};
    let _ =
      ApolloClient.React.useMutation(
        ~mutation=(module LoginUser),
        ~onCompleted=
          ({login}) => {
            Js.log2("TOKEN_LOGIN", login);
            let token =
              login.token
              ->Belt.Option.map(t => t)
              ->Belt.Option.getWithDefault("");
            Dom.Storage.(localStorage |> setItem("token", token));
            Dom.Storage.(localStorage |> setItem("userId", login.id));
          },
        variables->ignore,
      )->ignore;
    ();
  };
  <div>
    <p>
      <button onClick={_e => loginFn()}>
        "ApolloClient.React.useMutation"->React.string
      </button>
    </p>
  </div>;
};

Thank you in advance! Super work here!

Also, how is the above function different from the following which works but doesnt have onCompleted as an option?

let logLogin = _ =>
  Client.instance.mutate(~mutation=(module LoginUser), {email: "me@me.com"})
  ->Promise.get(
      fun
      | {data: Some({login}), error: None} => {
          Js.log2("TOKEN_LOGIN", login);
          let token =
            login.token
            ->Belt.Option.map(t => t)
            ->Belt.Option.getWithDefault("");

          Dom.Storage.(localStorage |> setItem("token", token));
          Dom.Storage.(localStorage |> setItem("userId", login.id));
        }
      | {error} => Js.log2("Error: ", error),
    );
jeddeloh commented 4 years ago

It's number 2: "you might be breaking the rules of hooks". In the error it says "Hooks can only be called inside of the body of a function component", but here you're using a hook in the body of a plain function.

jeddeloh commented 4 years ago

And to answer how the two things are different, one is a hook and one is a method on the client (both do essentially the same thing). The hook has other args you can pass to it like onCompleted for some rare use-case, but ultimately, both executing the mutation that comes out of the hook and calling the method on the client return a promise. You would use the resolution of the promise to know when it is completed. I've never really had a use-case for useMutation, it feels like burden to me. I always do client.mutate.

jeddeloh commented 4 years ago

Also, please note you are not actually executing your mutation in your hook example. Please check out the apollo docs on how to use useMutation: https://www.apollographql.com/docs/react/data/mutations/

idkjs commented 4 years ago

Thank you for taking the time to educate me, brother. Peace to you.