Optimize Drawer re-renders (#2108)

zio/stable
dan 2023-12-06 17:50:06 +00:00 committed by GitHub
parent 8e541d753a
commit 7d158f82fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 315 additions and 185 deletions

View File

@ -55,13 +55,13 @@ import {RQKEY as NOTIFS_RQKEY} from '#/state/queries/notifications/feed'
import {NavSignupCard} from '#/view/shell/NavSignupCard'
import {truncateAndInvalidate} from '#/state/queries/util'
export function DrawerProfileCard({
let DrawerProfileCard = ({
account,
onPressProfile,
}: {
account: SessionAccount
onPressProfile: () => void
}) {
}): React.ReactNode => {
const {_} = useLingui()
const pal = usePalette('default')
const {data: profile} = useProfileQuery({did: account.did})
@ -103,11 +103,12 @@ export function DrawerProfileCard({
</TouchableOpacity>
)
}
DrawerProfileCard = React.memo(DrawerProfileCard)
export {DrawerProfileCard}
export function DrawerContent() {
let DrawerContent = ({}: {}): React.ReactNode => {
const theme = useTheme()
const pal = usePalette('default')
const {_} = useLingui()
const queryClient = useQueryClient()
const setDrawerOpen = useSetDrawerOpen()
const navigation = useNavigation<NavigationProp>()
@ -115,7 +116,6 @@ export function DrawerContent() {
const {isAtHome, isAtSearch, isAtFeeds, isAtNotifications, isAtMyProfile} =
useNavigationTabState()
const {hasSession, currentAccount} = useSession()
const numUnreadNotifications = useUnreadNotifications()
// events
// =
@ -229,158 +229,26 @@ export function DrawerContent() {
<NavSignupCard />
)}
{hasSession && <InviteCodes style={{paddingLeft: 0}} />}
{hasSession && <InviteCodes />}
{hasSession && <View style={{height: 10}} />}
<MenuItem
icon={
isAtSearch ? (
<MagnifyingGlassIcon2Solid
style={pal.text as StyleProp<ViewStyle>}
size={24}
strokeWidth={1.7}
/>
) : (
<MagnifyingGlassIcon2
style={pal.text as StyleProp<ViewStyle>}
size={24}
strokeWidth={1.7}
/>
)
}
label={_(msg`Search`)}
accessibilityLabel={_(msg`Search`)}
accessibilityHint=""
bold={isAtSearch}
onPress={onPressSearch}
/>
<MenuItem
icon={
isAtHome ? (
<HomeIconSolid
style={pal.text as StyleProp<ViewStyle>}
size="24"
strokeWidth={3.25}
/>
) : (
<HomeIcon
style={pal.text as StyleProp<ViewStyle>}
size="24"
strokeWidth={3.25}
/>
)
}
label={_(msg`Home`)}
accessibilityLabel={_(msg`Home`)}
accessibilityHint=""
bold={isAtHome}
onPress={onPressHome}
/>
<SearchMenuItem isActive={isAtSearch} onPress={onPressSearch} />
<HomeMenuItem isActive={isAtHome} onPress={onPressHome} />
{hasSession && (
<MenuItem
icon={
isAtNotifications ? (
<BellIconSolid
style={pal.text as StyleProp<ViewStyle>}
size="24"
strokeWidth={1.7}
/>
) : (
<BellIcon
style={pal.text as StyleProp<ViewStyle>}
size="24"
strokeWidth={1.7}
/>
)
}
label={_(msg`Notifications`)}
accessibilityLabel={_(msg`Notifications`)}
accessibilityHint={
numUnreadNotifications === ''
? ''
: `${numUnreadNotifications} unread`
}
count={numUnreadNotifications}
bold={isAtNotifications}
<NotificationsMenuItem
isActive={isAtNotifications}
onPress={onPressNotifications}
/>
)}
<MenuItem
icon={
isAtFeeds ? (
<HashtagIcon
strokeWidth={3}
style={pal.text as FontAwesomeIconStyle}
size={24}
/>
) : (
<HashtagIcon
strokeWidth={2}
style={pal.text as FontAwesomeIconStyle}
size={24}
/>
)
}
label={_(msg`Feeds`)}
accessibilityLabel={_(msg`Feeds`)}
accessibilityHint=""
bold={isAtFeeds}
onPress={onPressMyFeeds}
/>
<FeedsMenuItem isActive={isAtFeeds} onPress={onPressMyFeeds} />
{hasSession && (
<>
<MenuItem
icon={<ListIcon strokeWidth={2} style={pal.text} size={26} />}
label={_(msg`Lists`)}
accessibilityLabel={_(msg`Lists`)}
accessibilityHint=""
onPress={onPressLists}
/>
<MenuItem
icon={<HandIcon strokeWidth={5} style={pal.text} size={24} />}
label={_(msg`Moderation`)}
accessibilityLabel={_(msg`Moderation`)}
accessibilityHint=""
onPress={onPressModeration}
/>
<MenuItem
icon={
isAtMyProfile ? (
<UserIconSolid
style={pal.text as StyleProp<ViewStyle>}
size="26"
strokeWidth={1.5}
/>
) : (
<UserIcon
style={pal.text as StyleProp<ViewStyle>}
size="26"
strokeWidth={1.5}
/>
)
}
label={_(msg`Profile`)}
accessibilityLabel={_(msg`Profile`)}
accessibilityHint=""
<ListsMenuItem onPress={onPressLists} />
<ModerationMenuItem onPress={onPressModeration} />
<ProfileMenuItem
isActive={isAtMyProfile}
onPress={onPressProfile}
/>
<MenuItem
icon={
<CogIcon
style={pal.text as StyleProp<ViewStyle>}
size="26"
strokeWidth={1.75}
/>
}
label={_(msg`Settings`)}
accessibilityLabel={_(msg`Settings`)}
accessibilityHint=""
onPress={onPressSettings}
/>
<SettingsMenuItem onPress={onPressSettings} />
</>
)}
@ -388,43 +256,64 @@ export function DrawerContent() {
<View style={styles.smallSpacer} />
</ScrollView>
<View style={styles.footer}>
<TouchableOpacity
accessibilityRole="link"
accessibilityLabel={_(msg`Send feedback`)}
accessibilityHint=""
onPress={onPressFeedback}
style={[
styles.footerBtn,
styles.footerBtnFeedback,
theme.colorScheme === 'light'
? styles.footerBtnFeedbackLight
: styles.footerBtnFeedbackDark,
]}>
<FontAwesomeIcon
style={pal.link as FontAwesomeIconStyle}
size={18}
icon={['far', 'message']}
/>
<Text type="lg-medium" style={[pal.link, s.pl10]}>
<Trans>Feedback</Trans>
</Text>
</TouchableOpacity>
<TouchableOpacity
accessibilityRole="link"
accessibilityLabel={_(msg`Send feedback`)}
accessibilityHint=""
onPress={onPressHelp}
style={[styles.footerBtn]}>
<Text type="lg-medium" style={[pal.link, s.pl10]}>
<Trans>Help</Trans>
</Text>
</TouchableOpacity>
</View>
<DrawerFooter
onPressFeedback={onPressFeedback}
onPressHelp={onPressHelp}
/>
</SafeAreaView>
</View>
)
}
DrawerContent = React.memo(DrawerContent)
export {DrawerContent}
let DrawerFooter = ({
onPressFeedback,
onPressHelp,
}: {
onPressFeedback: () => void
onPressHelp: () => void
}): React.ReactNode => {
const theme = useTheme()
const pal = usePalette('default')
const {_} = useLingui()
return (
<View style={styles.footer}>
<TouchableOpacity
accessibilityRole="link"
accessibilityLabel={_(msg`Send feedback`)}
accessibilityHint=""
onPress={onPressFeedback}
style={[
styles.footerBtn,
styles.footerBtnFeedback,
theme.colorScheme === 'light'
? styles.footerBtnFeedbackLight
: styles.footerBtnFeedbackDark,
]}>
<FontAwesomeIcon
style={pal.link as FontAwesomeIconStyle}
size={18}
icon={['far', 'message']}
/>
<Text type="lg-medium" style={[pal.link, s.pl10]}>
<Trans>Feedback</Trans>
</Text>
</TouchableOpacity>
<TouchableOpacity
accessibilityRole="link"
accessibilityLabel={_(msg`Send feedback`)}
accessibilityHint=""
onPress={onPressHelp}
style={[styles.footerBtn]}>
<Text type="lg-medium" style={[pal.link, s.pl10]}>
<Trans>Help</Trans>
</Text>
</TouchableOpacity>
</View>
)
}
DrawerFooter = React.memo(DrawerFooter)
interface MenuItemProps extends ComponentProps<typeof TouchableOpacity> {
icon: JSX.Element
@ -433,6 +322,244 @@ interface MenuItemProps extends ComponentProps<typeof TouchableOpacity> {
bold?: boolean
}
let SearchMenuItem = ({
isActive,
onPress,
}: {
isActive: boolean
onPress: () => void
}): React.ReactNode => {
const {_} = useLingui()
const pal = usePalette('default')
return (
<MenuItem
icon={
isActive ? (
<MagnifyingGlassIcon2Solid
style={pal.text as StyleProp<ViewStyle>}
size={24}
strokeWidth={1.7}
/>
) : (
<MagnifyingGlassIcon2
style={pal.text as StyleProp<ViewStyle>}
size={24}
strokeWidth={1.7}
/>
)
}
label={_(msg`Search`)}
accessibilityLabel={_(msg`Search`)}
accessibilityHint=""
bold={isActive}
onPress={onPress}
/>
)
}
SearchMenuItem = React.memo(SearchMenuItem)
let HomeMenuItem = ({
isActive,
onPress,
}: {
isActive: boolean
onPress: () => void
}): React.ReactNode => {
const {_} = useLingui()
const pal = usePalette('default')
return (
<MenuItem
icon={
isActive ? (
<HomeIconSolid
style={pal.text as StyleProp<ViewStyle>}
size="24"
strokeWidth={3.25}
/>
) : (
<HomeIcon
style={pal.text as StyleProp<ViewStyle>}
size="24"
strokeWidth={3.25}
/>
)
}
label={_(msg`Home`)}
accessibilityLabel={_(msg`Home`)}
accessibilityHint=""
bold={isActive}
onPress={onPress}
/>
)
}
HomeMenuItem = React.memo(HomeMenuItem)
let NotificationsMenuItem = ({
isActive,
onPress,
}: {
isActive: boolean
onPress: () => void
}): React.ReactNode => {
const {_} = useLingui()
const pal = usePalette('default')
const numUnreadNotifications = useUnreadNotifications()
return (
<MenuItem
icon={
isActive ? (
<BellIconSolid
style={pal.text as StyleProp<ViewStyle>}
size="24"
strokeWidth={1.7}
/>
) : (
<BellIcon
style={pal.text as StyleProp<ViewStyle>}
size="24"
strokeWidth={1.7}
/>
)
}
label={_(msg`Notifications`)}
accessibilityLabel={_(msg`Notifications`)}
accessibilityHint={
numUnreadNotifications === '' ? '' : `${numUnreadNotifications} unread`
}
count={numUnreadNotifications}
bold={isActive}
onPress={onPress}
/>
)
}
NotificationsMenuItem = React.memo(NotificationsMenuItem)
let FeedsMenuItem = ({
isActive,
onPress,
}: {
isActive: boolean
onPress: () => void
}): React.ReactNode => {
const {_} = useLingui()
const pal = usePalette('default')
return (
<MenuItem
icon={
isActive ? (
<HashtagIcon
strokeWidth={3}
style={pal.text as FontAwesomeIconStyle}
size={24}
/>
) : (
<HashtagIcon
strokeWidth={2}
style={pal.text as FontAwesomeIconStyle}
size={24}
/>
)
}
label={_(msg`Feeds`)}
accessibilityLabel={_(msg`Feeds`)}
accessibilityHint=""
bold={isActive}
onPress={onPress}
/>
)
}
FeedsMenuItem = React.memo(FeedsMenuItem)
let ListsMenuItem = ({onPress}: {onPress: () => void}): React.ReactNode => {
const {_} = useLingui()
const pal = usePalette('default')
return (
<MenuItem
icon={<ListIcon strokeWidth={2} style={pal.text} size={26} />}
label={_(msg`Lists`)}
accessibilityLabel={_(msg`Lists`)}
accessibilityHint=""
onPress={onPress}
/>
)
}
ListsMenuItem = React.memo(ListsMenuItem)
let ModerationMenuItem = ({
onPress,
}: {
onPress: () => void
}): React.ReactNode => {
const {_} = useLingui()
const pal = usePalette('default')
return (
<MenuItem
icon={<HandIcon strokeWidth={5} style={pal.text} size={24} />}
label={_(msg`Moderation`)}
accessibilityLabel={_(msg`Moderation`)}
accessibilityHint=""
onPress={onPress}
/>
)
}
ModerationMenuItem = React.memo(ModerationMenuItem)
let ProfileMenuItem = ({
isActive,
onPress,
}: {
isActive: boolean
onPress: () => void
}): React.ReactNode => {
const {_} = useLingui()
const pal = usePalette('default')
return (
<MenuItem
icon={
isActive ? (
<UserIconSolid
style={pal.text as StyleProp<ViewStyle>}
size="26"
strokeWidth={1.5}
/>
) : (
<UserIcon
style={pal.text as StyleProp<ViewStyle>}
size="26"
strokeWidth={1.5}
/>
)
}
label={_(msg`Profile`)}
accessibilityLabel={_(msg`Profile`)}
accessibilityHint=""
onPress={onPress}
/>
)
}
ProfileMenuItem = React.memo(ProfileMenuItem)
let SettingsMenuItem = ({onPress}: {onPress: () => void}): React.ReactNode => {
const {_} = useLingui()
const pal = usePalette('default')
return (
<MenuItem
icon={
<CogIcon
style={pal.text as StyleProp<ViewStyle>}
size="26"
strokeWidth={1.75}
/>
}
label={_(msg`Settings`)}
accessibilityLabel={_(msg`Settings`)}
accessibilityHint=""
onPress={onPress}
/>
)
}
SettingsMenuItem = React.memo(SettingsMenuItem)
function MenuItem({
icon,
label,
@ -478,7 +605,7 @@ function MenuItem({
)
}
function InviteCodes({style}: {style?: StyleProp<ViewStyle>}) {
let InviteCodes = ({}: {}): React.ReactNode => {
const {track} = useAnalytics()
const setDrawerOpen = useSetDrawerOpen()
const pal = usePalette('default')
@ -496,7 +623,7 @@ function InviteCodes({style}: {style?: StyleProp<ViewStyle>}) {
return (
<TouchableOpacity
testID="menuItemInviteCodes"
style={[styles.inviteCodes, style]}
style={styles.inviteCodes}
onPress={onPress}
accessibilityRole="button"
accessibilityLabel={_(msg`Invite codes: ${invitesAvailable} available`)}
@ -526,6 +653,7 @@ function InviteCodes({style}: {style?: StyleProp<ViewStyle>}) {
</TouchableOpacity>
)
}
InviteCodes = React.memo(InviteCodes)
const styles = StyleSheet.create({
view: {
@ -595,7 +723,7 @@ const styles = StyleSheet.create({
},
inviteCodes: {
paddingLeft: 22,
paddingLeft: 0,
paddingVertical: 8,
flexDirection: 'row',
},

View File

@ -11,7 +11,7 @@ import {Button} from '#/view/com/util/forms/Button'
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
import {useCloseAllActiveElements} from '#/state/util'
export function NavSignupCard() {
let NavSignupCard = ({}: {}): React.ReactNode => {
const {_} = useLingui()
const pal = usePalette('default')
const {setShowLoggedOut} = useLoggedOutViewControls()
@ -59,3 +59,5 @@ export function NavSignupCard() {
</View>
)
}
NavSignupCard = React.memo(NavSignupCard)
export {NavSignupCard}