Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple function calls when using custom hook useCallableFunctionResponse #606

Open
VBota1 opened this issue Jan 27, 2024 · 1 comment
Open

Comments

@VBota1
Copy link

VBota1 commented Jan 27, 2024

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 -> Functions select your_callable_function and open the Detailed usage stats using the 3 dot menu.
    This will open the Google Cloud Console -> Function details page for the function.
  • Select the Logs tab 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>
      );
    }
@JCBsystem
Copy link

try google react useeffect called twice

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants