reactfire
reactfire copied to clipboard
Multiple function calls when using custom hook useCallableFunctionResponse
Short description
Using the useCallableFunctionResponse hook from reactfire causes the function to be called twice.
This might lead to undesired costs.
Version info
React: "^18" Firebase: "^10.0.0" ReactFire: "^4.2.3" Next: "14.1.0" Node: "^20"
Test case
Content of app/layout.tsx:
"use client"
import { Inter } from "next/font/google";
import "./globals.css";
import {FirebaseAppProvider} from "reactfire";
const inter = Inter({ subsets: ["latin"] });
const firebaseConfig = {
// your firebase config
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<FirebaseAppProvider firebaseConfig={firebaseConfig}>
<body className={inter.className}>{children}</body>
</FirebaseAppProvider>
</html>
);
}
Content of app/page.tsx:
"use client"
import {FunctionsProvider, useCallableFunctionResponse, useFirebaseApp} from "reactfire";
import {getFunctions} from "@firebase/functions";
import Test from "@/app/test";
const FUNCTIONS_REGION = 'your region';
export default function Home() {
const firebaseApp = useFirebaseApp();
const functions = getFunctions(firebaseApp, FUNCTIONS_REGION);
return (
<FunctionsProvider sdk={functions}>
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<Test />
</main>
</FunctionsProvider>
);
}
Content of app/test.tsx:
import {useCallableFunctionResponse} from "reactfire";
export default function Test() {
const responseObservable = useCallableFunctionResponse<any, string>('your_callable_function', {data: {}});
return (
<div>
{
responseObservable.status === 'loading' ?
<p>Loading ...</p> :
<p>{responseObservable.data}</p>
}
</div>
);
}
Steps to reproduce
- Run app (possible with
npm run dev) - Open app in browser
- In
Firebase console->Functionsselectyour_callable_functionand open theDetailed usage statsusing the 3 dot menu. This will open theGoogle Cloud Console->Function detailspage for the function. - Select the
Logstab and wait for the logs to load. - Check how many times the function was called when you refreshed the browser page.
Expected behavior
The function should be called once.
202x-xx-xx xx:xx:xx.731 xxx | POST 200 xxx B x ms xxxxxx https://region-project.cloudfunctions.net/your_callable_function
Actual behavior
The function is actually called twice.
202x-xx-xx xx:xx:xx.731 xxx | POST 200 xxx B x ms xxxxxx https://region-project.cloudfunctions.net/your_callable_function
202x-xx-xx xx:xx:xx.798 xxx | POST 200 xxx B x ms xxxxxx https://region-project.cloudfunctions.net/your_callable_function
Workaround
Using the httpsCallable from firebase/functions combined with the native hooks useEffect and useState solves the issue.
Content of app/test.tsx:
import {useFunctions} from "reactfire";
import {httpsCallable} from "firebase/functions";
import {useEffect, useState} from "react";
export default function Test() {
const functions = useFunctions();
const dataReader = httpsCallable<object, string>(functions, 'your_callable_function');
const [responseObservable, setResponseObservable] =
useState<{status: string, data: string}>({status: 'loading', data: ''});
useEffect(() => {
dataReader({})
.then((result) => {
setResponseObservable({status: 'success', data: result.data});
})
.catch((error) => {
setResponseObservable({status: 'error', data: error});
});
}, []);
return (
<div>
{
responseObservable.status === 'loading' ?
<p>Loading ...</p> :
<p>{responseObservable.data}</p>
}
</div>
);
}
try google react useeffect called twice