Reputation: 653
I have a provider component that sets the initial auth context from firebase-auth.
Everything works fine until I try to add persistence in the form of setting up an observer with onAuthStateChanged
. This checks for auth and I update my state via dispatch method.
But this is causing an infinite loop. I added an unsubscribe function call, but this makes no difference,
Can anyone advise? thanks
AuthContext.js
import React from "react";
import * as firebase from "firebase/app";
//firebaseauth reducer
import { firebaseAuth } from "../reducers/AuthReducer";
export const Auth = React.createContext();
const initialState = { user: {} };
export const AuthProvider = (props) => {
const [state, dispatch] = React.useReducer(firebaseAuth, initialState);
const value = { state, dispatch };
const unsubscribe = firebase.auth().onAuthStateChanged((user) => {
dispatch({
type: "HYDRATE_AUTH",
payload: user,
});
});
unsubscribe();
return <Auth.Provider value={value}>{props.children}</Auth.Provider>;
};
Upvotes: 6
Views: 2717
Reputation: 39
Thanks to @tomek-ch -- an alternate solution would be to prevent the re-render by storing the state (eg: keep the user bits in the component state) and then do not update the state if its already there (or the same).
In my case I just keep the user the first time, set a boolean state flag, and ignore subsequent events.
Upvotes: 0
Reputation: 157
What is happening is:
Unsubscribing doesn't help because the component keeps rerendering and adding a new listener every time.
We can tell the component to set the listener only once by using useEffect()
:
AuthContext.js
import React from "react";
import * as firebase from "firebase/app";
//firebaseauth reducer
import { firebaseAuth } from "../reducers/AuthReducer";
export const Auth = React.createContext();
const initialState = { user: {} };
export const AuthProvider = (props) => {
const [state, dispatch] = React.useReducer(firebaseAuth, initialState);
const value = { state, dispatch };
React.useEffect(() => {
firebase.auth().onAuthStateChanged((user) => {
dispatch({
type: "HYDRATE_AUTH",
payload: user,
});
});
}, []);
return <Auth.Provider value={value}>{props.children}</Auth.Provider>;
};
By providing an empty dependency array to useEffect()
, we tell it to run the callback only once, when the component initially renders, so the auth listener is set only once.
Upvotes: 4