错误在 Graphiql 上正确显示但未在反应前端返回给 Apollo 客户端

Errors show correctly on Graphiql but not returned to Apollo Client in react front end

我特意将名称字段留空 (""),以便我可以在 GraphQL 后端测试我的自定义错误表单检查。 使用 Graphiql,错误数组显示得很好。 (String! 只能阻止 null,不能阻止 ""。)

谁能解释为什么错误没有到达实际的反应组件以及如何解决这个问题?

PS:一旦字段被填满,变异就会完美地工作。它也更新为新创建的记录。

Graphiql 查询窗格

mutation addEmployee(
  $name: String!
  $position: String!
) {
  addEmployee(name: $name, position: $position) {
    name
    position
  }
}

query getEmployees {
  employees {
    _id
    name
    position
    createdAt
  }
}

Graphiql 查询变量:注意空的 name 字段。

{
  "name": "",
  "position": "CEO",
}

Graphiql 结果窗格 - 按预期工作。

{
  "errors": [
    {
      "message": "Field cannot be empty",
      "statusCode": 400
    }
  ],
  "data": {
    "addEmployee": null
  }
}

反应组件中 getEmployeesQuery 的控制台日志显示:

called: true
error: undefined
fetchMore: ƒ (fetchMoreOptions)
loading: false
networkStatus: 7
refetch: ƒ (variables)
employees: (16) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
startPolling: ƒ (pollInterval)
stopPolling: ƒ ()
subscribeToMore: ƒ (options)
updateQuery: ƒ (mapFn)
variables: {}

这是我的突变:

const Mutation = new GraphQLObjectType({
  name: "Mutation",
  fields: {
    addEmployee: {
      type: EmployeeType,
      args: {
        name: { type: new GraphQLNonNull(GraphQLString) },
        position: { type: new GraphQLNonNull(GraphQLString) },
      },
      resolve(parent, args) {
        let employee = new Employee({
          name: args.name,
          position: args.position,
        });
        let errors = [];

        try {
          if (!args.name) {
            errors.push("name");
          }
          if (errors.length) throw new Error(errorName.INVALID_FIELD);
          return employee.save();
        } catch (err) {
          throw new GraphQLError(err.message);
        }
      }
    }
  }
});

这是我的组件:

const Employees = ({
  getEmployeesQuery: { employees, loading, errors },
  addEmployeeMutation
}) => {

  const [state, setState] = useState({
    name: "",
    position: "",
  });

  const showEmployee = id => () => {
    const employee = store.state.employees.find(v => v._id === id);
  };

  const handleChange = name => evt => {
    setState({ ...state, [name]: evt.target.value });
  };

  const addEmployee = () => {
    addEmployeeMutation({
      variables: {
        name: state.name,
        position: state.position,
      },
      refetchQueries: [{ query: getEmployeesQuery }]
    });
  };

  return (
    <div className={styles.root}>
      <h2>Employees</h2>
      <div className={styles.listContainer}>
        <header>
          <div>Employee Name</div>
          <div>Position</div>
        </header>
        <div className={styles.list}>
          {!loading ? (
            employees.map(v => (
              <Employee
                key={v._id}
                showEmployees={showEmployees(v._id)}
                position={v.position}
                id={v._id}
              />
            ))
          ) : (
            <Loader />
          )}
        </div>
      </div>
      {(errors || []).map((error, i) => (
        <div>{error.message}</div>
      ))}
      <EmployeeForm
        fields={state}
        handleChange={handleChange}
        submit={addEmployee}
      />
    </div>
  );
};

Employees.propTypes = {
  classes: PropTypes.object,
  route: PropTypes.string,
  name: PropTypes.string
};

export default compose(
  getEmployeesQuery,
  addEmployeeMutation
)(Employees);

查询次数:

import { gql } from "apollo-boost";
import { graphql } from "react-apollo";

export const getEmployeesQuery = graphql(
  gql`
    {
      employees {
        _id
        createdAt
        name
        position
      }
    }
  `,
  { name: "getEmployeesQuery" }
);

export const addEmployeeMutation = graphql(
  gql`
    mutation(
      $name: String!
      $position: String!
    ) {
      addEmployee(
        name: $name
        position: $position
      ) {
        _id
        createdAt
        name
        position
      }
    }
  `,
  { name: "addEmployeeMutation" }
);

这篇文章越来越长了,但这是最后一篇了。承诺。 这是 index.js!

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";

import "./index.css";
import App from "./layout/App";
import * as serviceWorker from "./serviceWorker";

import { ApolloProvider } from "react-apollo";
import { ApolloClient } from "apollo-client";
import { createHttpLink } from "apollo-link-http";
import { InMemoryCache } from "apollo-cache-inmemory";

const httpLink = createHttpLink({
  uri: "http://localhost:4000/graphql"
});

const client = new ApolloClient({
  link: httpLink,
  cache: new InMemoryCache()
});

ReactDOM.render(
  <ApolloProvider client={client}>
      <BrowserRouter>
        <App />
      </BrowserRouter>
  </ApolloProvider>,
  document.getElementById("root")
);

serviceWorker.register();

问题很简单。但是对于那些运行同样陷入愚蠢陷阱的人。 . . 请确保您 运行 preventDefault() 提交事件。默认操作在提交时重新加载页面,仅 运行 getEmployeesQuery。这就是 addEmployeeMutation 上什么都不存在的原因。 preventDefault 强制 addEmployeeMutation 到 return 并出现错误。

还要确保在 try/catch 中捕获错误。它们不包括在道具中。 (谢谢Long Nguyen)。

const [errors, setErrors] = useState([]);

const addEmployee = async evt => {
    evt.preventDefault(); // This fixed it!
    try {
      await addEmployeeMutation({
        variables: {
          name: state.name,
          position: state.position,
        },
        refetchQueries: [{ query: queries.getEmployeesQuery }]
      });
    } catch (e) {
      setErrors([e.message]);
    }
  };