0

Most of the suggestions I've seen on various articles and StackOverflow answers suggest wrapping custom auth hooks such as:

import { useState, useEffect } from "react"
import { auth } from "./firebaseConfig"

function useFirebaseAuthentication() => {
  const [user, setUser] = useState(null);
  useEffect(() => {
    return auth.onAuthStateChanged((user) => {
      authUser ? setUser(user) : setUser(null)
    }
  }), [])
}

into a React Context. Sometimes the suggestion comes with claims such as "so you don't initialize Firebase multiple times" or "if you don't, onAuthStateChanged will be called multiple times." (This first warning came from a deleted answer on StackOverflow.)

However, I do not think the hook I wrote above is subject to multiple Firebase initializations or multiple calls to onAuthStateChanged. But I don't know enough to be sure. What I did do is put in a lot of console logs to watch what is happening. Specifically, I defined my hook in a "service" and logged everything:

// authService.js
import { useState, useEffect } from "react"
import { auth } from "./firebaseConfig"

// export of SignIn and SignOut components elided

export function useAuthentication() {
  const [user, setUser] = useState(null)
  useEffect(() => {
    console.log("Going to invoke onAuthStateChanged to set listener")
    const unlisten = auth.onAuthStateChanged((user) => {
      console.log("Auth hook: callback invoked")
      user ? setUser(user) : setUser(null)
    })
    return () => {
      console.log("Auth hook: unlistening")
      unlisten()
    }
  }, [])
  return user
}

Then I imported and used my hook and logged in and logged out a zillion times and watched the logs. I don't see any "extra" calls---my callback is called only when the auth state changes, and in fact my useEffect call also is invoked only when the auth state changes. As far as I can tell, nothing is being reinitialized or called too often.

// App.js
import { useEffect, useState } from "react"
import { SignIn, SignOut, useAuthentication } from "./authService"
// importing components, stylesheets, services, etc. elided

export default function App() {
  const user = useAuthentication()    // My custom hook call
  // Other state variables elided

  useEffect(() => {
    // Database and API stuff
  }, [user])

  console.log("Rendering app")
  return (
    <div className="App">
      { /* Code using user here */ }
    </div>
  )
}

Now, I am aware of react-firebase-hooks and I know how to use useAuthState, and I even looked at its source code! I see nothing about context there. I am trying to learn more about custom hooks and thought this would be a good exercise. And yet, using context seems to be common advice. So am I missing something? I guess my worry is, and hopefully someone with more React experience than me can answer, is:

Did I do anything wrong here? And perhaps I am only getting lucky because I am only using my custom hook in my App component and not elsewhere?

Ray Toal
  • 82,964
  • 16
  • 166
  • 221

0 Answers0