Firebase v9 onAuthStateChanged only fires on initialization

Viewed 690

I am in the process of migrating my React app to firebase v9. Currently I am working on the auth context.
The problem is that the onAuthStateChanged() callback only fires once during initialization, but not on signInWithEmailAndPassword() or signOut(). Refreshing the page shows that the auth state has indeed changed, only the listener won't fire.

Have there been any changes in v9 that might be causing this or am I missing something?

Context
AuthContext.jsx

export const AuthContext = createContext(undefined);

export const AuthWrapper = ({ children }) => {
  const [user, setUser] = useState(undefined);

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (currentUser) => {
      setUser(currentUser);
    });
    return unsubscribe();
  }, []);

  return <AuthContext.Provider value={user}>{children}</AuthContext.Provider>;
};

Usage
index.jsx

import { AuthWrapper } from "./context/AuthContext";

ReactDOM.render(
  <React.StrictMode>
    <AuthWrapper>
      <App />
    </AuthWrapper>
  </React.StrictMode>,
  document.getElementById("root")

App.jsx

import { useContext } from "react";
import { AuthContext } from "./context/AuthContext";

function App() {
  const user = useContext(AuthContext);

  return <>{user ? <Dashboard /> : <Landing />}</>
}
1 Answers

I think your clean up effect setup is wrong.

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (currentUser) => {
      setUser(currentUser);
    });
    // to fix:
    return () => { unsubscribe() }
    // equivalent to:
    return unsubscribe
    // but not:
    return unsubscribe(); // it cleans up immediately after the first call
  }, []);
Related