'supabase onAuthStateChange not re-rendering useEffect
I have the following custom hook useAuth, in which I am having a supabase.auth.onAuthStateChange event listener.
export const useAuth = () => {
const [session, setSession] = useState(supabase.auth.session());
const signOutUser = async () => {
await supabase.auth.signOut();
useAuthStore.setState({
user: null,
});
setSession(null);
};
useEffect(() => {
console.log({ session });
}, [session]);
supabase.auth.onAuthStateChange(async (event, session) => {
if (session) {
const { error: fetchError, data } = await fetchUser(session);
if (fetchError) {
await signOutUser();
} else {
if (data.length === 0) {
setSession(session);
} else {
setSession(session);
}
}
} else {
setSession(null);
}
});
return session;
};
Now I am using react-router-dom@6 for routing.
This is my App.js file
function RequireAuth({ children }) {
const session = useAuth();
let location = useLocation();
console.log({ children, session });
if (!session) {
return <Navigate to="/login" state={{ from: location }} replace />;
}
return children;
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route
path="/"
element={
<RequireAuth>
<Home />
</RequireAuth>
}
/>
<Route path="/login" element={<Login />} />
<Route
path="/servers"
element={
<RequireAuth>
<Servers />
</RequireAuth>
}
/>
<Route path="*" element={<FourNotFour />} />
</Routes>
</BrowserRouter>
);
}
Now my question is within useAuth i have a line like console.log({ session }); which prints out session object, but this line is getting printed only once, even after the auth state has changed to logged in, and setSession got executed. And thus on App.js file the method RequireAuth keep on executing only once thus after login my app is still on the login page, it's not re-routing to Home page
Why is that?
Solution 1:[1]
You should put your auth listener inside of a useEffect so you can react to changes.
onAuthStateChange returns the listener, which you can unsubscribe from in the useEffect's cleanup function:
useEffect(() => {
const { data: authListener } = supabase.auth.onAuthStateChange(
async (event, session) => {
if (session) {
const { error: fetchError, data } = await fetchUser(session);
if (fetchError) {
await signOutUser();
} else {
if (data.length === 0) {
setSession(session);
} else {
setSession(session);
}
}
} else {
setSession(null);
}
}
);
// cleanup function to unsubscribe
return () => {
if (authListener) authListener.unsubscribe();
};
}, [supabase.auth]);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Bennett Dams |
