Separate caches

This commit is contained in:
Dan Abramov
2025-01-19 20:10:28 +00:00
parent 47f9ae1b3f
commit 0bd92c1bd0
9 changed files with 103 additions and 14 deletions
@@ -1,14 +1,16 @@
import React from 'react' import React, {useEffect} from 'react'
import {ScrollView, View} from 'react-native' import {ScrollView, View} from 'react-native'
import {AppBskyEmbedVideo, AtUri} from '@atproto/api' import {AppBskyEmbedVideo, AtUri} from '@atproto/api'
import {msg, Trans} from '@lingui/macro' import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {useQueryClient} from '@tanstack/react-query'
import {VIDEO_FEED_URI} from '#/lib/constants' import {VIDEO_FEED_URI} from '#/lib/constants'
import {makeCustomFeedLink} from '#/lib/routes/links' import {makeCustomFeedLink} from '#/lib/routes/links'
import {logEvent} from '#/lib/statsig/statsig' import {logEvent} from '#/lib/statsig/statsig'
import {useTrendingSettingsApi} from '#/state/preferences/trending' import {useTrendingSettingsApi} from '#/state/preferences/trending'
import {usePostFeedQuery} from '#/state/queries/post-feed' import {usePostFeedQuery} from '#/state/queries/post-feed'
import {RQKEY} from '#/state/queries/post-feed'
import {BlockDrawerGesture} from '#/view/shell/BlockDrawerGesture' import {BlockDrawerGesture} from '#/view/shell/BlockDrawerGesture'
import {atoms as a, useGutters, useTheme} from '#/alf' import {atoms as a, useGutters, useTheme} from '#/alf'
import {Button, ButtonIcon} from '#/components/Button' import {Button, ButtonIcon} from '#/components/Button'
@@ -25,11 +27,32 @@ import {
const CARD_WIDTH = 100 const CARD_WIDTH = 100
const FEED_DESC = `feedgen|${VIDEO_FEED_URI}`
const FEED_PARAMS: {
feedCacheKey: 'discover'
} = {
feedCacheKey: 'discover',
}
export function TrendingVideos() { export function TrendingVideos() {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {_} = useLingui()
const gutters = useGutters([0, 'base']) const gutters = useGutters([0, 'base'])
const {data, isLoading, error} = usePostFeedQuery(`feedgen|${VIDEO_FEED_URI}`) const {data, isLoading, error} = usePostFeedQuery(FEED_DESC, FEED_PARAMS)
// Refetch on unmount if nothing else is using this query.
const queryClient = useQueryClient()
useEffect(() => {
return () => {
const query = queryClient
.getQueryCache()
.find({queryKey: RQKEY(FEED_DESC, FEED_PARAMS)})
if (query && query.getObserversCount() <= 1) {
query.fetch()
}
}
}, [queryClient])
const {setTrendingVideoDisabled} = useTrendingSettingsApi() const {setTrendingVideoDisabled} = useTrendingSettingsApi()
const trendingPrompt = Prompt.usePromptControl() const trendingPrompt = Prompt.usePromptControl()
@@ -138,7 +161,7 @@ function VideoCards({
}, [data]) }, [data])
const href = React.useMemo(() => { const href = React.useMemo(() => {
const urip = new AtUri(VIDEO_FEED_URI) const urip = new AtUri(VIDEO_FEED_URI)
return makeCustomFeedLink(urip.host, urip.rkey) return makeCustomFeedLink(urip.host, urip.rkey, undefined, 'discover')
}, []) }, [])
return ( return (
@@ -151,6 +174,7 @@ function VideoCards({
sourceContext={{ sourceContext={{
type: 'feedgen', type: 'feedgen',
uri: VIDEO_FEED_URI, uri: VIDEO_FEED_URI,
feedCacheKey: 'discover',
}} }}
onInteract={() => { onInteract={() => {
logEvent('videoCard:click', { logEvent('videoCard:click', {
+6 -2
View File
@@ -19,9 +19,13 @@ export function makeProfileLink(
export function makeCustomFeedLink( export function makeCustomFeedLink(
did: string, did: string,
rkey: string, rkey: string,
...segments: string[] segment?: string | undefined,
feedCacheKey?: 'discover' | 'explore' | undefined,
) { ) {
return [`/profile`, did, 'feed', rkey, ...segments].join('/') return (
[`/profile`, did, 'feed', rkey, ...(segment ? [segment] : [])].join('/') +
(feedCacheKey ? `?feedCacheKey=${encodeURIComponent(feedCacheKey)}` : '')
)
} }
export function makeListLink(did: string, rkey: string, ...segments: string[]) { export function makeListLink(did: string, rkey: string, ...segments: string[]) {
+5 -1
View File
@@ -22,7 +22,11 @@ export type CommonNavigatorParams = {
PostLikedBy: {name: string; rkey: string} PostLikedBy: {name: string; rkey: string}
PostRepostedBy: {name: string; rkey: string} PostRepostedBy: {name: string; rkey: string}
PostQuotes: {name: string; rkey: string} PostQuotes: {name: string; rkey: string}
ProfileFeed: {name: string; rkey: string} ProfileFeed: {
name: string
rkey: string
feedCacheKey?: 'discover' | 'explore' | undefined
}
ProfileFeedLikedBy: {name: string; rkey: string} ProfileFeedLikedBy: {name: string; rkey: string}
ProfileLabelerLikedBy: {name: string} ProfileLabelerLikedBy: {name: string}
Debug: undefined Debug: undefined
+21 -3
View File
@@ -21,7 +21,7 @@ import {isNative} from '#/platform/detection'
import {listenSoftReset} from '#/state/events' import {listenSoftReset} from '#/state/events'
import {FeedFeedbackProvider, useFeedFeedback} from '#/state/feed-feedback' import {FeedFeedbackProvider, useFeedFeedback} from '#/state/feed-feedback'
import {FeedSourceFeedInfo, useFeedSourceInfoQuery} from '#/state/queries/feed' import {FeedSourceFeedInfo, useFeedSourceInfoQuery} from '#/state/queries/feed'
import {FeedDescriptor} from '#/state/queries/post-feed' import {FeedDescriptor, FeedParams} from '#/state/queries/post-feed'
import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed' import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed'
import { import {
usePreferencesQuery, usePreferencesQuery,
@@ -49,6 +49,11 @@ type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFeed'>
export function ProfileFeedScreen(props: Props) { export function ProfileFeedScreen(props: Props) {
const {rkey, name: handleOrDid} = props.route.params const {rkey, name: handleOrDid} = props.route.params
const feedParams: FeedParams | undefined = props.route.params.feedCacheKey
? {
feedCacheKey: props.route.params.feedCacheKey,
}
: undefined
const pal = usePalette('default') const pal = usePalette('default')
const {_} = useLingui() const {_} = useLingui()
const navigation = useNavigation<NavigationProp>() const navigation = useNavigation<NavigationProp>()
@@ -99,7 +104,10 @@ export function ProfileFeedScreen(props: Props) {
return resolvedUri ? ( return resolvedUri ? (
<Layout.Screen> <Layout.Screen>
<ProfileFeedScreenIntermediate feedUri={resolvedUri.uri} /> <ProfileFeedScreenIntermediate
feedUri={resolvedUri.uri}
feedParams={feedParams}
/>
</Layout.Screen> </Layout.Screen>
) : ( ) : (
<Layout.Screen> <Layout.Screen>
@@ -111,7 +119,13 @@ export function ProfileFeedScreen(props: Props) {
) )
} }
function ProfileFeedScreenIntermediate({feedUri}: {feedUri: string}) { function ProfileFeedScreenIntermediate({
feedUri,
feedParams,
}: {
feedUri: string
feedParams: FeedParams | undefined
}) {
const {data: preferences} = usePreferencesQuery() const {data: preferences} = usePreferencesQuery()
const {data: info} = useFeedSourceInfoQuery({uri: feedUri}) const {data: info} = useFeedSourceInfoQuery({uri: feedUri})
@@ -128,15 +142,18 @@ function ProfileFeedScreenIntermediate({feedUri}: {feedUri: string}) {
<ProfileFeedScreenInner <ProfileFeedScreenInner
preferences={preferences} preferences={preferences}
feedInfo={info as FeedSourceFeedInfo} feedInfo={info as FeedSourceFeedInfo}
feedParams={feedParams}
/> />
) )
} }
export function ProfileFeedScreenInner({ export function ProfileFeedScreenInner({
feedInfo, feedInfo,
feedParams,
}: { }: {
preferences: UsePreferencesQueryResponse preferences: UsePreferencesQueryResponse
feedInfo: FeedSourceFeedInfo feedInfo: FeedSourceFeedInfo
feedParams: FeedParams | undefined
}) { }) {
const {_} = useLingui() const {_} = useLingui()
const {hasSession} = useSession() const {hasSession} = useSession()
@@ -190,6 +207,7 @@ export function ProfileFeedScreenInner({
<FeedFeedbackProvider value={feedFeedback}> <FeedFeedbackProvider value={feedFeedback}>
<PostFeed <PostFeed
feed={feed} feed={feed}
feedParams={feedParams}
pollInterval={60e3} pollInterval={60e3}
disablePoll={hasNew} disablePoll={hasNew}
onHasNew={setHasNew} onHasNew={setHasNew}
@@ -3,13 +3,15 @@ import {ScrollView, View} from 'react-native'
import {AppBskyEmbedVideo, AtUri} from '@atproto/api' import {AppBskyEmbedVideo, AtUri} from '@atproto/api'
import {msg, Trans} from '@lingui/macro' import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {useFocusEffect} from '@react-navigation/native'
import {useQueryClient} from '@tanstack/react-query'
import {VIDEO_FEED_URI} from '#/lib/constants' import {VIDEO_FEED_URI} from '#/lib/constants'
import {makeCustomFeedLink} from '#/lib/routes/links' import {makeCustomFeedLink} from '#/lib/routes/links'
import {logEvent} from '#/lib/statsig/statsig' import {logEvent} from '#/lib/statsig/statsig'
import {isWeb} from '#/platform/detection' import {isWeb} from '#/platform/detection'
import {useSavedFeeds} from '#/state/queries/feed' import {useSavedFeeds} from '#/state/queries/feed'
import {usePostFeedQuery} from '#/state/queries/post-feed' import {RQKEY, usePostFeedQuery} from '#/state/queries/post-feed'
import {useAddSavedFeedsMutation} from '#/state/queries/preferences' import {useAddSavedFeedsMutation} from '#/state/queries/preferences'
import {BlockDrawerGesture} from '#/view/shell/BlockDrawerGesture' import {BlockDrawerGesture} from '#/view/shell/BlockDrawerGesture'
import {atoms as a, tokens, useGutters, useTheme} from '#/alf' import {atoms as a, tokens, useGutters, useTheme} from '#/alf'
@@ -27,11 +29,31 @@ import {
const CARD_WIDTH = 100 const CARD_WIDTH = 100
const FEED_DESC = `feedgen|${VIDEO_FEED_URI}`
const FEED_PARAMS: {
feedCacheKey: 'explore'
} = {
feedCacheKey: 'explore',
}
export function ExploreTrendingVideos() { export function ExploreTrendingVideos() {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {_} = useLingui()
const gutters = useGutters([0, 'base']) const gutters = useGutters([0, 'base'])
const {data, isLoading, error} = usePostFeedQuery(`feedgen|${VIDEO_FEED_URI}`) const {data, isLoading, error} = usePostFeedQuery(FEED_DESC, FEED_PARAMS)
// Refetch on tab change if nothing else is using this query.
const queryClient = useQueryClient()
useFocusEffect(() => {
return () => {
const query = queryClient
.getQueryCache()
.find({queryKey: RQKEY(FEED_DESC, FEED_PARAMS)})
if (query && query.getObserversCount() <= 1) {
query.fetch()
}
}
})
const {data: saved} = useSavedFeeds() const {data: saved} = useSavedFeeds()
const isSavedAlready = React.useMemo(() => { const isSavedAlready = React.useMemo(() => {
@@ -179,7 +201,7 @@ function VideoCards({
}, [data]) }, [data])
const href = React.useMemo(() => { const href = React.useMemo(() => {
const urip = new AtUri(VIDEO_FEED_URI) const urip = new AtUri(VIDEO_FEED_URI)
return makeCustomFeedLink(urip.host, urip.rkey) return makeCustomFeedLink(urip.host, urip.rkey, undefined, 'explore')
}, []) }, [])
return ( return (
@@ -192,6 +214,7 @@ function VideoCards({
sourceContext={{ sourceContext={{
type: 'feedgen', type: 'feedgen',
uri: VIDEO_FEED_URI, uri: VIDEO_FEED_URI,
feedCacheKey: 'explore',
}} }}
onInteract={() => { onInteract={() => {
logEvent('videoCard:click', { logEvent('videoCard:click', {
+8 -1
View File
@@ -190,7 +190,14 @@ function Feed() {
}, [params]) }, [params])
const feedFeedback = useFeedFeedback(feedDesc, hasSession) const feedFeedback = useFeedFeedback(feedDesc, hasSession)
const {data, error, hasNextPage, isFetchingNextPage, fetchNextPage} = const {data, error, hasNextPage, isFetchingNextPage, fetchNextPage} =
usePostFeedQuery(feedDesc) usePostFeedQuery(
feedDesc,
params.type === 'feedgen' && params.feedCacheKey !== undefined
? {
feedCacheKey: params.feedCacheKey,
}
: undefined,
)
const videos = useMemo(() => { const videos = useMemo(() => {
let vids = let vids =
+6 -1
View File
@@ -4,7 +4,12 @@ import {AuthorFilter} from '#/state/queries/post-feed'
* Kind of like `FeedDescriptor` but not * Kind of like `FeedDescriptor` but not
*/ */
export type VideoFeedSourceContext = export type VideoFeedSourceContext =
| {type: 'feedgen'; uri: string; initialPostUri?: string} | {
type: 'feedgen'
uri: string
initialPostUri?: string
feedCacheKey?: 'discover' | 'explore' | undefined
}
| { | {
type: 'author' type: 'author'
did: string did: string
+1
View File
@@ -61,6 +61,7 @@ export type FeedDescriptor =
export interface FeedParams { export interface FeedParams {
mergeFeedEnabled?: boolean mergeFeedEnabled?: boolean
mergeFeedSources?: string[] mergeFeedSources?: string[]
feedCacheKey?: 'discover' | 'explore' | undefined
} }
type RQPageParam = {cursor: string | undefined; api: FeedAPI} | undefined type RQPageParam = {cursor: string | undefined; api: FeedAPI} | undefined
+3
View File
@@ -208,6 +208,7 @@ let PostFeed = ({
return isNative && gate('yolo') return isNative && gate('yolo')
}, [gate]) }, [gate])
const feedCacheKey = feedParams?.feedCacheKey
const opts = React.useMemo( const opts = React.useMemo(
() => ({enabled, ignoreFilterFor}), () => ({enabled, ignoreFilterFor}),
[enabled, ignoreFilterFor], [enabled, ignoreFilterFor],
@@ -654,6 +655,7 @@ let PostFeed = ({
sourceContext={{ sourceContext={{
type: 'feedgen', type: 'feedgen',
uri: row.sourceFeedUri, uri: row.sourceFeedUri,
feedCacheKey: feedCacheKey,
}} }}
/> />
) )
@@ -670,6 +672,7 @@ let PostFeed = ({
_, _,
onPressRetryLoadMore, onPressRetryLoadMore,
feedUri, feedUri,
feedCacheKey,
], ],
) )