如何将具有多个对象的状态数组作为参数传递给graphql突变?

凡妮莎文图拉

我正在创建一个允许用户创建列表的应用程序(所有数据都存储在 mongoDB 上并通过 Apollo GraphQL 访问);每个列表都有一个属性 listItems,这是一个存储列表中所有项目的数组。

目前,我现在可以移动 listItems 并将它们 setState 放在通过 state.items 访问的数组中,如本视频所示列表移动由react-sortable-hoc 库中的组件控制

我遇到的问题是采用 listItems 的 state.items 数组并使用突变让 state.items 数组替换数据库中后端相应的 list.listItems 数组。

我相信我可能没有正确设置输入 ListItems 的 typeDefs(我收到错误:Mutation.editListItems(listItems:) 的类型必须是输入类型但得到:[ListItem]!。所以我将其更改为输入而不是类型这可能是一个问题?)

最后,我尝试在下面的 RankList 功能组件中调用 editListItems 突变(包含在 RankList.js 中)“onChange”。我不确定问题出在哪里以及在移动物品时,似乎没有调用突变。请提供建议(让我知道是否应该包含更多信息)!

总的来说,我想知道以下是否可能是一个问题:

  • editListItems 的 typeDef 是否正确实现?
  • 在这里使用 onChange 是正确的吗?
  • 我是否正确调用了突变(在 RankList 组件中)?
  • 我是否在 editListItems 突变(在 RankList 组件中)正确传递 state.items ?

typeDefs.js

const { gql } = require("apollo-server");

//schema

module.exports = gql`
  type List {
    id: ID!
    title: String!
    createdAt: String!
    username: String!
    listItems: [ListItem]!
    comments: [Comment]!
    likes: [Like]!
    likeCount: Int!
    commentCount: Int!
  }
  type ListItem {
    id: ID!
    createdAt: String!
    username: String!
    body: String!
  }
  input ListItems {
    id: ID!
    createdAt: String!
    username: String!
    body: String!
  }
  type Comment {
    id: ID!
    createdAt: String!
    username: String!
    body: String!
  }
  type Like {
    id: ID!
    createdAt: String!
    username: String!
  }
  type User {
    id: ID!
    email: String!
    token: String!
    username: String!
    createdAt: String!
  }
  input RegisterInput {
    username: String!
    password: String!
    confirmPassword: String!
    email: String!
  }
  type Query {
    getLists: [List]
    getList(listId: ID!): List
  }
  type Mutation {
    register(registerInput: RegisterInput): User!
    login(username: String!, password: String!): User!
    createList(title: String!): List!
    editListItems(listId: ID!, listItems: ListItems!): List!
    deleteList(listId: ID!): String!
    createListItem(listId: ID!, body: String!): List!
    deleteListItem(listId: ID!, listItemId: ID!): List!
    createComment(listId: ID!, body: String!): List!
    deleteComment(listId: ID!, commentId: ID!): List!
    likeList(listId: ID!): List!
  },
  type Subscription{
    newList: List!
  }
`;

list.js(解析器)

async editListItems(_, { listId, listItems }, context) {
      console.log("editListItems Mutation activated!");
      const user = checkAuth(context);

      const list = await List.findById(listId);

      if (list) {
        if (user.username === list.username) {
          list.listItems = listItems;
          await list.save();
          return list;
        } else {
          throw new AuthenticationError("Action not allowed");
        }
      } else {
        throw new UserInputError("List not found");
      }
    },

RankList.js(上面视频中显示的列表组件)

import React, { useContext, useEffect, useRef, useState } from "react";
import gql from "graphql-tag";
import { useQuery, useMutation } from "@apollo/react-hooks";
import { Form } from "semantic-ui-react";
import moment from "moment";

import { AuthContext } from "../context/auth";
import { SortableContainer, SortableElement } from "react-sortable-hoc";
import arrayMove from "array-move";
import "../RankList.css";
import { CSSTransitionGroup } from "react-transition-group";

const SortableItem = SortableElement(({ value }) => (
  <li className="listLI">{value}</li>
));

const SortableList = SortableContainer(({ items }) => {
  return (
    <ol className="theList">
      <CSSTransitionGroup
        transitionName="ranklist"
        transitionEnterTimeout={500}
        transitionLeaveTimeout={300}
      >
        {items.map((item, index) => (
          <SortableItem
            key={`item-${item.id}`}
            index={index}
            value={item.body}
          />
        ))}
      </CSSTransitionGroup>
    </ol>
  );
});

function RankList(props) {
  const listId = props.match.params.listId;
  const { user } = useContext(AuthContext);
  const listItemInputRef = useRef(null);

  const [state, setState] = useState({ items: [] });
  const [listItem, setListItem] = useState("");

  const { loading, error, data } = useQuery(FETCH_LIST_QUERY, {
    variables: {
      listId,
    },
    onError(err) {
      console.log(err.graphQLErrors[0].extensions.exception.errors);
      // setErrors(err.graphQLErrors[0].extensions.exception.errors);
    }
  });

  useEffect(() => {
    if (data && data.getList && data.getList.listItems) {
      setState(() => ({ items: data.getList.listItems }));
    }
  }, [data]);

  // const [state, setState] = useState({ items: data.getList.listItems });

  const [submitListItem] = useMutation(SUBMIT_LIST_ITEM_MUTATION, {
    update() {
      setListItem("");
      listItemInputRef.current.blur();
    },
    variables: {
      listId,
      body: listItem,
    },
  });

  const [editListItems] = useMutation(EDIT_LIST_ITEMS_MUTATION, {
    variables: {
      listId,
      listItems: state.items,
    },
  });

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error..</p>;

  function deleteListCallback() {
    props.history.push("/");
  }

  function onSortEnd({ oldIndex, newIndex }) {
    setState(({ items }) => ({
      items: arrayMove(items, oldIndex, newIndex),
    }));
    //THIS MAY BE WHERE THE ISSUE LIES
    editListItems();
  }

  let listMarkup;
  if (!data.getList) {
    listMarkup = <p>Loading list...</p>;
  } else {
    const {
      id,
      title,
      createdAt,
      username,
      listItems,
      comments,
      likes,
      likeCount,
      commentCount,
    } = data.getList;

    listMarkup = user ? (
      <div className="todoListMain">
        <div className="rankListMain">
          <div className="rankItemInput">
            <h3>{title}</h3>
            <Form>
              <div className="ui action input fluid">
                <input
                  type="text"
                  placeholder="Choose rank item.."
                  name="listItem"
                  value={listItem}
                  onChange={(event) => setListItem(event.target.value)}
                  ref={listItemInputRef}
                />
                <button
                  type="submit"
                  className="ui button teal"
                  disabled={listItem.trim() === ""}
                  onClick={submitListItem}
                >
                  Submit
                </button>
              </div>
            </Form>
          </div>
          <SortableList
            items={state.items}
            onSortEnd={onSortEnd}
            helperClass="helperLI"
          />
        </div>
      </div>
    ) : (
      <div className="todoListMain">
        <div className="rankListMain">
          <div className="rankItemInput">
            <h3>{props.title}</h3>
          </div>
          <SortableList
            items={listItems}
            onSortEnd={onSortEnd}
            helperClass="helperLI"
          />
        </div>
      </div>
    );
  }

  return listMarkup;
}

const EDIT_LIST_ITEMS_MUTATION = gql`
  mutation($listId: ID!, $listItems: ListItems!) {
    editListItems(listId: $listId, listItems: $listItems) {
      id
      listItems {
        id
        body
        createdAt
        username
      }
    }
  }
`;

const SUBMIT_LIST_ITEM_MUTATION = gql`
  mutation($listId: ID!, $body: String!) {
    createListItem(listId: $listId, body: $body) {
      id
      listItems {
        id
        body
        createdAt
        username
      }
      comments {
        id
        body
        createdAt
        username
      }
      commentCount
    }
  }
`;

const FETCH_LIST_QUERY = gql`
  query($listId: ID!) {
    getList(listId: $listId) {
      id
      title
      createdAt
      username
      listItems {
        id
        createdAt
        username
        body
      }
      likeCount
      likes {
        username
      }
      commentCount
      comments {
        id
        username
        createdAt
        body
      }
    }
  }
`;

export default RankList;
xadm

问题太多......简要:

const [state, setState] = useState({ items: [] });

不要setState在钩子中使用......这是误导,setState用于类组件。

使用一些有意义的名称 fe itemList

const [itemList, setItemList] = useState( [] ); // just array

调整查询结果保存:

useEffect(() => {
  if (data && data.getList && data.getList.listItems) {
    // setState(() => ({ items: data.getList.listItems }));
    setItemList( data.getList.listItems );
  }
}, [data]);

调整可排序更新处理程序:

const onSortEnd = ({oldIndex, newIndex}) => {
  // this.setState(({items}) => ({
  //  items: arrayMove(items, oldIndex, newIndex),
  // }));
  const newListOrder = arrayMove( itemList, oldIndex, newIndex);
  // console.log("array sorted", newListOrder );
  // update order in local state
  // kind of optimistic update
  setItemList( newListOrder );
  // update remote data
  editListItems( {
    variables: {
      listId,
      listItems: newListOrder,
    }
  });

onSortEnd处理程序传递给可排序的:

<SortableList items={itemList} onSortEnd={onSortEnd} />

Mutation 应该有update处理程序(writeQuery- 阅读文档)来强制查询更新/重新渲染。在这种情况下不是必需的(数组已经按可排序排序,我们正在更新本地数组,它将重新渲染)但它应该在这里(突变失败/错误 - 处理error来自useMutation)。

类型很好......但是api 检测到错误的类型......数组中的每个项目都包含__typename属性......迭代newListOrder元素(fe using .map())并删除__typename它应该在console.log(newListOrder).

在操场 ( /graphiql) 中尝试后端/API ...在编码前端之前尝试使用变量进行突变比较网络请求/响应详细信息。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何将具有多个覆盖的 valueOf 方法作为参数传递给方法

如何将多个游标传递给具有多个节点 ID 的单个 GitHub GraphQL 查询?

我如何将数组作为args列表传递给C中具有可变数量参数的函数

如何将对象数组作为参数传递给模板

如何将具有多种类型的参数作为参数传递给 Typescript 中的函数?

Kotlin:如何将具有可变参数的函数作为参数传递给其他函数

如何将多个(未知数)对象(作为参数)传递给函数 - Java Script

如何将JSON对象作为参数传递给url?

React,Graphql - 如何将变量传递给突变

如何将JSON数组作为参数传递给URL

如何将数组作为单独的参数传递给方法

如何将Swift数组作为参数传递给线程?

具有X类,如何将X作为模板参数传递给自身?

将复杂的参数传递给GraphQL突变

如何将数组(未知长度)的所有元素作为单独的参数传递给函数?

将对象作为参数传递给GraphQL突变(graphql-request)

如何将具有多个参数的函数传递给python parallel.futures.ProcessPoolExecutor.map()?

如何将具有多个参数的URL传递给URL?

如何将多个对象属性作为参数传递?

无论如何将数组作为多个参数传递?

如何将具有相同查询参数的值的数组传递给路由器?

GraphQL Ruby:如何编写具有多个参数的DRY突变?

如何将具有多个参数的函数传递给期望只有一个参数的函数的子例程?

GraphQL-将枚举值直接传递给突变作为参数吗?

是否可以将对象作为变量传递给graphQL突变?

如何将数组作为参数传递?

如何将 unique_ptr 对象作为参数传递给作为库的类

将模拟对象作为JUnit参数传递给具有参数的测试方法

我可以将数组作为参数传递给Java中具有可变参数的方法吗?