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