Repository: artsy/eigen
Pull request #11673: feat: Prefetch links on Artist screen
Author: login: olerichter00
Labels: name: Jira Synced
Created: 2025-03-13T13:26:12Z | Merged: 2025-03-18T09:22:15Z

This PR resolves [ONYX-1583] <!-- eg [PROJECT-XXXX] -->

### Description

Prefetch links on Artist screen.

### 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.

<details><summary>Changelog updates</summary>

### Changelog updates

<!-- 📝 Please fill out at least one of these sections. -->
<!-- ⓘ 'User-facing' changes will be published as release notes. -->
<!-- ⌫ Feel free to remove sections that don't apply. -->
<!-- • Write a markdown list or just a single paragraph, but stick to plain text. -->
<!-- 📖 eg. `Enable lotsByFollowedArtists` or `Fix phone input misalignment`. -->
<!-- 🤷‍♂️ Replace this entire block with the hashtag `#nochangelog` to avoid updating the changelog. -->
<!-- ⚠️ Prefix with `[NEEDS EXTERNAL QA]` if a change requires external QA -->

#### Cross-platform user-facing changes

- Prefetch all links on Artist screen - ole

#### iOS user-facing changes

-

#### Android user-facing changes

-

#### Dev changes

-

<!-- end_changelog_updates -->

</details>

Need help with something? Have a look at our [docs], or get in touch with us.

[app state migration]: ../blob/main/docs/adding_state_migrations.md
[feature flag]: ../blob/main/docs/developing_a_feature.md
[docs]: ../blob/main/docs/README.md


[ONYX-1583]: https://artsyproduct.atlassian.net/browse/ONYX-1583?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ


Diff:
diff --git a/src/app/Components/Artist/Articles/Article.tsx b/src/app/Components/Artist/Articles/Article.tsx
index 4eabb019e22..de64c4bdcf7 100644
--- a/src/app/Components/Artist/Articles/Article.tsx
+++ b/src/app/Components/Artist/Articles/Article.tsx
@@ -1,10 +1,10 @@
 import { ActionType, ContextModule, OwnerType, TappedArticleGroup } from "@artsy/cohesion"
-import { Flex, Spacer, Text, Touchable } from "@artsy/palette-mobile"
+import { Flex, Spacer, Text } from "@artsy/palette-mobile"
 import { Article_article$data, Article_article$key } from "__generated__/Article_article.graphql"
 import { Article_artist$data, Article_artist$key } from "__generated__/Article_artist.graphql"
-import { navigate } from "app/system/navigation/navigate"
+import { RouterLink } from "app/system/navigation/RouterLink"
 import FastImage from "react-native-fast-image"
-import { useFragment, graphql } from "react-relay"
+import { graphql, useFragment } from "react-relay"
 import { useTracking } from "react-tracking"
 
 interface ArticleProps {
@@ -21,12 +21,11 @@ export const Article: React.FC<ArticleProps> = ({ article, artist, headline = fa
   const handleOnPress = () => {
     if (articleData.href) {
       tracking.trackEvent(tracks.tappedArticleGroup(articleData, artistData))
-      navigate(articleData.href)
     }
   }
 
   return (
-    <Touchable onPress={handleOnPress}>
+    <RouterLink onPress={handleOnPress} to={articleData.href}>
       <Flex width="100%" overflow="hidden">
         <Flex width="100%" style={{ aspectRatio: 1.5 }}>
           {/* TODO: palette Image doesn't work with percentages, we can change it
@@ -51,7 +50,7 @@ export const Article: React.FC<ArticleProps> = ({ article, artist, headline = fa
         <Text variant="xs" color="black60">{`By ${articleData.byline}`}</Text>
         {!headline && <Spacer y={4} />}
       </Flex>
-    </Touchable>
+    </RouterLink>
   )
 }
 
diff --git a/src/app/Components/Artist/Articles/Articles.tsx b/src/app/Components/Artist/Articles/Articles.tsx
index f2e36ee9858..c34d32bf4df 100644
--- a/src/app/Components/Artist/Articles/Articles.tsx
+++ b/src/app/Components/Artist/Articles/Articles.tsx
@@ -1,11 +1,11 @@
 import { ActionType, ContextModule, OwnerType, TappedArticleGroup } from "@artsy/cohesion"
-import { Flex, Spacer, Text, Touchable } from "@artsy/palette-mobile"
+import { Flex, Spacer, Text } from "@artsy/palette-mobile"
 import { Articles_articles$key } from "__generated__/Articles_articles.graphql"
 import { Articles_artist$key } from "__generated__/Articles_artist.graphql"
 import { MasonryStatic } from "app/Components/MasonryStatic"
-import { navigate } from "app/system/navigation/navigate"
+import { RouterLink } from "app/system/navigation/RouterLink"
 import { Dimensions } from "react-native"
-import { useFragment, graphql } from "react-relay"
+import { graphql, useFragment } from "react-relay"
 import { useTracking } from "react-tracking"
 import { Article } from "./Article"
 
@@ -21,7 +21,6 @@ export const Articles: React.FC<Props> = ({ articles, artist }) => {
 
   const handleViewAll = () => {
     tracking.trackEvent(tracks.tappedViewAll())
-    navigate(`artist/${artistData.slug}/articles`)
   }
 
   return (
@@ -36,11 +35,11 @@ export const Articles: React.FC<Props> = ({ articles, artist }) => {
             pr={1}
           >{`Artsy Editorial Featuring ${artistData.name}`}</Text>
         </Flex>
-        <Touchable onPress={handleViewAll}>
+        <RouterLink onPress={handleViewAll} to={`artist/${artistData.slug}/articles`}>
           <Text variant="xs" underline>
             View All
           </Text>
-        </Touchable>
+        </RouterLink>
       </Flex>
 
       <Spacer y={4} />
diff --git a/src/app/Components/Artist/ArtistAbout/ArtistAboutEmpty.tsx b/src/app/Components/Artist/ArtistAbout/ArtistAboutEmpty.tsx
index 863aa25ddc9..d8fd9a07ab9 100644
--- a/src/app/Components/Artist/ArtistAbout/ArtistAboutEmpty.tsx
+++ b/src/app/Components/Artist/ArtistAbout/ArtistAboutEmpty.tsx
@@ -1,5 +1,5 @@
-import { Box, BoxProps, Text, Touchable } from "@artsy/palette-mobile"
-import { navigate } from "app/system/navigation/navigate"
+import { Box, BoxProps, Text } from "@artsy/palette-mobile"
+import { RouterLink } from "app/system/navigation/RouterLink"
 import { FC } from "react"
 
 export const ArtistAboutEmpty: FC<BoxProps> = (props) => {
@@ -12,16 +12,11 @@ export const ArtistAboutEmpty: FC<BoxProps> = (props) => {
       <Text variant="md" textAlign="center" color="black60">
         Do you represent this artist?
       </Text>
-      <Touchable
-        onPress={() => {
-          navigate("https://partners.artsy.net")
-        }}
-        style={{ alignSelf: "center" }}
-      >
+      <RouterLink to="https://partners.artsy.net" style={{ alignSelf: "center" }}>
         <Text variant="md" color="black100" style={{ textDecorationLine: "underline" }}>
           Become a partner.
         </Text>
-      </Touchable>
+      </RouterLink>
     </Box>
   )
 }
diff --git a/src/app/Components/Artist/ArtistHeader.tsx b/src/app/Components/Artist/ArtistHeader.tsx
index 9780f96ba2b..c3c0df7bd4c 100644
--- a/src/app/Components/Artist/ArtistHeader.tsx
+++ b/src/app/Components/Artist/ArtistHeader.tsx
@@ -14,7 +14,7 @@ import {
   ArtistHeader_artist$data,
   ArtistHeader_artist$key,
 } from "__generated__/ArtistHeader_artist.graphql"
-import { navigate } from "app/system/navigation/navigate"
+import { RouterLink } from "app/system/navigation/RouterLink"
 import { useFeatureFlag } from "app/utils/hooks/useFeatureFlag"
 import { FlatList, LayoutChangeEvent, ViewProps } from "react-native"
 import { isTablet } from "react-native-device-info"
@@ -53,7 +53,7 @@ export const ArtistHeader: React.FC<Props> = ({ artist, onLayoutChange }) => {
 
   const { width, height, aspectRatio } = useArtistHeaderImageDimensions()
   const { updateScrollYOffset } = useScreenScrollContext()
-  const tracking = useTracking()
+  const { trackEvent } = useTracking()
   const artistData = useFragment(artistFragment, artist)
 
   if (!artistData) {
@@ -90,15 +90,6 @@ export const ArtistHeader: React.FC<Props> = ({ artist, onLayoutChange }) => {
     }
   }
 
-  const handleRepresentativePress = (
-    partner: ArtistHeader_artist$data["verifiedRepresentatives"][number]["partner"]
-  ) => {
-    if (partner?.href && partner?.internalID) {
-      tracking.trackEvent(tracks.tappedVerifiedRepresentative(artistData, partner))
-      navigate(partner.href)
-    }
-  }
-
   return (
     <Flex pointerEvents="box-none" onLayout={handleOnLayout}>
       {!!artistData?.coverArtwork?.image?.url && (
@@ -140,13 +131,17 @@ export const ArtistHeader: React.FC<Props> = ({ artist, onLayoutChange }) => {
             data={artistData.verifiedRepresentatives}
             keyExtractor={({ partner }) => `representative-${partner.internalID}`}
             renderItem={({ item }) => (
-              <Pill
-                variant="profile"
-                src={item.partner.profile?.icon?.url ?? undefined}
-                onPress={() => handleRepresentativePress(item.partner)}
+              <RouterLink
+                onPress={() => {
+                  trackEvent(tracks.tappedVerifiedRepresentative(artistData, item.partner))
+                }}
+                to={item.partner.href}
+                hasChildTouchable
               >
-                {item.partner.name}
-              </Pill>
+                <Pill variant="profile" src={item.partner.profile?.icon?.url ?? undefined}>
+                  {item.partner.name}
+                </Pill>
+              </RouterLink>
             )}
             ItemSeparatorComponent={() => <Spacer x={1} />}
             contentContainerStyle={{
diff --git a/src/app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx b/src/app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx
index 4c133d4732d..84ebd0c473f 100644
--- a/src/app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx
+++ b/src/app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx
@@ -20,7 +20,6 @@ import {
 import Spinner from "app/Components/Spinner"
 import { PAGE_SIZE } from "app/Components/constants"
 import { AuctionResultsState } from "app/Scenes/AuctionResults/AuctionResultsScreenWrapper"
-import { navigate } from "app/system/navigation/navigate"
 import { extractNodes } from "app/utils/extractNodes"
 import { useScreenDimensions } from "app/utils/hooks"
 import { ExtractNodeType } from "app/utils/relayHelpers"
@@ -270,7 +269,6 @@ const ArtistInsightsAuctionResults: React.FC<Props> = ({
               auctionResult={item}
               onPress={() => {
                 tracking.trackEvent(tracks.tapAuctionGroup(item.internalID, artist.internalID))
-                navigate(`/artist/${artist?.slug}/auction-result/${item.internalID}`)
               }}
             />
           )}
diff --git a/src/app/Components/Artist/ArtistInsights/ArtistsInsightsEmpty.tsx b/src/app/Components/Artist/ArtistInsights/ArtistsInsightsEmpty.tsx
index 1c13b185f90..1f0926d7820 100644
--- a/src/app/Components/Artist/ArtistInsights/ArtistsInsightsEmpty.tsx
+++ b/src/app/Components/Artist/ArtistInsights/ArtistsInsightsEmpty.tsx
@@ -1,5 +1,5 @@
 import { Box, BoxProps, Button, Spacer, Text } from "@artsy/palette-mobile"
-import { navigate } from "app/system/navigation/navigate"
+import { RouterLink } from "app/system/navigation/RouterLink"
 import { FC } from "react"
 
 export const ArtistInsightsEmpty: FC<BoxProps> = (props) => {
@@ -16,15 +16,11 @@ export const ArtistInsightsEmpty: FC<BoxProps> = (props) => {
 
       <Spacer y={2} />
 
-      <Button
-        variant="outline"
-        mx="auto"
-        onPress={() => {
-          navigate("/price-database")
-        }}
-      >
-        View Artsy’s Price Database
-      </Button>
+      <RouterLink to="/price-database">
+        <Button variant="outline" mx="auto">
+          View Artsy’s Price Database
+        </Button>
+      </RouterLink>
     </Box>
   )
 }
diff --git a/src/app/Components/Artist/ArtistShows/ArtistShow.tsx b/src/app/Components/Artist/ArtistShows/ArtistShow.tsx
index d3368bc9c73..ab65e08bfc6 100644
--- a/src/app/Components/Artist/ArtistShows/ArtistShow.tsx
+++ b/src/app/Components/Artist/ArtistShows/ArtistShow.tsx
@@ -37,7 +37,7 @@ export const ArtistShow: React.FC<Props> = ({ styles, show, index, imageDimensio
   const imageURL = image && image.url
 
   return (
-    <RouterLink onPress={handleTap} to={hrefForPartialShow(data)} haptic>
+    <RouterLink haptic onPress={handleTap} to={hrefForPartialShow(data)}>
       <View style={[styles?.container]}>
         <View style={[styles?.imageMargin]}>
           <ImageWithFallback
diff --git a/src/app/Components/Artist/RelatedArtistsRailCell.tsx b/src/app/Components/Artist/RelatedArtistsRailCell.tsx
index a74ec957249..dc01f08cc5d 100644
--- a/src/app/Components/Artist/RelatedArtistsRailCell.tsx
+++ b/src/app/Components/Artist/RelatedArtistsRailCell.tsx
@@ -1,5 +1,5 @@
 import { ActionType, ContextModule, OwnerType, TappedArtistGroup } from "@artsy/cohesion"
-import { Flex, FollowButton, Image, Text, Touchable } from "@artsy/palette-mobile"
+import { Flex, FollowButton, Image, Text } from "@artsy/palette-mobile"
 import {
   RelatedArtistsRailCell_artist$data,
   RelatedArtistsRailCell_artist$key,
@@ -8,9 +8,9 @@ import {
   RelatedArtistsRailCell_relatedArtist$data,
   RelatedArtistsRailCell_relatedArtist$key,
 } from "__generated__/RelatedArtistsRailCell_relatedArtist.graphql"
-import { navigate } from "app/system/navigation/navigate"
+import { RouterLink } from "app/system/navigation/RouterLink"
 import { useFollowArtist } from "app/utils/mutations/useFollowArtist"
-import { useFragment, graphql } from "react-relay"
+import { graphql, useFragment } from "react-relay"
 import { useTracking } from "react-tracking"
 
 const DEFAULT_CELL_WIDTH = 300
@@ -37,7 +37,6 @@ export const RelatedArtistsRailCell: React.FC<RelatedArtistsRailCellProps> = ({
 
   const handleOnPress = () => {
     tracking.trackEvent(tracks.tappedArtistGroup(relatedArtistData, artistData, index))
-    navigate(relatedArtistData.href)
   }
 
   const handleOnFollow = () => {
@@ -61,7 +60,7 @@ export const RelatedArtistsRailCell: React.FC<RelatedArtistsRailCellProps> = ({
   }
 
   return (
-    <Touchable onPress={handleOnPress}>
+    <RouterLink onPress={handleOnPress} to={relatedArtistData.href}>
       <Image
         testID="related-artist-cover"
         src={relatedArtistData.coverArtwork?.image?.url ?? ""}
@@ -78,7 +77,7 @@ export const RelatedArtistsRailCell: React.FC<RelatedArtistsRailCellProps> = ({
         </Flex>
         <FollowButton isFollowed={!!relatedArtistData.isFollowed} onPress={handleOnFollow} />
       </Flex>
-    </Touchable>
+    </RouterLink>
   )
 }
 
diff --git a/src/app/Components/LatestAuctionResultsRail.tsx b/src/app/Components/LatestAuctionResultsRail.tsx
index 9210a4ccb33..9623837fee5 100644
--- a/src/app/Components/LatestAuctionResultsRail.tsx
+++ b/src/app/Components/LatestAuctionResultsRail.tsx
@@ -57,7 +57,6 @@ export const LatestAuctionResultsRail: React.FC<Props> = ({ me }) => {
               width={AUCTION_RESULT_CARD_WIDTH}
               onPress={() => {
                 trackEvent(tracks.tappedThumbnail(item.internalID, index))
-                navigate(`/artist/${item.artistID}/auction-result/${item.internalID}`)
               }}
             />
           )
diff --git a/src/app/Components/Lists/AuctionResultListItem.tests.tsx b/src/app/Components/Lists/AuctionResultListItem.tests.tsx
index d3645cd34c4..e5c751cb015 100644
--- a/src/app/Components/Lists/AuctionResultListItem.tests.tsx
+++ b/src/app/Components/Lists/AuctionResultListItem.tests.tsx
@@ -1,9 +1,10 @@
-import { Touchable } from "@artsy/palette-mobile"
+import { fireEvent, screen } from "@testing-library/react-native"
 import { AuctionResultListItemTestsQuery } from "__generated__/AuctionResultListItemTestsQuery.graphql"
 import * as navigation from "app/system/navigation/navigate"
+import { RouterLink } from "app/system/navigation/RouterLink"
 import { extractNodes } from "app/utils/extractNodes"
 import { extractText } from "app/utils/tests/extractText"
-import { renderWithWrappersLEGACY } from "app/utils/tests/renderWithWrappers"
+import { renderWithWrappers, renderWithWrappersLEGACY } from "app/utils/tests/renderWithWrappers"
 import { resolveMostRecentRelayOperation } from "app/utils/tests/resolveMostRecentRelayOperation"
 import moment from "moment"
 import { graphql, QueryRenderer } from "react-relay"
@@ -191,8 +192,8 @@ describe("AuctionResults", () => {
 
     expect(tree.root.findByProps({ testID: "saleInfo" }).props.children).toContain("Jan 12, 2021")
   })
-  it("navigates to the lot screen for upcoming auction results happening in ", () => {
-    const tree = renderWithWrappersLEGACY(<TestRenderer />)
+  it("navigates to the lot screen for upcoming auction results happening in ", async () => {
+    renderWithWrappers(<TestRenderer />)
     resolveMostRecentRelayOperation(mockEnvironment, {
       Artist: () => ({
         auctionResultsConnection: {
@@ -211,8 +212,10 @@ describe("AuctionResults", () => {
       }),
     })
 
-    const button = tree.root.findAllByType(Touchable)[0]
-    button.props.onPress()
+    const button = screen.getByText("Mediumtext-1")
+
+    fireEvent.press(button)
+
     expect(navigate).toHaveBeenCalledWith("https://www.artsy.net/artwork/auction-lot")
   })
 
@@ -237,8 +240,10 @@ describe("AuctionResults", () => {
       }),
     })
 
-    const button = tree.root.findAllByType(Touchable)[0]
+    const button = tree.root.findAllByType(RouterLink)[0]
+
     button.props.onPress()
+
     expect(mockOnPress).toHaveBeenCalled()
     expect(navigate).not.toHaveBeenCalled()
   })
diff --git a/src/app/Components/Lists/AuctionResultListItem.tsx b/src/app/Components/Lists/AuctionResultListItem.tsx
index 96255ea27b2..e57032cf570 100644
--- a/src/app/Components/Lists/AuctionResultListItem.tsx
+++ b/src/app/Components/Lists/AuctionResultListItem.tsx
@@ -1,17 +1,8 @@
-import {
-  bullet,
-  Flex,
-  NoArtworkIcon,
-  Spacer,
-  Stopwatch,
-  Text,
-  useColor,
-  Touchable,
-} from "@artsy/palette-mobile"
+import { bullet, Flex, NoArtworkIcon, Spacer, Stopwatch, Text } from "@artsy/palette-mobile"
 import { addBreadcrumb } from "@sentry/react-native"
 import { AuctionResultListItem_auctionResult$data } from "__generated__/AuctionResultListItem_auctionResult.graphql"
 import { auctionResultHasPrice, auctionResultText } from "app/Scenes/AuctionResult/helpers"
-import { navigate } from "app/system/navigation/navigate"
+import { RouterLink } from "app/system/navigation/RouterLink"
 import { QAInfoManualPanel, QAInfoRow } from "app/utils/QAInfo"
 import { capitalize } from "lodash"
 import moment from "moment"
@@ -46,8 +37,6 @@ const AuctionResultListItem: React.FC<Props> = ({
   const tracking = useTracking()
   const [couldNotLoadImage, setCouldNotLoadImage] = useState(false)
 
-  const color = useColor()
-
   const QAInfo: React.FC = () => (
     <QAInfoManualPanel position="absolute" top={0} left={95}>
       <QAInfoRow name="id" value={auctionResult.internalID} />
@@ -65,17 +54,16 @@ const AuctionResultListItem: React.FC<Props> = ({
     } else if (trackingEventPayload) {
       tracking.trackEvent(trackingEventPayload)
     }
-
-    // For upcoming auction results that are happening in Artsy we want to navigate to the lot page
-    if (auctionResult.isUpcoming && auctionResult.isInArtsyAuction && auctionResult.externalURL) {
-      navigate(auctionResult.externalURL)
-    } else {
-      navigate(`/artist/${auctionResult.artistID}/auction-result/${auctionResult.internalID}`)
-    }
   }
 
+  // For upcoming auction results that are happening in Artsy we want to navigate to the lot page
+  const href =
+    auctionResult.isUpcoming && auctionResult.isInArtsyAuction && auctionResult.externalURL
+      ? auctionResult.externalURL
+      : `/artist/${auctionResult.artistID}/auction-result/${auctionResult.internalID}`
+
   return (
-    <Touchable underlayColor={color("black5")} onPress={handlePress}>
+    <RouterLink onPress={handlePress} to={href}>
       <Flex px={withHorizontalPadding ? 2 : 0} flexDirection="row" width={width}>
         {/* Sale Artwork Thumbnail Image */}
         {!auctionResult.images?.thumbnail?.url || couldNotLoadImage ? (
@@ -170,7 +158,7 @@ const AuctionResultListItem: React.FC<Props> = ({
         </Flex>
       </Flex>
       <QAInfo />
-    </Touchable>
+    </RouterLink>
   )
 }
 
diff --git a/src/app/Navigation/routes.tsx b/src/app/Navigation/routes.tsx
index a4cd5881e3e..c3fe867961a 100644
--- a/src/app/Navigation/routes.tsx
+++ b/src/app/Navigation/routes.tsx
@@ -30,14 +30,17 @@ import {
   ArtistScreenQuery,
   defaultArtistVariables,
 } from "app/Scenes/Artist/Artist"
-import { ArtistArticlesQueryRenderer } from "app/Scenes/ArtistArticles/ArtistArticles"
+import {
+  ArtistArticlesQueryRenderer,
+  ArtistArticlesResultScreenQuery,
+} from "app/Scenes/ArtistArticles/ArtistArticles"
 import {
   ArtistSeriesQueryRenderer,
   ArtistSeriesScreenQuery,
 } from "app/Scenes/ArtistSeries/ArtistSeries"
 import {
   ArtistSeriesFullArtistSeriesListQueryRenderer,
-  ArtistSeriesFullArtistSeriesListScreenQuery,
+  ArtistSeriesFullArtistSeriesScreenQuery,
 } from "app/Scenes/ArtistSeries/ArtistSeriesFullArtistSeriesList"
 import { ArtistShowsQueryRenderer } from "app/Scenes/ArtistShows/ArtistShows"
 import { ArtworkScreen, ArtworkScreenQuery } from "app/Scenes/Artwork/Artwork"
@@ -52,7 +55,10 @@ import {
 } from "app/Scenes/ArtworkMedium/ArtworkMedium"
 import { ArtworkRecommendationsScreen } from "app/Scenes/ArtworkRecommendations/ArtworkRecommendations"
 import { AuctionBuyersPremiumQueryRenderer } from "app/Scenes/AuctionBuyersPremium/AuctionBuyersPremium"
-import { AuctionResultQueryRenderer } from "app/Scenes/AuctionResult/AuctionResult"
+import {
+  AuctionResultQueryRenderer,
+  AuctionResultScreenQuery,
+} from "app/Scenes/AuctionResult/AuctionResult"
 import {
   AuctionResultsForArtistsYouFollowPrefetchQuery,
   AuctionResultsForArtistsYouFollowQueryRenderer,
@@ -74,7 +80,7 @@ import { FeaturedFairsScreen, featuredFairsScreenQuery } from "app/Scenes/Fair/F
 import { Favorites } from "app/Scenes/Favorites/Favorites"
 import { FeatureQueryRenderer } from "app/Scenes/Feature/Feature"
 import { GalleriesForYouScreen } from "app/Scenes/GalleriesForYou/GalleriesForYouScreen"
-import { GeneQueryRenderer } from "app/Scenes/Gene/Gene"
+import { GeneQueryRenderer, GeneScreenQuery } from "app/Scenes/Gene/Gene"
 import { HomeViewScreen, homeViewScreenQuery } from "app/Scenes/HomeView/HomeView"
 import {
   HOME_SECTION_SCREEN_QUERY,
@@ -381,6 +387,7 @@ export const artsyDotNetRoutes = defineRoutes([
         headerShown: false,
       },
     },
+    queries: [ArtistArticlesResultScreenQuery],
   },
   {
     path: "/artist/:artistID/artist-series",
@@ -391,12 +398,13 @@ export const artsyDotNetRoutes = defineRoutes([
         headerTitle: "Artist Series",
       },
     },
-    queries: [ArtistSeriesFullArtistSeriesListScreenQuery],
+    queries: [ArtistSeriesFullArtistSeriesScreenQuery],
   },
   {
     path: "/artist/:artistID/auction-result/:auctionResultInternalID",
     name: "AuctionResult",
     Component: AuctionResultQueryRenderer,
+    queries: [AuctionResultScreenQuery],
   },
   {
     path: "/artist/:artistID/auction-results",
@@ -816,6 +824,7 @@ export const artsyDotNetRoutes = defineRoutes([
         headerShown: false,
       },
     },
+    queries: [GeneScreenQuery],
   },
   {
     path: "/home-view/sections/:id",
diff --git a/src/app/Scenes/ArtistArticles/ArtistArticles.tsx b/src/app/Scenes/ArtistArticles/ArtistArticles.tsx
index 781cf83b749..c5234f16727 100644
--- a/src/app/Scenes/ArtistArticles/ArtistArticles.tsx
+++ b/src/app/Scenes/ArtistArticles/ArtistArticles.tsx
@@ -14,10 +14,10 @@ import { screen } from "app/utils/track/helpers"
 import { useState } from "react"
 import {
   createPaginationContainer,
+  Environment,
+  graphql,
   QueryRenderer,
   RelayPaginationProp,
-  graphql,
-  Environment,
 } from "react-relay"
 import { useTracking } from "react-tracking"
 
@@ -126,13 +126,7 @@ export const ArtistArticlesQueryRenderer: React.FC<{
   return (
     <QueryRenderer<ArtistArticlesResultQuery>
       environment={environment || getRelayEnvironment()}
-      query={graphql`
-        query ArtistArticlesResultQuery($artistID: String!) {
-          artist(id: $artistID) {
-            ...ArtistArticles_artist
-          }
-        }
-      `}
+      query={ArtistArticlesResultScreenQuery}
       variables={{
         artistID,
       }}
@@ -144,6 +138,14 @@ export const ArtistArticlesQueryRenderer: React.FC<{
   )
 }
 
+export const ArtistArticlesResultScreenQuery = graphql`
+  query ArtistArticlesResultQuery($artistID: String!) {
+    artist(id: $artistID) {
+      ...ArtistArticles_artist
+    }
+  }
+`
+
 export const tracks = {
   tapArticlesListItem: (articleId: string, articleSlug: string) => ({
     action: ActionType.tappedArticleGroup,
diff --git a/src/app/Scenes/ArtistSeries/ArtistSeriesFullArtistSeriesList.tsx b/src/app/Scenes/ArtistSeries/ArtistSeriesFullArtistSeriesList.tsx
index 414ec05daf5..b02c8bf84ab 100644
--- a/src/app/Scenes/ArtistSeries/ArtistSeriesFullArtistSeriesList.tsx
+++ b/src/app/Scenes/ArtistSeries/ArtistSeriesFullArtistSeriesList.tsx
@@ -69,21 +69,13 @@ export const ArtistSeriesFullArtistSeriesListFragmentContainer = createFragmentC
   }
 )
 
-export const ArtistSeriesFullArtistSeriesListScreenQuery = graphql`
-  query ArtistSeriesFullArtistSeriesListQuery($artistID: String!) {
-    artist(id: $artistID) {
-      ...ArtistSeriesFullArtistSeriesList_artist
-    }
-  }
-`
-
 export const ArtistSeriesFullArtistSeriesListQueryRenderer: React.FC<{ artistID: string }> = ({
   artistID,
 }) => {
   return (
     <QueryRenderer<ArtistSeriesFullArtistSeriesListQuery>
       environment={getRelayEnvironment()}
-      query={ArtistSeriesFullArtistSeriesListScreenQuery}
+      query={ArtistSeriesFullArtistSeriesScreenQuery}
       variables={{
         artistID,
       }}
@@ -91,3 +83,11 @@ export const ArtistSeriesFullArtistSeriesListQueryRenderer: React.FC<{ artistID:
     />
   )
 }
+
+export const ArtistSeriesFullArtistSeriesScreenQuery = graphql`
+  query ArtistSeriesFullArtistSeriesListQuery($artistID: String!) {
+    artist(id: $artistID) {
+      ...ArtistSeriesFullArtistSeriesList_artist
+    }
+  }
+`
diff --git a/src/app/Scenes/ArtistSeries/ArtistSeriesListItem.tests.tsx b/src/app/Scenes/ArtistSeries/ArtistSeriesListItem.tests.tsx
index 1aae29ec06c..58fd3266a50 100644
--- a/src/app/Scenes/ArtistSeries/ArtistSeriesListItem.tests.tsx
+++ b/src/app/Scenes/ArtistSeries/ArtistSeriesListItem.tests.tsx
@@ -1,14 +1,14 @@
 import { OwnerType } from "@artsy/cohesion"
-import { Touchable } from "@artsy/palette-mobile"
+import { fireEvent, screen } from "@testing-library/react-native"
 import { ArtistSeriesListItem } from "app/Scenes/ArtistSeries/ArtistSeriesListItem"
 import { ArtistSeriesConnectionEdge } from "app/Scenes/ArtistSeries/ArtistSeriesMoreSeries"
 import { navigate } from "app/system/navigation/navigate"
-import { renderWithWrappersLEGACY } from "app/utils/tests/renderWithWrappers"
-import { act } from "react-test-renderer"
+import { RouterLink } from "app/system/navigation/RouterLink"
+import { renderWithWrappers, renderWithWrappersLEGACY } from "app/utils/tests/renderWithWrappers"
 
 describe("ArtistSeriesListItem", () => {
   it("navigates to the artist series when tapped", () => {
-    const artistSeriesListItem = renderWithWrappersLEGACY(
+    renderWithWrappers(
       <ArtistSeriesListItem
         horizontalSlidePosition={2}
         contextScreenOwnerType={OwnerType.artist}
@@ -16,9 +16,7 @@ describe("ArtistSeriesListItem", () => {
       />
     )
 
-    const instance = artistSeriesListItem.root.findAllByType(Touchable)[0]
-
-    act(() => instance.props.onPress())
+    fireEvent.press(screen.getByTestId("list-item-image"))
 
     expect(navigate).toHaveBeenCalledWith("/artist-series/yayoi-kusama-pumpkins")
   })
@@ -32,7 +30,7 @@ describe("ArtistSeriesListItem", () => {
       />
     )
 
-    const instance = artistSeriesListItem.root.findAllByType(Touchable)[0]
+    const instance = artistSeriesListItem.root.findAllByType(RouterLink)[0]
 
     expect(instance.findAllByProps({ testID: "list-item-image" })[0].props.src).toBe(
       "https://d32dm0rphc51dk.cloudfront.net/dL3hz4h6f_tMHQjVHsdO4w/medium.jpg"
diff --git a/src/app/Scenes/ArtistSeries/ArtistSeriesListItem.tsx b/src/app/Scenes/ArtistSeries/ArtistSeriesListItem.tsx
index f8682da1255..74cda9defc1 100644
--- a/src/app/Scenes/ArtistSeries/ArtistSeriesListItem.tsx
+++ b/src/app/Scenes/ArtistSeries/ArtistSeriesListItem.tsx
@@ -5,9 +5,9 @@ import {
   ScreenOwnerType,
   TappedArtistSeriesGroup,
 } from "@artsy/cohesion"
-import { ArrowRightIcon, Flex, useColor, Text, Touchable, Image } from "@artsy/palette-mobile"
+import { ArrowRightIcon, Flex, Image, Text, useColor } from "@artsy/palette-mobile"
 import { ArtistSeriesConnectionEdge } from "app/Scenes/ArtistSeries/ArtistSeriesMoreSeries"
-import { navigate } from "app/system/navigation/navigate"
+import { RouterLink } from "app/system/navigation/RouterLink"
 import { useTracking } from "react-tracking"
 
 interface ArtistSeriesListItemProps {
@@ -55,7 +55,7 @@ export const ArtistSeriesListItem: React.FC<ArtistSeriesListItemProps> = ({
   }
 
   return (
-    <Touchable
+    <RouterLink
       accessibilityLabel="Artist Series List Item"
       accessibilityRole="button"
       underlayColor={color("black5")}
@@ -64,8 +64,8 @@ export const ArtistSeriesListItem: React.FC<ArtistSeriesListItemProps> = ({
       style={{ marginHorizontal: -20 }}
       onPress={() => {
         trackArtworkClick()
-        navigate(`/artist-series/${listItem?.node?.slug}`)
       }}
+      to={`/artist-series/${listItem?.node?.slug}`}
     >
       <Flex px={2} my={1} flexDirection="row" justifyContent="space-between">
         <Flex flexDirection="row" justifyContent="space-between" width="100%">
@@ -94,6 +94,6 @@ export const ArtistSeriesListItem: React.FC<ArtistSeriesListItemProps> = ({
           </Flex>
         </Flex>
       </Flex>
-    </Touchable>
+    </RouterLink>
   )
 }
diff --git a/src/app/Scenes/ArtistSeries/ArtistSeriesMoreSeries.tests.tsx b/src/app/Scenes/ArtistSeries/ArtistSeriesMoreSeries.tests.tsx
index 109941f4bf9..3159a949007 100644
--- a/src/app/Scenes/ArtistSeries/ArtistSeriesMoreSeries.tests.tsx
+++ b/src/app/Scenes/ArtistSeries/ArtistSeriesMoreSeries.tests.tsx
@@ -1,11 +1,11 @@
 import { ContextModule, OwnerType } from "@artsy/cohesion"
-import { Touchable } from "@artsy/palette-mobile"
 import { ArtistSeriesMoreSeriesTestsQuery } from "__generated__/ArtistSeriesMoreSeriesTestsQuery.graphql"
 import { ArtistSeriesListItem } from "app/Scenes/ArtistSeries/ArtistSeriesListItem"
 import {
   ArtistSeriesMoreSeries,
   ArtistSeriesMoreSeriesFragmentContainer,
 } from "app/Scenes/ArtistSeries/ArtistSeriesMoreSeries"
+import { RouterLink } from "app/system/navigation/RouterLink"
 import { mockTrackEvent } from "app/utils/tests/globallyMockedStuff"
 import { renderWithWrappersLEGACY } from "app/utils/tests/renderWithWrappers"
 import { graphql, QueryRenderer } from "react-relay"
@@ -86,7 +86,7 @@ describe("ArtistSeriesMoreSeries", () => {
     it("tracks an event on click", async () => {
       const root = getWrapper(ArtistSeriesMoreSeriesFixture)
       const artistSerieListItems = await root.findAllByType(ArtistSeriesListItem)
-      const artistSeriesButton = artistSerieListItems[0].findByType(Touchable)
+      const artistSeriesButton = artistSerieListItems[0].findByType(RouterLink)
 
       act(() => artistSeriesButton.props.onPress())
 
diff --git a/src/app/Scenes/AuctionResult/AuctionResult.tsx b/src/app/Scenes/AuctionResult/AuctionResult.tsx
index d725f134562..79451d23167 100644
--- a/src/app/Scenes/AuctionResult/AuctionResult.tsx
+++ b/src/app/Scenes/AuctionResult/AuctionResult.tsx
@@ -388,7 +388,7 @@ const artistFragment = graphql`
   }
 `
 
-const AuctionResultScreenQuery = graphql`
+export const AuctionResultScreenQuery = graphql`
   query AuctionResultQuery($auctionResultInternalID: String!, $artistID: String!) {
     auctionResult(id: $auctionResultInternalID) {
       ...AuctionResult_auctionResult
@@ -408,16 +408,11 @@ export const AuctionResultScreenContainer: React.FC<AuctionResultQueryRendererPr
   auctionResultInternalID,
   artistID,
 }) => {
-  const data = useLazyLoadQuery<AuctionResultQuery>(
-    AuctionResultScreenQuery,
-    {
-      auctionResultInternalID,
-      artistID,
-    },
-    {
-      fetchPolicy: "store-and-network",
-    }
-  )
+  const data = useLazyLoadQuery<AuctionResultQuery>(AuctionResultScreenQuery, {
+    auctionResultInternalID,
+    artistID,
+  })
+
   if (!data?.auctionResult || !data?.artist) {
     return (
       <Flex>
@@ -425,6 +420,7 @@ export const AuctionResultScreenContainer: React.FC<AuctionResultQueryRendererPr
       </Flex>
     )
   }
+
   return <AuctionResult artist={data.artist} auctionResult={data.auctionResult} />
 }
 
diff --git a/src/app/Scenes/AuctionResult/ComparableWorks.tsx b/src/app/Scenes/AuctionResult/ComparableWorks.tsx
index e1431afb170..49b2135a7d1 100644
--- a/src/app/Scenes/AuctionResult/ComparableWorks.tsx
+++ b/src/app/Scenes/AuctionResult/ComparableWorks.tsx
@@ -1,11 +1,10 @@
 import { ActionType, ContextModule, OwnerType } from "@artsy/cohesion"
-import { Flex, Text, Join } from "@artsy/palette-mobile"
+import { Flex, Join, Text } from "@artsy/palette-mobile"
 import { ComparableWorks_auctionResult$data } from "__generated__/ComparableWorks_auctionResult.graphql"
 import {
   AuctionResultListItemFragmentContainer,
   AuctionResultListSeparator,
 } from "app/Components/Lists/AuctionResultListItem"
-import { navigate } from "app/system/navigation/navigate"
 import { extractNodes } from "app/utils/extractNodes"
 import { compact } from "lodash"
 import { createFragmentContainer, graphql } from "react-relay"
@@ -37,9 +36,6 @@ const ComparableWorks: React.FC<ComparableWorks> = ({ auctionResult }) => {
               auctionResult={auctionResultRow}
               onPress={() => {
                 trackEvent(tracks.tapAuctionResult(auctionResultRow.internalID, index))
-                navigate(
-                  `/artist/${auctionResultRow.artistID}/auction-result/${auctionResultRow.internalID}`
-                )
               }}
             />
           ))}
diff --git a/src/app/Scenes/Gene/Gene.tsx b/src/app/Scenes/Gene/Gene.tsx
index 392550c52f6..306f8d7c4ec 100644
--- a/src/app/Scenes/Gene/Gene.tsx
+++ b/src/app/Scenes/Gene/Gene.tsx
@@ -96,18 +96,7 @@ export const GeneQueryRenderer: React.FC<GeneQueryRendererProps> = (props) => {
   return (
     <QueryRenderer<GeneQuery>
       environment={getRelayEnvironment()}
-      query={graphql`
-        query GeneQuery($geneID: String!, $input: FilterArtworksInput) {
-          gene(id: $geneID) @principalField {
-            displayName
-            name
-            slug
-            ...Header_gene
-            ...About_gene
-            ...GeneArtworks_gene @arguments(input: $input)
-          }
-        }
-      `}
+      query={GeneScreenQuery}
       variables={{
         geneID,
         input,
@@ -121,6 +110,19 @@ export const GeneQueryRenderer: React.FC<GeneQueryRendererProps> = (props) => {
   )
 }
 
+export const GeneScreenQuery = graphql`
+  query GeneQuery($geneID: String!, $input: FilterArtworksInput) {
+    gene(id: $geneID) @principalField {
+      displayName
+      name
+      slug
+      ...Header_gene
+      ...About_gene
+      ...GeneArtworks_gene @arguments(input: $input)
+    }
+  }
+`
+
 export const GeneSkeleton: React.FC = () => {
   return (
     <Screen>
diff --git a/src/app/Scenes/MyCollection/Screens/Artwork/Components/ArtworkInsights/MyCollectionArtworkArtistAuctionResults.tsx b/src/app/Scenes/MyCollection/Screens/Artwork/Components/ArtworkInsights/MyCollectionArtworkArtistAuctionResults.tsx
index 76d07463fb4..183ec9ec4b3 100644
--- a/src/app/Scenes/MyCollection/Screens/Artwork/Components/ArtworkInsights/MyCollectionArtworkArtistAuctionResults.tsx
+++ b/src/app/Scenes/MyCollection/Screens/Artwork/Components/ArtworkInsights/MyCollectionArtworkArtistAuctionResults.tsx
@@ -45,7 +45,6 @@ export const MyCollectionArtworkArtistAuctionResults: React.FC<
             onPress={() => {
               if (!!artist?.slug) {
                 trackEvent(tracks.tappedAuctionResultGroup(artwork?.internalID, artwork?.slug))
-                navigate(`/artist/${artist.slug}/auction-result/${item.internalID}`)
               }
             }}
           />
diff --git a/src/app/Scenes/MyCollection/Screens/Artwork/Components/ArtworkInsights/MyCollectionArtworkComparableWorks.tsx b/src/app/Scenes/MyCollection/Screens/Artwork/Components/ArtworkInsights/MyCollectionArtworkComparableWorks.tsx
index 88e843a73c8..e348cfcddba 100644
--- a/src/app/Scenes/MyCollection/Screens/Artwork/Components/ArtworkInsights/MyCollectionArtworkComparableWorks.tsx
+++ b/src/app/Scenes/MyCollection/Screens/Artwork/Components/ArtworkInsights/MyCollectionArtworkComparableWorks.tsx
@@ -3,7 +3,6 @@ import { Flex, Separator } from "@artsy/palette-mobile"
 import { MyCollectionArtworkComparableWorks_artwork$key } from "__generated__/MyCollectionArtworkComparableWorks_artwork.graphql"
 import { AuctionResultListItemFragmentContainer } from "app/Components/Lists/AuctionResultListItem"
 import { SectionTitle } from "app/Components/SectionTitle"
-import { navigate } from "app/system/navigation/navigate"
 import { extractNodes } from "app/utils/extractNodes"
 import { graphql, useFragment } from "react-relay"
 import { useTracking } from "react-tracking"
@@ -36,7 +35,6 @@ export const MyCollectionArtworkComparableWorks: React.FC<
             onPress={() => {
               if (artwork.artist?.slug) {
                 trackEvent(tracks.tappedAuctionResultGroup(artwork?.internalID, artwork?.slug))
-                navigate(`/artist/${artwork.artist.slug}/auction-result/${item.internalID}`)
               }
             }}
           />
diff --git a/src/app/Scenes/MyCollection/Screens/Insights/AuctionResultsForArtistsYouCollectRail.tsx b/src/app/Scenes/MyCollection/Screens/Insights/AuctionResultsForArtistsYouCollectRail.tsx
index 37aaa4585ae..a5cbedb15be 100644
--- a/src/app/Scenes/MyCollection/Screens/Insights/AuctionResultsForArtistsYouCollectRail.tsx
+++ b/src/app/Scenes/MyCollection/Screens/Insights/AuctionResultsForArtistsYouCollectRail.tsx
@@ -52,7 +52,6 @@ export const AuctionResultsForArtistsYouCollectRail: React.FC<
             showArtistName
             onPress={() => {
               trackEvent(tracks.tappedAuctionResultGroup(index))
-              navigate(`/artist/${item.artistID}/auction-result/${item.internalID}`)
             }}
           />
         )}


Reviews:
user: login: nickskalkin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T16:26:18Z
user: login: olerichter00
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T16:30:51Z
user: login: nickskalkin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T09:04:30Z
user: login: nickskalkin
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T09:05:12Z

Review comments:
diff_hunk: @@ -57,7 +57,6 @@ export const LatestAuctionResultsRail: React.FC<Props> = ({ me }) => {
               width={AUCTION_RESULT_CARD_WIDTH}
               onPress={() => {
                 trackEvent(tracks.tappedThumbnail(item.internalID, index))
-                navigate(`/artist/${item.artistID}/auction-result/${item.internalID}`)
path: src/app/Components/LatestAuctionResultsRail.tsx
user: login: nickskalkin
body: @olerichter00 sorry I'm blind, but I don't see where this navigation is being handled after your changes
created_at: 2025-03-17T16:26:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,7 +57,6 @@ export const LatestAuctionResultsRail: React.FC<Props> = ({ me }) => {
               width={AUCTION_RESULT_CARD_WIDTH}
               onPress={() => {
                 trackEvent(tracks.tappedThumbnail(item.internalID, index))
-                navigate(`/artist/${item.artistID}/auction-result/${item.internalID}`)
path: src/app/Components/LatestAuctionResultsRail.tsx
user: login: olerichter00
body: It's handled in `AuctionResultListItem` instead ([here](https://github.com/artsy/eigen/blob/d7eadbb7e4320fd6e8a2ea725f37f89851828ab2/src/app/Components/Lists/AuctionResultListItem.tsx#L66)). The rail uses these items. I tested the rail and the navigation is working 🚂 
created_at: 2025-03-17T16:30:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,7 +57,6 @@ export const LatestAuctionResultsRail: React.FC<Props> = ({ me }) => {
               width={AUCTION_RESULT_CARD_WIDTH}
               onPress={() => {
                 trackEvent(tracks.tappedThumbnail(item.internalID, index))
-                navigate(`/artist/${item.artistID}/auction-result/${item.internalID}`)
path: src/app/Components/LatestAuctionResultsRail.tsx
user: login: nickskalkin
body: thanks!
created_at: 2025-03-18T09:04:30Z
author_association: CONTRIBUTOR

PR comments:
user: login: ArtsyOpenSource
created_at: 2025-03-13T13:29:02Z
body: 
<!--
  0 failure: 
  0 warning: 
  
  1 markdown notices
  DangerID: danger-id-Danger;
-->



### This PR contains the following changes:

- Cross-platform user-facing changes (Prefetch all links on Artist screen - ole - olerichter00)
<p align="right">
  Generated by :no_entry_sign: <a href="https://danger.systems/js">dangerJS</a> against 35a2ee5756c83361a8169f737a36661f9dafb104
</p>

author_association: CONTRIBUTOR