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

feat: Introduce RouterLink component to prefetch links as they enter the viewport #11293

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

olerichter00
Copy link
Contributor

@olerichter00 olerichter00 commented Dec 17, 2024

This PR resolves ONYX-1461

Description

This PR introduces a RouterLink component that wraps Palette's Touchable and takes an extra to prop with a URL or path to link to.

The reason for introducing the new RouterLink component is to be able to prefetch (all) app links as they enter the viewport, similar to how it's implemented in Force (artsy/force#14520 & artsy/force#14454).

If prefetching is enabled, the component automatically prefetches the URL with Relay as soon as it enters the viewport.

The new RouterLink component will replace PrefetchFlatList, which is also capable of prefetching links as they enter the viewport, but is limited and cannot be used as universally as the new link component.

Next Steps:

  • Use the new RouterLink component in more places
  • Make routes ready to be prefetched by adding the main query to routes.ts

Screenshots / Videos

Bildschirmaufnahme.2025-01-09.um.10.54.00.mov

PR Checklist

  • I have tested my changes on iOS and Android.
  • I hid my changes behind a feature flag, or they don't need one.
  • I have included screenshots or videos, or I have not changed the UI.
  • I have added tests, or my changes don't require any.
  • I added an app state migration, or my changes do not require one.
  • I have documented any follow-up work that this PR will require, or it does not require any.
  • I have added a changelog entry below, or my changes do not require one.

To the reviewers 👀

  • I would like at least one of the reviewers to run this PR on the simulator or device.
Changelog updates

Changelog updates

Cross-platform user-facing changes

  • Prefetch links as they enter the viewport - ole

iOS user-facing changes

Android user-facing changes

Dev changes

Need help with something? Have a look at our docs, or get in touch with us.

@olerichter00 olerichter00 marked this pull request as draft December 17, 2024 14:44
@olerichter00 olerichter00 self-assigned this Dec 17, 2024

return (
<ElementInView onVisible={handleVisible}>
<Touchable {...restProps} onPress={handlePress} />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder here if Touchable would be our preferred way, sometimes we use TouchableOpacity and sometimes we use TouchableWithoutHighlight.
Anyway, that's a problem for later, we can start with this now and extend it later.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this is a call to use RouterTouchableOpacity 🤷

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used the Touchable component from "@artsy/palette-mobile" and figured this is probably the preferred one. It has a prop to adjust the opacity on press.

Yeah, RouterTouchableOpacity or RouterTouchable could also be good names for this component. I took the name RouterLink from Force but haven't thought much about naming yet. I'm very open for ideas for the naming.

@olerichter00 olerichter00 force-pushed the olerichter00/ONYX-1461/prefetch-all-links-as-they-enter-the-viewport branch from f26a274 to 2cfaa76 Compare January 3, 2025 13:35
@olerichter00 olerichter00 force-pushed the olerichter00/ONYX-1461/prefetch-all-links-as-they-enter-the-viewport branch from 1104fed to d93009a Compare January 9, 2025 09:14
@olerichter00 olerichter00 changed the title feat: Prefetch all links as they enter the viewport feat: Introduce RouterLink component to prefetch links as they enter the viewport Jan 9, 2025
@olerichter00 olerichter00 marked this pull request as ready for review January 9, 2025 09:50
@ArtsyOpenSource
Copy link
Contributor

ArtsyOpenSource commented Jan 9, 2025

This PR contains the following changes:

  • Cross-platform user-facing changes (Prefetch links as they enter the viewport - ole - olerichter00)

Generated by 🚫 dangerJS against 3a7712b

@olerichter00 olerichter00 force-pushed the olerichter00/ONYX-1461/prefetch-all-links-as-they-enter-the-viewport branch from 346d855 to 9e354b2 Compare January 9, 2025 09:57
to: string | null | undefined
}

export const RouterLink: React.FC<RouterLinkProps & TouchableProps> = ({
Copy link
Contributor Author

@olerichter00 olerichter00 Jan 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've named the component RouterLink, as it is called in Force (routerlink.ts). But I am open to other suggestions regarding the naming. Another name I find quite good for this component is AppLink.

@olerichter00 olerichter00 force-pushed the olerichter00/ONYX-1461/prefetch-all-links-as-they-enter-the-viewport branch from fbbd649 to 3a7712b Compare January 9, 2025 14:46
Copy link
Member

@MounirDhahri MounirDhahri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this addition. I left few suggestions - I would leave to use to decide if they're worth the effort

@@ -46,6 +46,7 @@ const prefetchRoute = async <TQuery extends OperationType>(
const allVariables = { ...result.params, ...variables }

return queries.map((query) => {
console.log("[queryPrefetching] Prefetching:", route, JSON.stringify(allVariables))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👀

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! This doesn't need to be here. Just used it for debugging.

@@ -8,7 +8,7 @@ import { fetchQuery, GraphQLTaggedNode } from "react-relay"
import { OperationType, Variables, VariablesOf } from "relay-runtime"
import { logPrefetching } from "./loggers"

const DEFAULT_QUERIES_PER_INTERVAL = 60
const DEFAULT_QUERIES_PER_INTERVAL = 180
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment on lines +24 to +34
const handlePress = (event: GestureResponderEvent) => {
onPress?.(event)

if (!to) return

if (passProps) {
navigate(to, { passProps })
} else {
navigate(to)
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought: I don't have strong opinions about your approach here but I would have approached this differently for the benefit of more flexibility.
I would have left handlePress={props.onPress} to allow us to have full flexibility about taps and to be able as well to disable router links without much code added and handle the navigate event from within the component that uses RouterLink. And, I would use to only for prefetching the url.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a very interesting thought! I approached it this way to simplify how we implement links (similar to the web) while still having the full flexibility of onPress.

Do you have an example from the app where we would not be able to use the new to prop?

If it's just an edge case, then the workaround could be to do the navigation in onPress and not use to and not prefetch

}

return (
<ElementInView onVisible={handleVisible}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of the computation gets triggered here. I would also suggest to wrap the component behind the same enableViewPortPrefetching feature flag.
Maybe something like
Wrapper = enableViewPortPrefetching ? ElementInView : Touchable (maybe not exactly like that)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good idea and could be useful if the change affects performance too much 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

beautiful 👏

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

Successfully merging this pull request may close these issues.

4 participants