refactor(navigation): replace direct navigation with navigation service
Some checks failed
Frontend CI / ota-android (push) Has been cancelled
Frontend CI / build-android-apk (push) Has been cancelled
Frontend CI / build-and-push-web (push) Has been cancelled

Replace direct `navigation.navigate()` and `navigation.getParent()?.navigate()` calls with centralized `navigationService.navigate()` across multiple screens. Convert screen component functions from JSX elements to array-returning functions in RootNavigator to fix React key warnings and improve render consistency.

- HomeScreen: use navigationService for post and user navigation
- PrivateChatInfoScreen: use navigationService for profile navigation
- ChatScreen: use navigationService for avatar press and user profile navigation
- RootNavigator: convert PublicScreens and AuthenticatedScreens to getPublicScreens() and getAuthenticatedScreens() functions returning arrays with proper keys
This commit is contained in:
lafay
2026-03-18 14:52:58 +08:00
parent a8f7e907b6
commit 2321c2dc06
4 changed files with 181 additions and 170 deletions

View File

@@ -41,166 +41,176 @@ interface RootNavigatorProps {
isInitializing: boolean; isInitializing: boolean;
} }
// 未认证时可访问的屏幕 // 未认证时可访问的屏幕 - 返回数组而不是 JSX
const PublicScreens = () => ( const getPublicScreens = () => [
<> <RootStack.Screen
<RootStack.Screen key="PostDetail"
name="PostDetail" name="PostDetail"
component={PostDetailScreen} component={PostDetailScreen}
options={{ options={{
headerShown: true, headerShown: true,
title: '', title: '',
headerStyle: { backgroundColor: colors.background.paper }, headerStyle: { backgroundColor: colors.background.paper },
headerTintColor: colors.text.primary, headerTintColor: colors.text.primary,
animation: 'slide_from_right', animation: 'slide_from_right',
}} }}
/> />,
<RootStack.Screen <RootStack.Screen
name="UserProfile" key="UserProfile"
component={UserScreen} name="UserProfile"
options={{ component={UserScreen}
headerShown: true, options={{
title: '用户主页', headerShown: true,
headerStyle: { backgroundColor: colors.background.paper }, title: '用户主页',
headerTintColor: colors.text.primary, headerStyle: { backgroundColor: colors.background.paper },
}} headerTintColor: colors.text.primary,
/> }}
</> />,
); ];
// 认证后可访问的屏幕 // 认证后可访问的屏幕 - 返回数组而不是 JSX
const AuthenticatedScreens = () => ( const getAuthenticatedScreens = () => [
<> <RootStack.Screen
<RootStack.Screen key="PostDetail"
name="PostDetail" name="PostDetail"
component={PostDetailScreen} component={PostDetailScreen}
options={{ options={{
headerShown: true, headerShown: true,
title: '', title: '',
headerStyle: { backgroundColor: colors.background.paper }, headerStyle: { backgroundColor: colors.background.paper },
headerTintColor: colors.text.primary, headerTintColor: colors.text.primary,
animation: 'slide_from_right', animation: 'slide_from_right',
}} }}
/> />,
<RootStack.Screen <RootStack.Screen
name="UserProfile" key="UserProfile"
component={UserScreen} name="UserProfile"
options={{ component={UserScreen}
headerShown: true, options={{
title: '用户主页', headerShown: true,
headerStyle: { backgroundColor: colors.background.paper }, title: '用户主页',
headerTintColor: colors.text.primary, headerStyle: { backgroundColor: colors.background.paper },
}} headerTintColor: colors.text.primary,
/> }}
<RootStack.Screen />,
name="CreatePost" <RootStack.Screen
component={CreatePostScreen} key="CreatePost"
options={{ name="CreatePost"
headerShown: true, component={CreatePostScreen}
title: '发布帖子', options={{
headerStyle: { backgroundColor: colors.background.paper }, headerShown: true,
headerTintColor: colors.text.primary, title: '发布帖子',
presentation: 'modal', headerStyle: { backgroundColor: colors.background.paper },
}} headerTintColor: colors.text.primary,
/> presentation: 'modal',
<RootStack.Screen }}
name="Chat" />,
component={ChatScreen} <RootStack.Screen
options={{ key="Chat"
headerShown: false, name="Chat"
animation: 'slide_from_right', component={ChatScreen}
}} options={{
/> headerShown: false,
<RootStack.Screen animation: 'slide_from_right',
name="FollowList" }}
component={FollowListScreen} />,
options={{ <RootStack.Screen
headerShown: true, key="FollowList"
title: '关注列表', name="FollowList"
headerStyle: { backgroundColor: colors.background.paper }, component={FollowListScreen}
headerTintColor: colors.text.primary, options={{
animation: 'slide_from_right', headerShown: true,
}} title: '关注列表',
/> headerStyle: { backgroundColor: colors.background.paper },
<RootStack.Screen headerTintColor: colors.text.primary,
name="CreateGroup" animation: 'slide_from_right',
component={CreateGroupScreen} }}
options={{ />,
headerShown: true, <RootStack.Screen
title: '创建群聊', key="CreateGroup"
headerStyle: { backgroundColor: colors.background.paper }, name="CreateGroup"
headerTintColor: colors.text.primary, component={CreateGroupScreen}
presentation: 'modal', options={{
}} headerShown: true,
/> title: '创建群聊',
<RootStack.Screen headerStyle: { backgroundColor: colors.background.paper },
name="JoinGroup" headerTintColor: colors.text.primary,
component={JoinGroupScreen} presentation: 'modal',
options={{ }}
headerShown: true, />,
title: '搜索群聊', <RootStack.Screen
headerStyle: { backgroundColor: colors.background.paper }, key="JoinGroup"
headerTintColor: colors.text.primary, name="JoinGroup"
animation: 'slide_from_right', component={JoinGroupScreen}
}} options={{
/> headerShown: true,
<RootStack.Screen title: '搜索群聊',
name="GroupInfo" headerStyle: { backgroundColor: colors.background.paper },
component={GroupInfoScreen} headerTintColor: colors.text.primary,
options={{ animation: 'slide_from_right',
headerShown: true, }}
title: '群信息', />,
headerStyle: { backgroundColor: colors.background.paper }, <RootStack.Screen
headerTintColor: colors.text.primary, key="GroupInfo"
animation: 'slide_from_right', name="GroupInfo"
}} component={GroupInfoScreen}
/> options={{
<RootStack.Screen headerShown: true,
name="GroupMembers" title: '群信息',
component={GroupMembersScreen} headerStyle: { backgroundColor: colors.background.paper },
options={{ headerTintColor: colors.text.primary,
headerShown: true, animation: 'slide_from_right',
title: '群成员', }}
headerStyle: { backgroundColor: colors.background.paper }, />,
headerTintColor: colors.text.primary, <RootStack.Screen
animation: 'slide_from_right', key="GroupMembers"
}} name="GroupMembers"
/> component={GroupMembersScreen}
<RootStack.Screen options={{
name="GroupRequestDetail" headerShown: true,
component={GroupRequestDetailScreen} title: '群成员',
options={{ headerStyle: { backgroundColor: colors.background.paper },
headerShown: true, headerTintColor: colors.text.primary,
title: '入群审批', animation: 'slide_from_right',
headerStyle: { backgroundColor: colors.background.paper }, }}
headerTintColor: colors.text.primary, />,
animation: 'slide_from_right', <RootStack.Screen
}} key="GroupRequestDetail"
/> name="GroupRequestDetail"
<RootStack.Screen component={GroupRequestDetailScreen}
name="GroupInviteDetail" options={{
component={GroupInviteDetailScreen} headerShown: true,
options={{ title: '入群审批',
headerShown: true, headerStyle: { backgroundColor: colors.background.paper },
title: '群聊邀请', headerTintColor: colors.text.primary,
headerStyle: { backgroundColor: colors.background.paper }, animation: 'slide_from_right',
headerTintColor: colors.text.primary, }}
animation: 'slide_from_right', />,
}} <RootStack.Screen
/> key="GroupInviteDetail"
<RootStack.Screen name="GroupInviteDetail"
name="PrivateChatInfo" component={GroupInviteDetailScreen}
component={PrivateChatInfoScreen} options={{
options={{ headerShown: true,
headerShown: true, title: '群聊邀请',
title: '聊天信息', headerStyle: { backgroundColor: colors.background.paper },
headerStyle: { backgroundColor: colors.background.paper }, headerTintColor: colors.text.primary,
headerTintColor: colors.text.primary, animation: 'slide_from_right',
animation: 'slide_from_right', }}
}} />,
/> <RootStack.Screen
</> key="PrivateChatInfo"
); name="PrivateChatInfo"
component={PrivateChatInfoScreen}
options={{
headerShown: true,
title: '聊天信息',
headerStyle: { backgroundColor: colors.background.paper },
headerTintColor: colors.text.primary,
animation: 'slide_from_right',
}}
/>,
];
export function RootNavigator({ isAuthenticated, isInitializing }: RootNavigatorProps) { export function RootNavigator({ isAuthenticated, isInitializing }: RootNavigatorProps) {
const { isMobile } = useResponsive(); const { isMobile } = useResponsive();
@@ -238,7 +248,7 @@ export function RootNavigator({ isAuthenticated, isInitializing }: RootNavigator
) )
} }
</RootStack.Screen> </RootStack.Screen>
<AuthenticatedScreens /> {getAuthenticatedScreens()}
</> </>
) : ( ) : (
<> <>
@@ -247,7 +257,7 @@ export function RootNavigator({ isAuthenticated, isInitializing }: RootNavigator
component={AuthNavigator} component={AuthNavigator}
options={{ headerShown: false }} options={{ headerShown: false }}
/> />
<PublicScreens /> {getPublicScreens()}
</> </>
)} )}
</RootStack.Navigator> </RootStack.Navigator>

View File

@@ -35,6 +35,7 @@ import { HomeStackParamList, RootStackParamList } from '../../navigation/types';
import { useResponsive, useResponsiveSpacing } from '../../hooks/useResponsive'; import { useResponsive, useResponsiveSpacing } from '../../hooks/useResponsive';
import { SearchScreen } from './SearchScreen'; import { SearchScreen } from './SearchScreen';
import { CreatePostScreen } from '../create/CreatePostScreen'; import { CreatePostScreen } from '../create/CreatePostScreen';
import { navigationService } from '../../infrastructure/navigation/navigationService';
type NavigationProp = NativeStackNavigationProp<HomeStackParamList, 'Home'> & NativeStackNavigationProp<RootStackParamList>; type NavigationProp = NativeStackNavigationProp<HomeStackParamList, 'Home'> & NativeStackNavigationProp<RootStackParamList>;
@@ -343,12 +344,12 @@ export const HomeScreen: React.FC = () => {
// 跳转到帖子详情 // 跳转到帖子详情
const handlePostPress = (postId: string, scrollToComments: boolean = false) => { const handlePostPress = (postId: string, scrollToComments: boolean = false) => {
navigation.getParent()?.navigate('PostDetail', { postId, scrollToComments }); navigationService.navigate('PostDetail', { postId, scrollToComments });
}; };
// 跳转到用户主页 // 跳转到用户主页
const handleUserPress = (userId: string) => { const handleUserPress = (userId: string) => {
navigation.getParent()?.navigate('UserProfile', { userId }); navigationService.navigate('UserProfile', { userId });
}; };
// 点赞帖子 // 点赞帖子

View File

@@ -31,6 +31,7 @@ import { userManager } from '../../stores/userManager';
import { Avatar, Text, Button, Loading, Divider } from '../../components/common'; import { Avatar, Text, Button, Loading, Divider } from '../../components/common';
import { User } from '../../types'; import { User } from '../../types';
import { RootStackParamList, MessageStackParamList } from '../../navigation/types'; import { RootStackParamList, MessageStackParamList } from '../../navigation/types';
import { navigationService } from '../../infrastructure/navigation/navigationService';
type NavigationProp = NativeStackNavigationProp<MessageStackParamList>; type NavigationProp = NativeStackNavigationProp<MessageStackParamList>;
type PrivateChatInfoRouteProp = RouteProp<MessageStackParamList, 'PrivateChatInfo'>; type PrivateChatInfoRouteProp = RouteProp<MessageStackParamList, 'PrivateChatInfo'>;
@@ -149,9 +150,8 @@ const PrivateChatInfoScreen: React.FC = () => {
// 查看用户资料 // 查看用户资料
const handleViewProfile = () => { const handleViewProfile = () => {
// 使用导航跳转到用户资料页面 // 使用导航服务跳转到用户资料页面
const rootNavigation = navigation.getParent(); navigationService.navigate('UserProfile', { userId });
rootNavigation?.navigate('UserProfile' as any, { userId });
}; };
// 举报/投诉 // 举报/投诉

View File

@@ -31,6 +31,7 @@ import { groupService } from '../../../../services/groupService';
import { userManager } from '../../../../stores/userManager'; import { userManager } from '../../../../stores/userManager';
import { groupManager } from '../../../../stores/groupManager'; import { groupManager } from '../../../../stores/groupManager';
import { RootStackParamList } from '../../../../navigation/types'; import { RootStackParamList } from '../../../../navigation/types';
import { navigationService } from '../../../../infrastructure/navigation/navigationService';
import { import {
GroupMessage, GroupMessage,
PanelType, PanelType,
@@ -1039,9 +1040,9 @@ export const useChatScreen = () => {
// 点击头像跳转到用户主页 // 点击头像跳转到用户主页
const handleAvatarPress = useCallback((userId: string) => { const handleAvatarPress = useCallback((userId: string) => {
if (userId && userId !== currentUserId) { if (userId && userId !== currentUserId) {
navigation.navigate('UserProfile' as any, { userId: String(userId) }); navigationService.navigate('UserProfile', { userId: String(userId) });
} }
}, [navigation, currentUserId]); }, [currentUserId]);
// 长按头像@用户 // 长按头像@用户
const handleAvatarLongPress = useCallback((senderId: string, nickname: string) => { const handleAvatarLongPress = useCallback((senderId: string, nickname: string) => {
@@ -1113,8 +1114,7 @@ export const useChatScreen = () => {
conversationId: conversationId || undefined, conversationId: conversationId || undefined,
}); });
} else if (otherUser?.id) { } else if (otherUser?.id) {
const rootNavigation = navigation.getParent(); navigationService.navigate('UserProfile', { userId: String(otherUser.id) });
rootNavigation?.navigate('UserProfile' as any, { userId: String(otherUser.id) });
} }
}, [navigation, isGroupChat, routeGroupId, otherUser]); }, [navigation, isGroupChat, routeGroupId, otherUser]);