Vishal Shetty
Vishal Shetty

Reputation: 1668

How to run GraphQL mutation query using useSWR hook?

I have a MongoDB database hosted in MongoDB Atlas, I am using MongoDB Atlas RealM as well to create GraphQL schemas.

I am consuming the GraphQL API in react js application created using Next JS.

I am also using useSWR hooks to fetch the data. With useSWR I don't have any issues fetching the data but when it comes to running the mutation queries using useSWR I am unable to get it done.

There is no proper documentation on how to do it.

Here is my code

//@ts-nocheck
import React, { useContext, useEffect, useState } from "react";
import { Drawer, Button, Form, Input, Select, Cascader } from "antd";
import { TRANSACTION_TYPES } from "queries/transactionTypes";
import { LIST_CATEGORIES } from "queries/categories";
import { FINANCIAL_ACCOUNTS } from "queries/financialAccounts";
import { PAYMENT_MODES } from "queries/paymentModes";
import { INSERT_TRANSACTION } from "queries/transaction";
import useSWR from "swr";
import { AuthContext } from "context/AuthContext";

const AddTransaction = () => {
  const userId = useContext(AuthContext);
  const { Option } = Select;
  const [visible, setVisible] = useState(true);
  const [txnType, setTxnType] = useState();

  const { data: txnTypeData } = useSWR(TRANSACTION_TYPES);
  const { data: categories } = useSWR(LIST_CATEGORIES);
  const { data: accounts } = useSWR([FINANCIAL_ACCOUNTS, { user_id: userId }]);
  const { data: modes } = useSWR(PAYMENT_MODES);
  const { data: transaction, mutate } = useSWR(INSERT_TRANSACTION);
  if (txnTypeData && txnTypeData.error) {
    return <p>An error occurred: ${txnTypeData.error}</p>;
  }

  const txnTypes = txnTypeData ? txnTypeData.data.transaction_types : null;
  console.log("transaction", transaction);
  const options = categories
    ? categories.data.categories.map((cat) => {
        let children = [];
        cat.subcategories.forEach((subcat) =>
          children.push({
            value: subcat,
            label: subcat,
          })
        );

        return {
          value: cat.name,
          label: cat.name,
          children,
        };
      })
    : null;

  const showDrawer = () => {
    setVisible(true);
  };

  const onClose = () => {
    setVisible(false);
  };

  const handleTxnType = (value) => {
    setTxnType(value);
  };

  const onFinish = (values) => {
    const txnData = {};
    txnData.date = new Date();
    txnData.user_id = userId;
    txnData.category = values.category[0];
    txnData.subcategory = values.category[1];
    txnData.type = values.txntype;
    txnData.amount = values.amount;
    txnData.description = values.description;
    txnData.mode = values.mode;
    txnData.account = {
      account_name: "ICICI bank",
      bank_name: "ICICI bank",
      type: "savings",
    };

    console.log("txnData", txnData);
    mutate([INSERT_TRANSACTION, { data: txnData }]);
  };

  return (
    <>
      <Button type="primary" onClick={showDrawer}>
        Open
      </Button>
      <Drawer
        title="Add Transaction"
        placement="right"
        onClose={onClose}
        visible={visible}
      >
        <Form
          layout={"vertical"}
          initialValues={{ remember: true }}
          onFinish={onFinish}
          autoComplete="off"
        >
          <Form.Item label="Txn Type" name="txntype">
            <Select onChange={handleTxnType}>
              {txnTypes &&
                txnTypes.map((type) => (
                  <Option key={type._id} value={type.type}>
                    {type.type}
                  </Option>
                ))}
            </Select>
          </Form.Item>
          <Form.Item label="Cateogry / Subcategory" name="category">
            <Cascader options={options} placeholder="Please select" />
          </Form.Item>
          <Form.Item label="Description" name="description">
            <Input placeholder="Proper description of the expense" />
          </Form.Item>
          <Form.Item label="Amount(₹)" name="amount">
            <Input placeholder="Amount" />
          </Form.Item>
          {txnType !== "self transfer" && (
            <Form.Item label="Account" name="account">
              <Select>
                {accounts &&
                  accounts.data.financial_accounts.map((acc) => (
                    <Option key={acc._id}>{acc.name}</Option>
                  ))}
              </Select>
            </Form.Item>
          )}
          {txnType === "self transfer" && (
            <>
              <Form.Item label="From Account" name="from_account">
                <Select>
                  {accounts &&
                    accounts.data.financial_accounts.map((acc) => (
                      <Option key={acc._id}>{acc.name}</Option>
                    ))}
                </Select>
              </Form.Item>
              <Form.Item label="To Account" name="to_account">
                <Select>
                  {accounts &&
                    accounts.data.financial_accounts.map((acc) => (
                      <Option key={acc._id}>{acc.name}</Option>
                    ))}
                </Select>
              </Form.Item>
            </>
          )}
          <Form.Item label="Mode" name="mode">
            <Select defaultValue="gpay">
              {modes &&
                modes.data.payment_modes.map((mode) => (
                  <Option key={mode._id} value={mode.name}>
                    {mode.name}
                  </Option>
                ))}
            </Select>
          </Form.Item>
          <Form.Item>
            <Button type="primary" htmlType="submit">
              Submit
            </Button>
          </Form.Item>
        </Form>
      </Drawer>
    </>
  );
};

export default AddTransaction;


The problem is with this query

  const { data: transaction, mutate } = useSWR(INSERT_TRANSACTION);

Here is the mutation query

export const INSERT_TRANSACTION = `
mutation INSERT_TRANSACTION($data: TransactionInsertInput!) {
  insertOneTransaction(data: $data) {
    _id
  }
}
`;

I am calling the mutate function in the onFinish() like this

mutate([INSERT_TRANSACTION, { data: txnData }]);

But, I am getting an error message

message: "Variable \"$data\" of required type \"TransactionInsertInput!\" was not provided."

Not sure, why I am getting this error, as I have already been passing the $data to the query through mutate.

Someone, please shed some light on this, what I am doing wrong here?

Upvotes: 2

Views: 667

Answers (1)

Pablote
Pablote

Reputation: 5093

useSWR is only used to query data, and it's triggered immediatly when the component mounts, you don't want that for a data insert or update. The fact that a mutate fn is returned it's only to revalidate, or rerun said query.

Instead use useSWRMutation. This hook returns a trigger fn that you can execute the moment you want your insert to run. Or simpler yet, just don't use SWR for mutations.

Upvotes: 0

Related Questions