Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

showing a loading Spinner on first page load #100

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

Janny221199
Copy link

@Janny221199 Janny221199 commented Jul 29, 2023

Hey guys,

I love svelte and firebase ❤️ 🔥 So I had to take a look at sveltefire too! Its awesome!

But I face a small issue which I wanna try to solve with this contribution.
It would be great if you could have a look at it and maybe give me some Feedback.

Problem:
So what was my intention? I used the <SignedIn>...</SignedIn> and <SignedOut></SignedOut> components. However, I ran into the problem that when I was logged in and reloaded the page (so the onAuthStateChanged() method is triggered again), the auth user is momentarily null. This caused me to very briefly see the content of a logged out user. But this disappeared after a few milli seconds, because I am logged in and the auth status was updated. So I had a short "flashing". This leads to a bad user experience in my opinion. Especially with a more complex UI.
short example:
https://github.com/codediodeio/sveltefire/assets/61154357/bdbc8fc6-7316-4de6-864b-959136789b44

Solution:
For me it would be a better solution to show optionally a loading spinner or something to indicate that the user auth status is still loading... As an example I just display "Loading..." in this PR.
This issue was that the user within the store was either null or not null.
Since the user is always null at the initial page load and we don't know exactly when the auth status was really checked, I had the idea to set the initial value to undefined. So you can show a loading spinner until the auth status is no longer undefined.
short example with my solution (with a dummy loading indicator):
https://github.com/codediodeio/sveltefire/assets/61154357/bc665057-a787-4da5-b994-ba34fa016e01

// Optionally you can omit the AuthLoading. In that case you see directly the right content which takes a few milli seconds. But then still without the flashing. So this results also in a better User Experience for me personally.

I think we won't have any issues with server site rendering. We can still set the startsWith parameter. If this is not set, you would see the information as a logged out user through the SSR anyway, which is negligible for SEO backgrounds.

So there are 3 status:

  1. user != null -> signed in
  2. user == null -> signed out
  3. user == undefined -> still loading auth status on initial page load

In my eyes this is a very useful feature, which leads to a better user experience.

What is your opinion? ❤️

@codediodeio
Copy link
Owner

Overall this looks great! One question though:

SignedOut should render on undefined and null because otherwise it won't work with SSR by default, right? This component should always render with SSR unless it has a startWith value.

@Janny221199
Copy link
Author

Janny221199 commented Aug 1, 2023

Hey, thanks for your feedback!

I have also thought about this several times. As of today (my PR), the SignedOut component is not rendered on the SSR side.

The reason for this is that then the "flickering" occurs again. So you see the content for a short moment and then is switched, if you are actually logged in. Especially with "real" content with pictures and animation this is very unattractive in my opinion.

At least I haven't found an optimal way to combine both. As a developer you have to ask yourself whether you want to have the whole SSR optimized (for SEO) and accept the "flickering" or you want to accept restrictions in the SSR area for the user experience.

The optimal way with both possibilities does not work as far as I know.
HOWEVER, I still think the principle of PR makes a lot of sense. I would have an idea, how we could possibly unite this in the best possible way:

My suggestion: we could render the SignedOut component default at null and undefined. But then add an optional parameter (boolean) to the component, whether the component should be displayed at undefined or not. Then we can determine dynamically depending upon use case that arbitrarily. If you think this is good, I would adjust my PR once briefly.

@brandonbaraban
Copy link

brandonbaraban commented Oct 14, 2023

Hi @Janny221199, (a bit late but hope this is still helpful)

I ran into a similar problem to the one you are facing, and my solution was to edit the pages in my app that don't need SSR to wait until the auth state is ready (the same as waiting for the first onAuthStateChanged callback to fire) before attempting to render any content. This allows you to show a loading state while waiting for auth, as you already did, but also avoids any UI "flashing" without editing existing components in the repo.

For example, using @sveltejs/[email protected] and [email protected], this solution could look like adding this +layout.svelte to any routes that don't need SSR:

<script>
	import MyLoadingComponent from '$lib/components/MyLoadingComponent.svelte';
	import { auth } from '$lib/firebase';

	const promise = auth.authStateReady();
</script>

{#await promise}
	<MyLoadingComponent />
{:then}
	<slot />
{/await}

Note that if you want to use this solution, until #129 is merged, you would need to add --legacy-peer-deps to any npm install command, since peer dependencies for sveltefire specify firebase@^9.0.0 right now, and the auth.authStateReady() function is only available for firebase@^10.0.0.


With respect to the solution being proposed, in my opinion it isn't the best pattern to change the behavior of the SignedOut component conditionally, by definition the component should render content when there is no authenticated user, which is during any SSR by default as well (as @codediodeio mentioned above).

Instead, I think it could make sense to create some wrapper that does something similar to the code I shared, e.g. an AuthStateReady component that only renders children when the auth state is ready, and has a slot for a loading component. That way developers can use that component in addition to other primitives to create the behavior they want in their application. This is similar in spirit to the AuthLoading component already set up in this PR.

@nickt28
Copy link

nickt28 commented May 12, 2024

@brandonbaraban Legend, thanks

Change log: https://firebase.google.com/support/release-notes/js#version_1010_-_july_20_2023

I put the function in the firebase.ts and use the export everywhere

// firebase.ts
export const userAuthReady = auth.authStateReady();

// pages
<script>
  import { userAuthReady } from '$lib/firebase';
</script>

{#await userAuthReady then}
  <SignedIn></SignedIn>
  <SignedOut></SignedOut>
{/await}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants