在 GraphQL 查询中传递自定义变量

Pass Custom Variables In GraphQL Query

我有一个 UpdateUserPage 可以根据传递的输入变量的数量以不同的方式调用突变,例如:

只更新名字

    mutation{
            updateUser(email: "d@d.com",
            input: {firstName:"check"}){id}
            }

名字和姓氏都已更新:

    mutation{
            updateUser(email: "d@d.com",
            input: {firstName:"check", lastName: "new"}){id}
            }

现在在我的代码中查询:

export const UPDATE_USER = gql`
  mutation UpdateUser($email: String!, $firstName: String, $lastName: String) {
    updateUser(
      email: $email
      input: { firstName: $firstName, lastName: $lastName }
    ) {
      id
      firstName
    }
  }
`;

我想要的:

我想更改我的表单,如果用户只输入 firstName 而将 lastName 字段留空, 那么只有 firstName 应该更新,这意味着应该使用第一种类型的查询,而 lastName 应该保持在调用 mutation 之前的状态。

现在发生了什么:

例如,以前的名字是 HELLO,姓氏是 WORLD。现在,我将 firstName 更新为 CHECK 并将 lastName 选项留空。所以当它 returns 值时,它应该 return CHECK 作为 firstName 和未修改的 WORLD 作为 lastName。但是,现在,它显示 lastName 为未定义。 如果我检查资源,我会看到:

{"operationName":"UpdateUser","variables":{"email":"c@c.com","firstName":"Final"},"query":"mutation UpdateUser($email: String!, $firstName: String, $lastName: String) {\n updateUser(email: $email, input: {firstName: $firstName, lastName: $lastName}) {\n id\n firstName\n __typename\n }\n}\n"} Looks like the lastName is still being passed in the mutation.

这意味着 lastName 仍在突变中使用。所以,我需要一种方法将自定义变量传递到我的查询中:

$input : Object!无效。

这是我整个页面的代码:

export default function UpdateUserPage() {
  const [isSubmitted, setIsSubmitted] = useState(false);
  const [isUpdated, setIsUpdated] = useState(false);

  const [updateUser] = useMutation(UPDATE_USER);
  let submitForm = (
    email: string,
    firstName: string,
    lastName: string,
  ) => {
    setIsSubmitted(true);

    if (email && (firstName || lastName || phoneNumber)) {
      const vars:any = {
        email
      };
    if( firstName !== ''){
      vars.firstName = firstName}
      if( lastName !== ''){
        vars.lastName = lastName}

      updateUser({
        variables: vars})
        .then(({ data }: any) => {
          setIsUpdated(true);
          console.log(updateUser);
          console.log('FN: ', data.updateUser.firstName);
          console.log('LN: ', data.updateUser.lastName);
        })
        .catch((error: { message: string }) => {
          setIsUpdated(false);
        });
    }
  };

  return (
    <div>
      <Formik
        initialValues={{
          firstName: '',
          lastName: '',
          email: '',
          phoneNumber: '',
        }}
        onSubmit={(values, actions) => {
          setTimeout(() => {
            alert(JSON.stringify(values, null, 2));
            actions.setSubmitting(false);
          }, 1000);
        }}
        validationSchema={schema}>
        {props => {
          const {
            values: { firstName, lastName, email, phoneNumber },
            errors,
            touched,
            handleChange,
            isValid,
            setFieldTouched,
          } = props;
          const change = (name: string, e: FormEvent) => {
            e.persist();
            handleChange(e);
            setFieldTouched(name, true, false);
          };
          return (
            <div className="main-content">
              <form
                style={{ width: '100%' }}
                onSubmit={e => {
                  e.preventDefault();
                  submitForm(email, firstName, lastName);
                }}>
                <div>
                  <TextField
                    variant="outlined"
                    margin="normal"
                    id="email"
                    name="email"
                    helperText={touched.email ? errors.email : ''}
                    error={touched.email && Boolean(errors.email)}
                    label="Email"
                    value={email}
                    onChange={change.bind(null, 'email')}
                  />
                  <br></br>
                  <TextField
                    variant="outlined"
                    margin="normal"
                    id="firstName"
                    name="firstName"
                    helperText={touched.firstName ? errors.firstName : ''}
                    error={touched.firstName && Boolean(errors.firstName)}
                    label="First Name"
                    value={firstName}
                    onChange={change.bind(null, 'firstName')}
                  />
                  <br></br>
                  <TextField
                    variant="outlined"
                    margin="normal"
                    id="lastName"
                    name="lastName"
                    helperText={touched.lastName ? errors.lastName : ''}
                    error={touched.lastName && Boolean(errors.lastName)}
                    label="Last Name"
                    value={lastName}
                    onChange={change.bind(null, 'lastName')}
                  />
                  <CustomButton
                    text={'Update User Info'}
                  />
                </div>
              </form>
            </div>
          );
        }}
      </Formik>
    </div>
  );
}

编辑:

来自架构:

input: UpdateUserInput!
input UpdateUserInput {
  email: String
  firstName: String
  lastName: String
  phoneNumber: String
}

现在,我已经这样做了:

interface UpdateUserInput {
  email: String
  firstName: String
  lastName: String
  phoneNumber: String
}

export const UPDATE_USER = gql`
  mutation UpdateUser($email: String!, $input : UpdateUserInput) {
    updateUser(
      email: $email
      input: $input
    ) {
      id
      firstName
    }
  }
`;

但是,当我提交表单时,我仍然得到这个错误:

GraphQL error: The variable `input` type is not compatible with the type of the argument `input`.
Expected type: `UpdateUserInput`.

可能是因为我仍在通过 vars 从我的主要 UpdateUserPage。我该如何改变它?

$input 变量的类型可以是 updateUserinput 参数的类型。如果您没有自己编写 GraphQL 架构,则需要查看 API 的文档或 GraphiQL/GraphQL 游乐场界面以确定要使用的类型。

对每个字段($firstName$lastName)使用单个变量 ($input) 而不是多个变量是首选的处理方式。也就是说,您的查询没有任何问题。您当前查询:

mutation ($email: String!, $firstName: String, $lastName: String) {
  updateUser(
    email: $email
    input: { firstName: $firstName, lastName: $lastName }
  ){
    id
  }
}

与变量 {"email": "c@c.com", "firstName": "Final"} 等价于

mutation ($email: String!, $input: WhateverYourInputTypeIs) {
  updateUser(
    email: $email
    input: $input
  ){
    id
  }
}

{"email": "c@c.com", "input": { "firstName": "Final"} }.

在这两种情况下,传递给服务器端解析器的参数是相同的。如果你在突变运行后得到错误的 lastName 值,那么这是解析器如何处理它接收到的参数的问题。

您可能需要修改您的界面,以便不需要这些字段。

interface UpdateUserInput {
  email?: String
  firstName?: String
  lastName?: String
  phoneNumber?: String
}

通过向字段添加问号,您可以将它们设为可选,这样您就可以一次传递一个或多个。