I am keenly aware of the convenience of graphql-code-generator, part 2

Introduction

Today and today, front React + back Rails ...

So, this time, as a continuation of I am keenly aware of the convenience of graphql-code-generator, Mutation such as registration and deletion etc. I will do the part of.

For the time being, try according to Apollo's formula

First, we will create a mechanism to add TODO.

I have prepared an additional text field. Enter a value here and enter will execute additional processing.

スクリーンショット 2020-09-22 12.44.46.png

src/App.tsx


+import { gql, useMutation } from "@apollo/client";

...

+const ADD_TODO = gql`
+  mutation addTodo($name: String!) {
+    addTodo(input: { name: $name }) {
+      todo {
+        id
+        name
+      }
+    }
+  }
+`;

 const App = () => {
   const { loading, data } = useTodosQuery();
+  const [addTodo] = useMutation(ADD_TODO);

...
         </p>
+        <input
+          type="text"
+          onKeyPress={(e) => {
+            if (e.key === "Enter") {
+              addTodo({ variables: { name: e.currentTarget.value } });
+            }
+          }}
+        />
         {loading ? (
...

We have created a mechanism that allows you to enter characters and perform additional processing with Enter.

If you reload the screen after pressing enter, you can see that TODO has been added.

スクリーンショット 2020-09-22 14.18.50.png

Since you can't understand the movement without reloading, in addition to the additional processing, clear the input field and re-acquire the list information.

src/App.tsx


...
-  const { loading, data } = useTodosQuery();
+  const { loading, data, refetch } = useTodosQuery();
-  const [addTodo] = useMutation(ADD_TODO);
+  const [addTodo] = useMutation(ADD_TODO, {
+    update() {
+      refetch();
+    },
+  });

...

           onKeyPress={(e) => {
             if (e.key === "Enter") {
               addTodo({ variables: { name: e.currentTarget.value } });
+              e.currentTarget.value = "";
             }
           }}

No particular error occurred regarding type.

Try to make it a little more convenient

Without inputting anything, execute the registration process and put in a mechanism that causes an error.

Added a validation error field to Todo to include the following values in the response:

"errors":[{"field":"name","error":"blank"}]

We also added a result field (Boolean) to see if the result of the process was successful.

If result is true, reload the list, and if false, create a mechanism to display error information with ʻalert`.

src/App.tsx


 const ADD_TODO = gql`
   mutation addTodo($name: String!) {
     addTodo(input: { name: $name }) {
       todo {
         id
         name
+        errors {
+          field
+          error
+        }
      }
+      result
    }
  }
`;

src/App.tsx


   const [addTodo] = useMutation(ADD_TODO, {
-    update() {
-      refetch();
-    },
-  });
+    update(
+      _cache,
+      {
+        data: {
+          addTodo: {
+            todo: { errors },
+            result,
+          },
+        },
+      }
+    ) {
+      if (result) {
+        refetch();
+      } else {
+        errors.forEach(({ field, error }) => {
+          alert(`${field} ${error}`);
+        });
+      }
+    },
+  });

An error occurred because the type of ʻerrors` was not declared.

スクリーンショット 2020-09-22 16.10.28.png

I will declare the type.

type ValidationErrorType = {
  field: string;
  error: string;
};
-errors.forEach(({ field, error }) => {
+errors.forEach(({ field, error }: ValidationErrorType) => {
  alert(`${field} ${error}`);
});

The error has been resolved and validation error messages can now be seen with ʻalert`.

スクリーンショット 2020-09-22 16.15.46.png

Like last time, I will use graphql-code-generator to clean it up.

use graphql-code-generator

First from the settings

Create a directory for mutations separately from queries, and store the query created this time there.

codegen.yml


-documents: ./graphql/queries/*.graphql
+documents:
+  - ./graphql/mutations/*.graphql
+  - ./graphql/queries/*.graphql

graphql/mutations/add_todo.graphql


mutation addTodo($name: String!) {
  addTodo(input: { name: $name }) {
    todo {
      id
      name
      errors {
        field
        error
      }
    }
    result
  }
}

Now when you run yarn generate, you have ʻuseAddTodoMutation for adding TODO to src / types.d.ts`.

Let's rewrite the additional process using ʻuseAddTodoMutation`.

-import { useTodosQuery } from "./types.d";
+import { useTodosQuery, useAddTodoMutation } from "./types.d";

+const [addTodo] = useMutation(ADD_TODO, {
+const [addTodo] = useAddTodoMutation({

Hmm? An error has occurred.

スクリーンショット 2020-09-22 21.01.17.png

Apparently data may be null or ʻundefined`.

With that in mind, I'll rewrite it a bit.

const [addTodo] = useAddTodoMutation({
  update(_cache, { data }) {
    const result = data?.addTodo?.result || false;
    const errors = data?.addTodo?.todo.errors || [];

    if (result) {
      refetch();
    } else {
      errors.forEach((e) => {
        if (e) alert(`${e.field} ${e.error}`);
      });
    }
  },
});

It needed a bit of tweaking, but it's refreshing in terms of source because it no longer requires queries and type declarations: thumbsup:

Try to implement the deletion process in the same way

Although it is a rough idea, a delete button is provided next to each TODO so that the delete process can be executed.

スクリーンショット 2020-09-27 23.50.47.png

graphql/mutations/del_todo.graphql


mutation delTodo($id: ID!) {
  delTodo(input: { id: $id }) {
    todo {
      id
    }
  }
}

You need to get an ID to identify the TODO to be deleted.

In graphql / queries / todos.graphql, only the name of TODO is acquired, so modify it so that it takes ʻid`.

graphql/queries/todos.graphql


 query todos {
   todos {
+    id
     name
   }
 }

Running yarn generate created the ʻuseDelTodoMutation function in src / types.d.ts`.

Use this ʻuseDelTodoMutation to enable the delete process to be executed when the delete` button is clicked.

src/App.tsx


-import { useTodosQuery, useAddTodoMutation } from "./types.d";
+import { useTodosQuery, useAddTodoMutation, useDelTodoMutation } from "./types.d";


+const [delTodo] = useDelTodoMutation({
+  update() {
+    refetch();
+  }
+});


-{data && data.todos.map(({ name }, i) => <li key={i}>{name}</li>)}
+{data && data.todos.map(({ id, name }, i) => <li key={i}>{name}<button onClick={() => delTodo({ variables: { id } })}>Delete</button></li>)}

I was able to easily implement the deletion process: tada:

add-del.gif

Finally

Since list acquisition, addition processing, and deletion processing are implemented on one screen and component, it may have become a slightly large file.

It may be possible to define the type definition and query information in another file and use ʻimport`, but I think that management may become complicated gradually if there are multiple people manually.

I thought that if this was developed according to the rules of graphql-code-generator in a sense, that problem would be solved.

This time, I implemented it as a fairly small example, so I didn't feel any obstacles to the introduction. I think it's an LGTM tool: thumbs up:

Recommended Posts

I am keenly aware of the convenience of graphql-code-generator, part 2
I want to be aware of the contents of variables!
I want to expand the clickable part of the link_to method
Qualify only part of the text
I read the source of ArrayList I read
I read the source of Integer
I read the source of Long
I read the source of Short
I read the source of Byte
I read the source of String
I investigated the internal processing of Retrofit
[day: 5] I summarized the basics of Java
I want to output the day of the week
I checked the place of concern of java.net.URL # getPath
I understood the very basics of character input
Image registration? Of course I can't (can) ~ part2 ~
[Java] The confusing part of String and StringBuilder
I compared the characteristics of Java and .NET
I want to var_dump the contents of the intent
I touched on the new features of Java 15
I tried using the profiler of IntelliJ IDEA
I checked the number of taxis with Ruby
Try the free version of Progate [Java I]
The part I was addicted to in "Introduction to Ajax in Java Web Applications" of NetBeans