remove memoization since we're using the compiler (#746)

* remove memoization since we're using the compiler

* remove memoization on the track and item rows

* remove memoization from artists list

* remove additional memoization
This commit is contained in:
Violet Caulfield
2025-12-03 20:42:46 -06:00
committed by GitHub
parent cadec335b0
commit af5c02c71a
5 changed files with 576 additions and 736 deletions

View File

@@ -1,6 +1,6 @@
import { ActivityIndicator, RefreshControl } from 'react-native'
import { RefreshControl } from 'react-native'
import { Separator, useTheme, XStack, YStack } from 'tamagui'
import React, { RefObject, useCallback, useEffect, useMemo, useRef } from 'react'
import React, { RefObject, useEffect, useRef } from 'react'
import { Text } from '../Global/helpers/text'
import { FlashList, FlashListRef } from '@shopify/flash-list'
import { UseInfiniteQueryResult } from '@tanstack/react-query'
@@ -39,55 +39,52 @@ export default function Albums({
const pendingLetterRef = useRef<string | null>(null)
// Memoize expensive stickyHeaderIndices calculation to prevent unnecessary re-computations
const stickyHeaderIndices = React.useMemo(() => {
if (!showAlphabeticalSelector || !albumsInfiniteQuery.data) return []
return albumsInfiniteQuery.data
const stickyHeaderIndices =
!showAlphabeticalSelector || !albumsInfiniteQuery.data
? []
: albumsInfiniteQuery.data
.map((album, index) => (typeof album === 'string' ? index : 0))
.filter((value, index, indices) => indices.indexOf(value) === index)
}, [showAlphabeticalSelector, albumsInfiniteQuery.data])
const { mutateAsync: alphabetSelectorMutate, isPending: isAlphabetSelectorPending } =
useAlphabetSelector((letter) => (pendingLetterRef.current = letter.toUpperCase()))
const refreshControl = useMemo(
() => (
const refreshControl = (
<RefreshControl
refreshing={albumsInfiniteQuery.isFetching && !isAlphabetSelectorPending}
onRefresh={albumsInfiniteQuery.refetch}
tintColor={theme.primary.val}
/>
),
[albumsInfiniteQuery.isFetching, isAlphabetSelectorPending, albumsInfiniteQuery.refetch],
)
const ItemSeparatorComponent = useCallback(
({ leadingItem, trailingItem }: { leadingItem: unknown; trailingItem: unknown }) =>
typeof leadingItem === 'string' || typeof trailingItem === 'string' ? null : (
<Separator />
),
[],
)
const ItemSeparatorComponent = ({
leadingItem,
trailingItem,
}: {
leadingItem: unknown
trailingItem: unknown
}) =>
typeof leadingItem === 'string' || typeof trailingItem === 'string' ? null : <Separator />
const keyExtractor = useCallback(
(item: BaseItemDto | string | number) =>
typeof item === 'string' ? item : typeof item === 'number' ? item.toString() : item.Id!,
[],
)
const keyExtractor = (item: BaseItemDto | string | number) =>
typeof item === 'string' ? item : typeof item === 'number' ? item.toString() : item.Id!
const renderItem = useCallback(
({ index, item: album }: { index: number; item: BaseItemDto | string | number }) =>
const renderItem = ({
index,
item: album,
}: {
index: number
item: BaseItemDto | string | number
}) =>
typeof album === 'string' ? (
<FlashListStickyHeader text={album.toUpperCase()} />
) : typeof album === 'number' ? null : typeof album === 'object' ? (
<ItemRow item={album} navigation={navigation} />
) : null,
[navigation],
)
) : null
const onEndReached = useCallback(() => {
const onEndReached = () => {
if (albumsInfiniteQuery.hasNextPage) albumsInfiniteQuery.fetchNextPage()
}, [albumsInfiniteQuery.hasNextPage, albumsInfiniteQuery.fetchNextPage])
}
// Effect for handling the pending alphabet selector letter
useEffect(() => {

View File

@@ -1,5 +1,5 @@
import React, { RefObject, useCallback, useEffect, useMemo, useRef } from 'react'
import { getTokenValue, Separator, useTheme, XStack, YStack } from 'tamagui'
import React, { RefObject, useEffect, useRef } from 'react'
import { Separator, useTheme, XStack, YStack } from 'tamagui'
import { Text } from '../Global/helpers/text'
import { RefreshControl } from 'react-native'
import ItemRow from '../Global/components/item-row'
@@ -50,30 +50,32 @@ export default function Artists({
const { mutateAsync: alphabetSelectorMutate, isPending: isAlphabetSelectorPending } =
useAlphabetSelector((letter) => (pendingLetterRef.current = letter.toUpperCase()))
const stickyHeaderIndices = useMemo(() => {
if (!showAlphabeticalSelector || !artists) return []
return artists
const stickyHeaderIndices =
!showAlphabeticalSelector || !artists
? []
: artists
.map((artist, index, artists) => (typeof artist === 'string' ? index : 0))
.filter((value, index, indices) => indices.indexOf(value) === index)
}, [showAlphabeticalSelector, artists])
const ItemSeparatorComponent = useCallback(
({ leadingItem, trailingItem }: { leadingItem: unknown; trailingItem: unknown }) =>
typeof leadingItem === 'string' || typeof trailingItem === 'string' ? null : (
<Separator />
),
[],
)
const ItemSeparatorComponent = ({
leadingItem,
trailingItem,
}: {
leadingItem: unknown
trailingItem: unknown
}) =>
typeof leadingItem === 'string' || typeof trailingItem === 'string' ? null : <Separator />
const KeyExtractor = useCallback(
(item: BaseItemDto | string | number, index: number) =>
typeof item === 'string' ? item : typeof item === 'number' ? item.toString() : item.Id!,
[],
)
const KeyExtractor = (item: BaseItemDto | string | number, index: number) =>
typeof item === 'string' ? item : typeof item === 'number' ? item.toString() : item.Id!
const renderItem = useCallback(
({ index, item: artist }: { index: number; item: BaseItemDto | number | string }) =>
const renderItem = ({
index,
item: artist,
}: {
index: number
item: BaseItemDto | number | string
}) =>
typeof artist === 'string' ? (
// Don't render the letter if we don't have any artists that start with it
// If the index is the last index, or the next index is not an object, then don't render the letter
@@ -82,9 +84,7 @@ export default function Artists({
)
) : typeof artist === 'number' ? null : typeof artist === 'object' ? (
<ItemRow circular item={artist} navigation={navigation} />
) : null,
[navigation],
)
) : null
// Effect for handling the pending alphabet selector letter
useEffect(() => {

View File

@@ -1,4 +1,4 @@
import React, { RefObject, useEffect, useMemo, useRef, useState } from 'react'
import React, { RefObject, useEffect, useRef, useState } from 'react'
import { LayoutChangeEvent, Platform, View as RNView } from 'react-native'
import { getToken, Spinner, useTheme, View, YStack } from 'tamagui'
import { Gesture, GestureDetector } from 'react-native-gesture-handler'
@@ -61,9 +61,7 @@ export default function AZScroller({
})
}
const panGesture = useMemo(
() =>
Gesture.Pan()
const panGesture = Gesture.Pan()
.runOnJS(true)
.onBegin((e) => {
const relativeY = e.absoluteY - alphabetSelectorTopY.current
@@ -99,13 +97,9 @@ export default function AZScroller({
} else {
scheduleOnRN(hideOverlay)
}
}),
[onLetterSelect],
)
})
const tapGesture = useMemo(
() =>
Gesture.Tap()
const tapGesture = Gesture.Tap()
.runOnJS(true)
.onBegin((e) => {
const relativeY = e.absoluteY - alphabetSelectorTopY.current
@@ -130,9 +124,7 @@ export default function AZScroller({
} else {
scheduleOnRN(hideOverlay)
}
}),
[onLetterSelect],
)
})
const gesture = Gesture.Simultaneous(panGesture, tapGesture)

View File

@@ -14,7 +14,7 @@ import { useNetworkStatus } from '../../../stores/network'
import useStreamingDeviceProfile from '../../../stores/device-profile'
import useItemContext from '../../../hooks/use-item-context'
import { RouteProp, useRoute } from '@react-navigation/native'
import React, { memo, useCallback, useMemo, useState } from 'react'
import React from 'react'
import { LayoutChangeEvent } from 'react-native'
import Animated, {
SharedValue,
@@ -51,14 +51,13 @@ interface ItemRowProps {
* @param navigation - The navigation object.
* @returns
*/
const ItemRow = memo(
function ItemRow({
function ItemRow({
item,
circular,
navigation,
onPress,
queueName,
}: ItemRowProps): React.JSX.Element {
}: ItemRowProps): React.JSX.Element {
const artworkAreaWidth = useSharedValue(0)
const api = useApi()
@@ -76,18 +75,15 @@ const ItemRow = memo(
const warmContext = useItemContext()
const { data: isFavorite } = useIsFavorite(item)
const onPressIn = useCallback(() => warmContext(item), [warmContext, item.Id])
const onPressIn = () => warmContext(item)
const onLongPress = useCallback(
() =>
const onLongPress = () =>
navigationRef.navigate('Context', {
item,
navigation,
}),
[navigationRef, navigation, item.Id],
)
})
const onPressCallback = useCallback(async () => {
const onPressCallback = async () => {
if (onPress) await onPress()
else
switch (item.Type) {
@@ -123,25 +119,19 @@ const ItemRow = memo(
break
}
}
}, [onPress, loadNewQueue, item.Id, navigation, queueName])
}
const renderRunTime = useMemo(
() => item.Type === BaseItemKind.Audio && !hideRunTimes,
[item.Type, hideRunTimes],
)
const renderRunTime = item.Type === BaseItemKind.Audio && !hideRunTimes
const isAudio = useMemo(() => item.Type === 'Audio', [item.Type])
const isAudio = item.Type === 'Audio'
const playlistTrackCount = useMemo(
() => (item.Type === 'Playlist' ? (item.SongCount ?? item.ChildCount ?? 0) : undefined),
[item.Type, item.SongCount, item.ChildCount],
)
const playlistTrackCount =
item.Type === 'Playlist' ? (item.SongCount ?? item.ChildCount ?? 0) : undefined
const leftSettings = useSwipeSettingsStore((s) => s.left)
const rightSettings = useSwipeSettingsStore((s) => s.right)
const swipeHandlers = useCallback(
() => ({
const swipeHandlers = () => ({
addToQueue: async () =>
await addToQueue({
api,
@@ -150,43 +140,26 @@ const ItemRow = memo(
tracks: [item],
queuingType: QueuingType.DirectlyQueued,
}),
toggleFavorite: () =>
isFavorite ? removeFavorite({ item }) : addFavorite({ item }),
toggleFavorite: () => (isFavorite ? removeFavorite({ item }) : addFavorite({ item })),
addToPlaylist: () => navigationRef.navigate('AddToPlaylist', { track: item }),
}),
[
addToQueue,
api,
deviceProfile,
networkStatus,
item,
addFavorite,
removeFavorite,
isFavorite,
],
)
})
const swipeConfig = useMemo(
() =>
isAudio
const swipeConfig = isAudio
? buildSwipeConfig({
left: leftSettings,
right: rightSettings,
handlers: swipeHandlers(),
})
: {},
[isAudio, leftSettings, rightSettings, swipeHandlers],
)
: {}
const handleArtworkLayout = useCallback(
(event: LayoutChangeEvent) => {
const handleArtworkLayout = (event: LayoutChangeEvent) => {
const { width } = event.nativeEvent.layout
artworkAreaWidth.value = width
},
[artworkAreaWidth],
)
}
const pressStyle = useMemo(() => ({ opacity: 0.5 }), [])
const pressStyle = {
opacity: 0.5,
}
return (
<SwipeableRow
@@ -210,11 +183,7 @@ const ItemRow = memo(
backgroundColor={'$background'}
borderRadius={'$2'}
>
<HideableArtwork
item={item}
circular={circular}
onLayout={handleArtworkLayout}
/>
<HideableArtwork item={item} circular={circular} onLayout={handleArtworkLayout} />
<SlidingTextArea leftGapWidth={artworkAreaWidth}>
<ItemRowDetails item={item} />
</SlidingTextArea>
@@ -236,17 +205,9 @@ const ItemRow = memo(
</XStack>
</SwipeableRow>
)
},
(prevProps, nextProps) =>
prevProps.item.Id === nextProps.item.Id &&
prevProps.circular === nextProps.circular &&
prevProps.navigation === nextProps.navigation &&
prevProps.queueName === nextProps.queueName &&
!!prevProps.onPress === !!nextProps.onPress,
)
}
const ItemRowDetails = memo(
function ItemRowDetails({ item }: { item: BaseItemDto }): React.JSX.Element {
function ItemRowDetails({ item }: { item: BaseItemDto }): React.JSX.Element {
const route = useRoute<RouteProp<BaseStackParamList>>()
const shouldRenderArtistName =
@@ -254,8 +215,7 @@ const ItemRowDetails = memo(
const shouldRenderProductionYear = item.Type === 'MusicAlbum' && route.name === 'Artist'
const shouldRenderGenres =
item.Type === 'Playlist' || item.Type === BaseItemKind.MusicArtist
const shouldRenderGenres = item.Type === 'Playlist' || item.Type === BaseItemKind.MusicArtist
return (
<YStack alignContent='center' justifyContent='center' flexGrow={1}>
@@ -271,11 +231,7 @@ const ItemRowDetails = memo(
{shouldRenderProductionYear && (
<XStack gap='$2'>
<Text
color={'$borderColor'}
lineBreakStrategyIOS='standard'
numberOfLines={1}
>
<Text color={'$borderColor'} lineBreakStrategyIOS='standard' numberOfLines={1}>
{item.ProductionYear?.toString() ?? 'Unknown Year'}
</Text>
@@ -292,21 +248,18 @@ const ItemRowDetails = memo(
)}
</YStack>
)
},
(prevProps, nextProps) => prevProps.item.Id === nextProps.item.Id,
)
}
// Artwork wrapper that fades out when the quick-action menu is open
const HideableArtwork = memo(
function HideableArtwork({
function HideableArtwork({
item,
circular,
onLayout,
}: {
}: {
item: BaseItemDto
circular?: boolean
onLayout?: (event: LayoutChangeEvent) => void
}): React.JSX.Element {
}): React.JSX.Element {
const { tx } = useSwipeableRowContext()
// Hide artwork as soon as swiping starts (any non-zero tx)
const style = useAnimatedStyle(() => ({
@@ -324,25 +277,18 @@ const HideableArtwork = memo(
</XStack>
</Animated.View>
)
},
(prevProps, nextProps) =>
prevProps.item.Id === nextProps.item.Id &&
prevProps.circular === nextProps.circular &&
!!prevProps.onLayout === !!nextProps.onLayout,
)
}
const SlidingTextArea = memo(
function SlidingTextArea({
function SlidingTextArea({
leftGapWidth,
children,
}: {
}: {
leftGapWidth: SharedValue<number>
children: React.ReactNode
}): React.JSX.Element {
}): React.JSX.Element {
const { tx, rightWidth } = useSwipeableRowContext()
const tokenValue = getToken('$2', 'space')
const spacingValue =
typeof tokenValue === 'number' ? tokenValue : parseFloat(`${tokenValue}`)
const spacingValue = typeof tokenValue === 'number' ? tokenValue : parseFloat(`${tokenValue}`)
const quickActionBuffer = Number.isFinite(spacingValue) ? spacingValue : 8
const style = useAnimatedStyle(() => {
const t = tx.value
@@ -363,10 +309,6 @@ const SlidingTextArea = memo(
{children}
</Animated.View>
)
},
(prevProps, nextProps) =>
prevProps.leftGapWidth === nextProps.leftGapWidth &&
prevProps.children?.valueOf() === nextProps.children?.valueOf(),
)
}
export default ItemRow

View File

@@ -1,4 +1,4 @@
import React, { useMemo, useCallback, useState, memo } from 'react'
import React, { useState } from 'react'
import { getToken, Theme, useTheme, XStack, YStack } from 'tamagui'
import { Text } from '../helpers/text'
import { RunTimeTicks } from '../helpers/time-codes'
@@ -28,10 +28,7 @@ import { useAddFavorite, useRemoveFavorite } from '../../../api/mutations/favori
import { StackActions } from '@react-navigation/native'
import { useSwipeableRowContext } from './swipeable-row-context'
import { useHideRunTimesSetting } from '../../../stores/settings/app'
import { queryClient, ONE_HOUR } from '../../../constants/query-client'
import { fetchMediaInfo } from '../../../api/queries/media/utils'
import MediaInfoQueryKey from '../../../api/queries/media/keys'
import JellifyTrack from '../../../types/JellifyTrack'
import useStreamedMediaInfo from '../../../api/queries/media'
export interface TrackProps {
track: BaseItemDto
@@ -48,21 +45,7 @@ export interface TrackProps {
editing?: boolean | undefined
}
const queueItemsCache = new WeakMap<JellifyTrack[], BaseItemDto[]>()
const getQueueItems = (queue: JellifyTrack[] | undefined): BaseItemDto[] => {
if (!queue?.length) return []
const cached = queueItemsCache.get(queue)
if (cached) return cached
const mapped = queue.map((entry) => entry.item)
queueItemsCache.set(queue, mapped)
return mapped
}
const Track = memo(
function Track({
export default function Track({
track,
navigation,
tracklist,
@@ -75,7 +58,7 @@ const Track = memo(
isNested,
invertedColors,
editing,
}: TrackProps): React.JSX.Element {
}: TrackProps): React.JSX.Element {
const theme = useTheme()
const [artworkAreaWidth, setArtworkAreaWidth] = useState(0)
@@ -91,6 +74,8 @@ const Track = memo(
const addToQueue = useAddToQueue()
const [networkStatus] = useNetworkStatus()
const { data: mediaInfo } = useStreamedMediaInfo(track.Id)
const offlineAudio = useDownloadedTrack(track.Id)
const { mutate: addFavorite } = useAddFavorite()
@@ -100,24 +85,15 @@ const Track = memo(
const rightSettings = useSwipeSettingsStore((s) => s.right)
// Memoize expensive computations
const isPlaying = useMemo(
() => nowPlaying?.item.Id === track.Id,
[nowPlaying?.item.Id, track.Id],
)
const isPlaying = nowPlaying?.item.Id === track.Id
const isOffline = useMemo(
() => networkStatus === networkStatusTypes.DISCONNECTED,
[networkStatus],
)
const isOffline = networkStatus === networkStatusTypes.DISCONNECTED
// Memoize tracklist for queue loading
const memoizedTracklist = useMemo(
() => tracklist ?? getQueueItems(playQueue),
[tracklist, playQueue],
)
const memoizedTracklist = tracklist ?? playQueue?.map((track) => track.item) ?? []
// Memoize handlers to prevent recreation
const handlePress = useCallback(async () => {
const handlePress = async () => {
if (onPress) {
await onPress()
} else {
@@ -133,79 +109,56 @@ const Track = memo(
startPlayback: true,
})
}
}, [
onPress,
api,
deviceProfile,
networkStatus,
track,
index,
memoizedTracklist,
queue,
loadNewQueue,
])
const fetchStreamingMediaSourceInfo = useCallback(async () => {
if (!api || !deviceProfile || !track.Id) return undefined
const queryKey = MediaInfoQueryKey({ api, deviceProfile, itemId: track.Id })
try {
const info = await queryClient.ensureQueryData({
queryKey,
queryFn: () => fetchMediaInfo(api, deviceProfile, track.Id),
staleTime: ONE_HOUR,
gcTime: ONE_HOUR,
})
return info.MediaSources?.[0]
} catch (error) {
console.warn('Failed to fetch media info for context sheet', error)
return undefined
}
}, [api, deviceProfile, track.Id])
const openContextSheet = useCallback(async () => {
const streamingMediaSourceInfo = await fetchStreamingMediaSourceInfo()
const handleLongPress = () => {
if (onLongPress) {
onLongPress()
} else {
navigationRef.navigate('Context', {
item: track,
navigation,
streamingMediaSourceInfo,
streamingMediaSourceInfo: mediaInfo?.MediaSources
? mediaInfo!.MediaSources![0]
: undefined,
downloadedMediaSourceInfo: offlineAudio?.mediaSourceInfo,
})
}, [fetchStreamingMediaSourceInfo, track, navigation, offlineAudio?.mediaSourceInfo])
const handleLongPress = useCallback(() => {
if (onLongPress) {
onLongPress()
return
}
}
void openContextSheet()
}, [onLongPress, openContextSheet])
const handleIconPress = () => {
navigationRef.navigate('Context', {
item: track,
navigation,
streamingMediaSourceInfo: mediaInfo?.MediaSources
? mediaInfo!.MediaSources![0]
: undefined,
downloadedMediaSourceInfo: offlineAudio?.mediaSourceInfo,
})
}
const handleIconPress = useCallback(() => {
void openContextSheet()
}, [openContextSheet])
// Memoize text color to prevent recalculation
const textColor = isPlaying
? theme.primary.val
: isOffline
? offlineAudio
? theme.color
: theme.neutral.val
: theme.color
// Memoize artists text
const artistsText = useMemo(() => track.Artists?.join(', ') ?? '', [track.Artists])
const artistsText = track.Artists?.join(', ') ?? ''
// Memoize track name
const trackName = useMemo(() => track.Name ?? 'Untitled Track', [track.Name])
const trackName = track.Name ?? 'Untitled Track'
// Memoize index number
const indexNumber = useMemo(() => track.IndexNumber?.toString() ?? '', [track.IndexNumber])
const indexNumber = track.IndexNumber?.toString() ?? ''
// Memoize show artists condition
const shouldShowArtists = useMemo(
() => showArtwork || (track.Artists && track.Artists.length > 1),
[showArtwork, track.Artists],
)
const shouldShowArtists = showArtwork || (track.Artists && track.Artists.length > 1)
const swipeHandlers = useMemo(
() => ({
const swipeHandlers = {
addToQueue: async () => {
console.info('Running add to queue swipe action')
await addToQueue({
@@ -217,9 +170,7 @@ const Track = memo(
})
},
toggleFavorite: () => {
console.info(
`Running ${isFavoriteTrack ? 'Remove' : 'Add'} favorite swipe action`,
)
console.info(`Running ${isFavoriteTrack ? 'Remove' : 'Add'} favorite swipe action`)
if (isFavoriteTrack) removeFavorite({ item: track })
else addFavorite({ item: track })
},
@@ -227,38 +178,15 @@ const Track = memo(
console.info('Running add to playlist swipe handler')
navigationRef.dispatch(StackActions.push('AddToPlaylist', { track }))
},
}),
[
addToQueue,
api,
deviceProfile,
networkStatus,
track,
addFavorite,
removeFavorite,
isFavoriteTrack,
navigationRef,
],
)
}
const swipeConfig = useMemo(
() =>
buildSwipeConfig({
const swipeConfig = buildSwipeConfig({
left: leftSettings,
right: rightSettings,
handlers: swipeHandlers,
}),
[leftSettings, rightSettings, swipeHandlers],
)
})
const textColor = useMemo(
() => (isPlaying ? theme.primary.val : theme.color.val),
[isPlaying],
)
const runtimeComponent = useMemo(
() =>
hideRunTimes ? (
const runtimeComponent = hideRunTimes ? (
<></>
) : (
<RunTimeTicks
@@ -273,8 +201,6 @@ const Track = memo(
>
{track.RunTimeTicks}
</RunTimeTicks>
),
[hideRunTimes, track.RunTimeTicks],
)
return (
@@ -321,7 +247,7 @@ const Track = memo(
</XStack>
<SlidingTextArea leftGapWidth={artworkAreaWidth} hasArtwork={!!showArtwork}>
<YStack alignItems='flex-start' justifyContent='center' flex={6}>
<YStack alignItems='flex-start' justifyContent='center' flex={1}>
<Text
key={`${track.Id}-name`}
bold
@@ -345,32 +271,17 @@ const Track = memo(
</YStack>
</SlidingTextArea>
<XStack justifyContent='flex-end' alignItems='center' flex={2} gap='$1'>
<XStack justifyContent='flex-end' alignItems='center' flexShrink={1} gap='$1'>
<DownloadedIcon item={track} />
<FavoriteIcon item={track} />
{runtimeComponent}
{!editing && (
<Icon name={'dots-horizontal'} onPress={handleIconPress} />
)}
{!editing && <Icon name={'dots-horizontal'} onPress={handleIconPress} />}
</XStack>
</XStack>
</SwipeableRow>
</Theme>
)
},
(prevProps, nextProps) =>
prevProps.track.Id === nextProps.track.Id &&
prevProps.index === nextProps.index &&
prevProps.showArtwork === nextProps.showArtwork &&
prevProps.isNested === nextProps.isNested &&
prevProps.invertedColors === nextProps.invertedColors &&
prevProps.testID === nextProps.testID &&
prevProps.editing === nextProps.editing &&
prevProps.queue === nextProps.queue &&
prevProps.tracklist === nextProps.tracklist &&
!!prevProps.onPress === !!nextProps.onPress &&
!!prevProps.onLongPress === !!nextProps.onLongPress,
)
}
function HideableArtwork({ children }: { children: React.ReactNode }) {
const { tx } = useSwipeableRowContext()
@@ -402,7 +313,5 @@ function SlidingTextArea({
}
return { transform: [{ translateX: offset }] }
})
return <Animated.View style={[{ flex: 5 }, style]}>{children}</Animated.View>
return <Animated.View style={[{ flex: 1 }, style]}>{children}</Animated.View>
}
export default Track