Cloud Functions

The @react-query-firebase/functions package provides hooks for calling Callable Cloud Functions.

Installation

npm i --save @react-query-firebase/functions

Usage

The package provides hooks for calling data as a query (useFunctionsQuery) or as a mutation (useFunctionsMutation).

To use the hooks, export your Functions instance, e.g:

import { initializeApp } from 'firebase/app';
import { getFunctions } from 'firebase/functions';

const firebase = initializeApp({
  ...
});

export const functions = getFunctions(firebase);

useFunctionsQuery

The useFunctionsQuery hook can be used to query a Callable Cloud Function using the useQuery hook.

import React from "react";
import { useFunctionsQuery } from "@react-query-firebase/functions";
import { functions } from "../firebase";

function Product({ id }: { id: number }) {
  // Functions has a deployed `getProduct` callable function
  const query = useFunctionsQuery(["product", id], functions, "getProduct", {
    id,
  });

  if (query.isLoading) {
    return <div>Loading...</div>;
  }

  return <h1>{query.data.name}</h1>;
}

TypeScript users can provide a custom RequestData and ResponseData types:

type RequestData = {
  // Product ID
  id: number;
};

type ResponseData = Product;

const productId = 123;

const query = useFunctionsQuery<RequestData, ResponseData>(
  ["product", productId],
  functions,
  "getProduct",
  {
    id: productId,
  }
);

if (query.isSuccess) {
  const product: Product = query.data;
}

The hook also accepts an HttpsCallableOptions] argument, which can be provided to the request:

useFunctionsQuery(
  ["product", id],
  functions,
  "getProduct",
  {
    id,
  },
  {
    timeout: 5000,
  }
);

Since the library wraps React Query, we can also hook onto the useQuery hook options. For example, to select a specific part of the data and be notified on success:

// Specify the data returned is instead a string
const query = useFunctionsQuery<RequestData, ResponseData, string>(
  ["product", id],
  functions,
  "getProduct",
  {
    id,
  },
  undefined,
  {
    // Select the `name` property fron the response.
    select(product: ResponseData): string {
      return product.name;
    },
    // Log on success.
    onSuccess(name: string): void {
      console.log("Got product: ", name);
    },
  }
);

if (query.isSuccess) {
  return <div>Product Name: {query.data}</div>;
}

useFunctionsMutation

The useFunctionsMutation hooks can be used to query a Callable Cloud Function on demand using the useMutation hook.

import React from "react";
import { useFunctionsQuery } from "@react-query-firebase/functions";
import { functions } from "../firebase";

function Product({ id }: { id: number }) {
  const mutation = useFunctionsMutation(functions, "updateProduct");

  return (
    <button
      disabled={mutation.isLoading}
      onClick={() => {
        mutation.mutate({
          id,
          name: "A new product name!",
        });
      }}
    >
      Edit Product
    </button>
  );
}

TypeScript users can provide a custom RequestData and ResponseData types:

type RequestData = {
  // Product ID
  id: number;
  // New product name
  name: string;
};

type ResponseData = Product;

const mutation useFunctionsMutation<RequestData, ResponseData>(...);

// The mutate/mutateAsync calls are now typed.
mutation.mutate({
  id: 123,
  name: "A new product name!",
})

The hook also accepts an HttpsCallableOptions] argument, which can be provided to the request:

useFunctionsMutation(functions, "updateProduct", {
  timeout: 5000,
});

Since the library wraps React Query, we can also hook onto the useMutation hook options. For example, to be notified on success or error:

type RequestData = {
  // Product ID
  id: number;
  // New product name
  name: string;
};

type ResponseData = Product;

function Product({ id }: { id: string }) {
  const mutation = useFunctionsMutation<RequestData, ResponseData>(
    functions,
    "updateProduct",
    undefined,
    {
      onSuccess(product: ResponseData) {
        console.log("Product updated! ", product);
      },
      onError(error) {
        console.error("Something went wrong updating the product! ", error);
      },
    }
  );

  return (
    <button
      disabled={mutation.isLoading}
      onClick={() => {
        mutation.mutate({
          id,
          name: "A new product name!",
        });
      }}
    >
      Edit Product
    </button>
  );
}