T
TanStack3y ago
ambitious-aqua

Supabase - Tanstack Query issue

kinda lost right now. I think i understand a bit whats happening but a little confused. Not sure what to do. this is there error on page load. Error: invalid input syntax for type uuid: "undefined" at getUser (useUser.tsx:12:11)
export const SessionContextProvider = ({
children,
}: SessionContextProviderProps) => {
const [session, setSession] = useState<Session | null>(null);
const [isLoading, setIsLoading] = useState(true);

useEffect(() => {
setIsLoading(true);
supabase.auth.getSession().then(({ data: { session } }) => {
setSession(session);
setIsLoading(false);
});

const { data: authListener } = supabase.auth.onAuthStateChange(
async (_, session) => {
setSession(session);
setIsLoading(false);
}
);
return () => {
authListener?.subscription.unsubscribe();
};
}, []);

return (
<SessionContext.Provider value={session}>
{!isLoading ? children : null}
</SessionContext.Provider>
);
};

export const useSession = () => {
const context = useContext(SessionContext);
if (context === undefined) {
throw Error('useSession must be used within SessionContextProvider');
}
return context;
};
export const SessionContextProvider = ({
children,
}: SessionContextProviderProps) => {
const [session, setSession] = useState<Session | null>(null);
const [isLoading, setIsLoading] = useState(true);

useEffect(() => {
setIsLoading(true);
supabase.auth.getSession().then(({ data: { session } }) => {
setSession(session);
setIsLoading(false);
});

const { data: authListener } = supabase.auth.onAuthStateChange(
async (_, session) => {
setSession(session);
setIsLoading(false);
}
);
return () => {
authListener?.subscription.unsubscribe();
};
}, []);

return (
<SessionContext.Provider value={session}>
{!isLoading ? children : null}
</SessionContext.Provider>
);
};

export const useSession = () => {
const context = useContext(SessionContext);
if (context === undefined) {
throw Error('useSession must be used within SessionContextProvider');
}
return context;
};
2 Replies
ambitious-aqua
ambitious-aquaOP3y ago
const getUser = async (userId: string | undefined) => {
const { data, error } = await supabase
.from('profiles')
.select()
.eq('id', userId)
.single();
if (error) {
throw new Error(error.message);
}

if (!data) {
throw new Error('User not found');
}

return data;
};

export default function useUser() {
const session = useSession();
console.log(session);
return useQuery({
queryKey: ['user'],
queryFn: () => getUser(session?.user?.id),
});
}
const getUser = async (userId: string | undefined) => {
const { data, error } = await supabase
.from('profiles')
.select()
.eq('id', userId)
.single();
if (error) {
throw new Error(error.message);
}

if (!data) {
throw new Error('User not found');
}

return data;
};

export default function useUser() {
const session = useSession();
console.log(session);
return useQuery({
queryKey: ['user'],
queryFn: () => getUser(session?.user?.id),
});
}
const queryClient = new QueryClient();

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<SessionContextProvider>
<BrowserRouter>
<App />
<ReactQueryDevtools initialIsOpen={false} />
</BrowserRouter>
</SessionContextProvider>
</QueryClientProvider>
</React.StrictMode>
);
const queryClient = new QueryClient();

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<SessionContextProvider>
<BrowserRouter>
<App />
<ReactQueryDevtools initialIsOpen={false} />
</BrowserRouter>
</SessionContextProvider>
</QueryClientProvider>
</React.StrictMode>
);
function App() {
const { data, isLoading, isError } = useUser();
console.log(data);
return (
<>
<Routes>
<Route path="/" element={<div>home</div>}></Route>
<Route path="/password" element={<Auth view="forgot_password" />} />
</Routes>
{data ? (
<div>
<h1>Hello, {data?.username}!</h1>
<p>Your ID is {data?.id}.</p>
</div>
) : (
<Auth view="sign_in" />
)}
</>
);
}
function App() {
const { data, isLoading, isError } = useUser();
console.log(data);
return (
<>
<Routes>
<Route path="/" element={<div>home</div>}></Route>
<Route path="/password" element={<Auth view="forgot_password" />} />
</Routes>
{data ? (
<div>
<h1>Hello, {data?.username}!</h1>
<p>Your ID is {data?.id}.</p>
</div>
) : (
<Auth view="sign_in" />
)}
</>
);
}
i would expect that when the session is null for the data from useUser to just be null and not keep fetching to find it or cause any errors so i tried this if (!userId) return null; before everything in the getUser function and stops the errors. Idk if this what im supposed to do or if theres a bigger problem in how im doing things and this is just a hacky solution. Also, when i sign in it updates the data correctly but it doesnt re-render until i un-focus -> focus the window. How can i get around this wait... is this the solution?!!!!
return useQuery({
queryKey: ['user'],
queryFn: () => getUser(session?.user?.id),
enabled: !!session?.user?.id,
});
return useQuery({
queryKey: ['user'],
queryFn: () => getUser(session?.user?.id),
enabled: !!session?.user?.id,
});
so after some thinking, this is what it looks like now. Trying to wrap my head around using react query, is this how i would do this.
import { useEffect } from 'react';
import supabase from '../../config/supabase';
import { useQueryClient, useQuery } from '@tanstack/react-query';

const getSession = async () => {
const {
data: { session },
} = await supabase.auth.getSession();
return session;
};

export const useSession = () => {
const queryClient = useQueryClient();
useEffect(() => {
const { data: authListener } = supabase.auth.onAuthStateChange(
async (_, session) => {
if (session) {
queryClient.invalidateQueries({ queryKey: ['session'] });
}
}
);
return () => {
authListener?.subscription.unsubscribe();
};
}, [queryClient]);
return useQuery({ queryKey: ['session'], queryFn: getSession });
};
import { useEffect } from 'react';
import supabase from '../../config/supabase';
import { useQueryClient, useQuery } from '@tanstack/react-query';

const getSession = async () => {
const {
data: { session },
} = await supabase.auth.getSession();
return session;
};

export const useSession = () => {
const queryClient = useQueryClient();
useEffect(() => {
const { data: authListener } = supabase.auth.onAuthStateChange(
async (_, session) => {
if (session) {
queryClient.invalidateQueries({ queryKey: ['session'] });
}
}
);
return () => {
authListener?.subscription.unsubscribe();
};
}, [queryClient]);
return useQuery({ queryKey: ['session'], queryFn: getSession });
};
import { useQuery } from '@tanstack/react-query';
import supabase from '../../config/supabase';
import { useSession } from './useSession';

const getUser = async (userId: string | undefined) => {
const { data, error } = await supabase
.from('profiles')
.select()
.eq('id', userId)
.single();

if (error) {
throw new Error(error.message);
}

if (!data) {
throw new Error('User not found');
}

return data;
};

export default function useUser() {
const { data: session } = useSession();
return useQuery({
queryKey: ['user'],
queryFn: () => getUser(session?.user?.id),
enabled: !!session?.user?.id,
});
}
import { useQuery } from '@tanstack/react-query';
import supabase from '../../config/supabase';
import { useSession } from './useSession';

const getUser = async (userId: string | undefined) => {
const { data, error } = await supabase
.from('profiles')
.select()
.eq('id', userId)
.single();

if (error) {
throw new Error(error.message);
}

if (!data) {
throw new Error('User not found');
}

return data;
};

export default function useUser() {
const { data: session } = useSession();
return useQuery({
queryKey: ['user'],
queryFn: () => getUser(session?.user?.id),
enabled: !!session?.user?.id,
});
}
fair-rose
fair-rose3y ago
Disable the query until you have a user id seems like a good idea, yeah. As a side note, I would also include the user id in queryKey, to get a cache per user id (ideally all the parameters the queryFn accepts should be in the keys).

Did you find this page helpful?