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.
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.
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.
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.
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.
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`.
Like last time, I will use graphql-code-generator
to clean it up.
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.
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:
Although it is a rough idea, a delete button is provided next to each TODO so that the delete process can be executed.
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:
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