错误在Graphiql上正确显示,但未在React前端返回给Apollo Client

时间:2019-11-10 01:52:22

标签: reactjs graphql react-apollo apollo-client graphiql

我故意将名称字段留空(""),以便可以在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
  }
}

react组件中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();

1 个答案:

答案 0 :(得分:0)

这个问题很基本。但是对于那些陷入同样愚蠢陷阱的人。 。 。 确保对提交事件运行preventDefault()。默认操作会在提交时重新加载仅运行getEmployeesQuery的页面。这就是addEmployeeMutation上不存在任何内容的原因。 preventDefault强制addEmployeeMutation返回错误。

还要确保在尝试/捕获中捕获错误。它们不包含在道具中。 (谢谢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]);
    }
  };