-
-
Notifications
You must be signed in to change notification settings - Fork 112
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
feat: PWA pull to refresh #1599
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, this is very impressive! It works great and the code is very clean. Stackers (myself included) are going to love this! Additionally, this was a breeze to review. Thank you so much for this! Looking forward to more contributions from you 👀
Now to the review:
I tested this on desktop by simply manually setting isPWA
to true
and then using the mobile emulator. I also tested that the refresh actually works by loading new comments that I created in a new tab.
I only have a few UX and CSS nitpicks:
- is it possible to prevent scrolling the window down when the
pull to refresh
shows up and I want to abort?
2024-11-18.01-26-46.mp4
- Why did you add the spacer during refresh? Afaict it does nothing except create layout shift. Therefore I think we should also remove it, it's even more cleaner that way. So the meme should have actually been this:
-
the pull message is a little big so I think we should use
font-size: small
in thepullMessage
CSS class. -
the distance to pull down might be a little too much (almost half of the screen) but we can roll this out and then see if we need to adjust it.actually, ignore this. I played around more and a big threshold as-is is better. -
pulling down also works when I start to pull down from the bottom of the screen when I am scrolled all the way to the top. Not sure if that's how other apps do it, I think you need to start at the top?
After dropping refreshing ...
, the spacer and making the text smaller, the UI/UX is this:
2024-11-18.01-53-19.mp4
Regarding Android: I haven't tested it on Android but since this works so well, I think we can keep your code enabled on Android to have a consistent experience.
If anything is weird, it's very easy to go back to the native behavior on Android.
Since these are all just nitpicks and it's already as-is a huge improvement, this is approved from my side ✅
@huumn is the final boss though
components/pull-to-refresh.js
Outdated
useEffect(() => { | ||
checkPWA() | ||
}, []) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useEffect(() => { | |
checkPWA() | |
}, []) | |
useEffect(checkPWA, []) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops 😳
}, [isPWA, isAndroid, android]) | ||
|
||
const handleTouchMove = useCallback((e) => { | ||
if (touchStartY.current === 0) return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed so the text doesn't get stuck in some cases? At least that's what I can tell starts happening when I remove this line. A comment in the code would be nice here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes! I thought I was going crazy because between refreshes the text would get stuck, noted thanks :P
}, []) | ||
|
||
const handleTouchEnd = useCallback(() => { | ||
if (touchStartY.current === 0 || touchEndY.current === 0) return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same reason here I suppose
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Touch can be finicky with JS, I wanted to make sure that we can't encounter weird behavior
components/pull-to-refresh.js
Outdated
import { useState, useRef, useEffect, useCallback } from 'react' | ||
import styles from './pull-to-refresh.module.css' | ||
|
||
const PULL_THRESHOLD = 300 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
100 as twice the threshold when , No, I played around with 100 and 300 is way better since it doesn't cause accidental refreshes.pull to refresh
starts showing might be a better threshold.
I would also call this REFRESH_THRESHOLD
since PULL_THRESHOLD
sounds like that's when we show the first message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noted, you're right it would make much more sense!
components/pull-to-refresh.js
Outdated
{pullDistance > 0 || isRefreshing | ||
? ( | ||
<> | ||
<p className={`${styles.pullMessage} ${pullDistance > 50 || isRefreshing ? styles.fadeIn : ''}`}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This suggests you want to show the message when pullDistance > 50
, but above you're checking for pullDistance > 0
. Isn't checking it at one place enough? Using only pullDistance > 50
looks good to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok so, I think that stayed there during multiple versions of this code, IIRC before placing touch checks this was a workaround to get me through refreshes and avoid unintended messages.
I'm going to test if that's still the case
components/pull-to-refresh.js
Outdated
<p className={`${styles.pullMessage} ${pullDistance > 50 || isRefreshing ? styles.fadeIn : ''}`}> | ||
{getPullMessage()} | ||
</p> | ||
{isRefreshing && <div className={styles.spacer} />} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should also drop this since afaict, it only causes layout shift
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And it doesn't look clean
.spacer { | ||
position: relative; | ||
margin-bottom: 32px; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see other comment
left: 50%; | ||
top: -50px; | ||
transform: translateX(-50%); | ||
font-size: 18px; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
font-size: 18px; | |
font-size: small; |
a solution for this might be to use the behavior in your first video where the whole page moves down when you pull down |
Many many thanks! I'm glad that you like it!
The behavior you're encountering should be uniquely present on desktop as it doesn't allow overscroll like mobile devices, if you notice in my two videos, the whole page moves down when you pull down :P wait- now that I think about it, to make it theoretically work on Android I conditionally disable overscroll, we would get the same result you get on desktop... we definitely need to go with your UI/UX changes in order to make it pretty for both devices
The spacer prevents the messages to appear on content, but since we're going towards a much cleaner experience I think it won't be a problem anymore (thanks!)
I agree wholeheartedly to both, about the threshold, I tried with lots of values and 300 was the right number imo!
So as long as the user is at the top of the page, refresh can (or should) happen because you can't scroll higher, if the user is scrolling from the bottom but can't reach threshold it will make the user think that for scrolling he needs to start pulling from top.
You're right, I've been too conservative in terms of UI/UX
Thanks!!! Your changes will be beneficial to android too because of disabled overscroll :P
Nitpicks are what makes apps and sites feel good to use, thank you so much, will commit changes later in the day ❤️ |
a4db44c
to
a992426
Compare
trim.5FAC5AE4-5EC9-4B63-B42A-E4C4A1454145.MOVwell it looks super cool. I moved |
i forgot to memoize the messages 🫣 |
Description
Pull-to-refresh for iOS, completing #1258.
As
router.reload()
is not graceful androuter.replace(...)
adds "/~" to the path breaking functionality across the app, I've decided to userouter.push()
instead, reloading the same page.This updates the browser's history but since we're talking about a PWA there's no history to be accessed from the user.
This component wraps
<Layout />
and is present in every page that make use of it.Screenshots
doc_2024-11-17_22-03-08.mp4
Additional Context
At the moment it's enabled also for Android, disabling its native pull-to-refresh. If we want to enable it back we can pass
android=false
Not being a master of creativity and CSS I want to know if you'd like to see something else instead of refreshing..., even though I think it's geeky in its own way
Checklist
Are your changes backwards compatible? Please answer below:
checkPWA prevents it from being triggered on anything that's not a PWA, also being a new component that has minimal CSS and loads only if the user is at the top of the page, I can say that it doesn't break functionality.
On a scale of 1-10 how well and how have you QA'd this change and any features it might affect? Please answer below:
7, I don't have an Android phone and I would like to know if there are any problems with it, as said before we can disable or enable Android's PTR.
As it should work only in a PWA context, I also tested it on browsers
For frontend changes: Tested on mobile? Please answer below:
Yes, being a mobile-only feature
Did you introduce any new environment variables? If so, call them out explicitly here: No