我现在才深刻意识到 graphql-code-generator 的方便程度,第二部分

首先

今天依旧是使用前端React和后端Rails的…

因此,作为继续感受到 graphql-code-generator 的便利性的一部分,这次我们要做的是注册、删除等Mutation部分。

※构成与上次相同。

暂时按照Apollo官方的指导尝试一下

首先,我们将建立一个添加TODO的机制。

我已经准备好一个用于添加的文本框。您可以在这里输入数值,然后按下回车键即可执行添加处理。

スクリーンショット 2020-09-22 12.44.46.png
+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 ? (
...

我們已經建立了一個能夠通過輸入文字並按下回車鍵來執行附加處理的機制。

当按下回车键后,当重新加载页面时,您会看到TODO已被添加。

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

如果不刷新,无法看到动态,所以顺便进行额外处理,包括清除输入栏和重新获取列表信息的操作。

...
-  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 = "";
             }
           }}

在类型相关方面,没有发生任何错误。

我会试着更加精细地制作,使其变得更加便利。

我会设置一个机制,让其在没有任何输入的情况下执行注册处理,并出现错误。

我已经向 Todo 添加了验证错误字段,并确保以下的值包含在响应中。

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

另外,我们添加了一个用于判断处理结果是否正常的result字段(布尔类型)。

如果结果为true,则创建一个机制,重新加载列表;如果结果为false,则使用alert显示错误信息。

 const ADD_TODO = gql`
   mutation addTodo($name: String!) {
     addTodo(input: { name: $name }) {
       todo {
         id
         name
+        errors {
+          field
+          error
+        }
      }
+      result
    }
  }
`;
   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}`);
+        });
+      }
+    },
+  });

因为未声明”errors”的类型,所以发生了错误。

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

我将提供类型声明。

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

错误已经解决,验证错误消息可以通过弹窗进行确认。

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

我打算像上一次一样,使用 graphql-code-generator,把它做得更加优雅一些。

使用graphql-code-generator

首先从设置开始。

除了查询(queries)目录外,还创建一个用于变更(mutations)的目录,并将本次创建的查询(query)存储在其中。

-documents: ./graphql/queries/*.graphql
+documents:
+  - ./graphql/mutations/*.graphql
+  - ./graphql/queries/*.graphql
mutation addTodo($name: String!) {
  addTodo(input: { name: $name }) {
    todo {
      id
      name
      errors {
        field
        error
      }
    }
    result
  }
}

当你运行`yarn generate`命令后,将会在`src/types.d.ts`中新增了一个名为`useAddTodoMutation`的方法,用于添加TODO事项。

我們試著使用 useAddTodoMutation 重新編寫添加處理。

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

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

哦?出错了。

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

听说 data 可能是 null 或 undefined。

考虑到这些情况,我会稍作修改。

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}`);
      });
    }
  },
});

尽管稍微需要调整,但由于不再需要查询和声明类型,代码变得更加清晰。

让我们同样尝试实现删除处理。

虽然有点凌乱,但是我们将在每个TODO旁边准备一个删除按钮,以便能够执行删除操作。

スクリーンショット 2020-09-27 23.50.47.png
mutation delTodo($id: ID!) {
  delTodo(input: { id: $id }) {
    todo {
      id
    }
  }
}

为了确定需要删除的待办事项,需要获取ID。

在 graphql/queries/todos.graphql 中,我们只获取了待办事项的名称,所以需要修改以获取其id。

 query todos {
   todos {
+    id
     name
   }
 }

运行`yarn generate`后,`useDelTodoMutation`函数就在`src/types.d.ts`文件中生成了。

使用useDelTodoMutation函数,使得在点击删除按钮时能够执行删除操作。

-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 } })}>削除</button></li>)}

我成功地实现了一种简便的删除处理方法。

add-del.gif

最终

由于在一个屏幕或组件上实现了列表获取、添加处理和删除处理,所以这个文件可能会稍微有点庞大。

可以將型定義和查詢信息定義在另一個文件中,然後使用import也可以,但如果是手動操作並且涉及多個人的話,我認為管理工作可能會逐漸變得繁瑣不堪。

我认为,如果按照graphql-code-generator的规则进行开发,这个问题可能会得到解决。

由于我們以一個相對小規模的實例進行了實施,所以在導入過程中並沒有太多遇到障礙的地方。我認為這是一個非常好的工具。

bannerAds