我对 react native 有点陌生,在我的应用程序的 react native 屏幕中登录和注销后,我很难在两个不同的选项卡导航器之间导航,这些屏幕都使用功能组件屏幕
有人可以建议我如何做到这一点吗?
在我的导航目录(处理导航流程)中,我有 2 个文件 index.js 和 main.js
- 导航/index.js
- 导航/main.js
用户启动应用程序后,用户会看到 navigation/index.js 文件中的屏幕。
用户注册或登录后,用户会看到 navigation/main.js 文件中的屏幕
除了在应用程序中登录和注销后在导航器之间导航之外,我已经实现了应用程序中的所有其他内容
我最初将所有屏幕放在同一个导航器文件中,但连续按后退按钮后我开始遇到问题
看下面的代码
:::::::::编辑::::::::::: 不再使用 Navigation/main.js 现在仅使用 Navigation/index.js 并实现 @Tolga Berk Ordanuç 的建议 但仍然需要更多帮助,因为 它部分起作用 现在 单击“登录”登录后出现错误
"错误任何导航器均未处理有效负载 {"name":"BottomTabNavigator"} 的操作“NAVIGATE”。
您有一个名为“BottomTabNavigator”的屏幕吗?”
当我通过多次回击完全关闭应用程序时, 我已登录 但现在第二个错误,当我单击注销时 我收到以下错误
错误任何导航器均未处理有效负载 {"name":"Walkthrough"} 的操作“NAVIGATE”。
您有一个名为“演练”的屏幕吗?
home.js
import React, {useState} from 'react';
import {View} from 'react-native';
import {useTheme} from '@config';
import {Header, Icon, Button} from '@components';
import {useDispatch} from 'react-redux';
export default function Home({navigation, route}) {
const {colors} = useTheme();
const dispatch = useDispatch();
const [loading, setLoading] = useState(false);
const logout = () => {
setLoading(true);
dispatch(setIsLoggedIn(false));
navigation.navigate('SignIn');
setLoading(false);
};
return (
<View style={{flex: 1}}>
<Header
title="sign in"
renderLeft={() => {
return (
<Icon
name="times"
size={20}
color={colors.primary}
enableRTL={true}
/>
);
}}
onPressLeft={() => {
navigation.goBack();
}}
/>
<View>
<Button style={{marginTop: 20}} full loading={loading} onPress={logout}>
Log Out
</Button>
</View>
</View>
);
}
导航/main.js
import React from 'react';
import {createStackNavigator} from '@react-navigation/stack';
import {useTheme} from '@config';
import {useSelector} from 'react-redux';
import {designSelect} from '@selectors';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import {BaseColor, useFont} from '@config';
import {Icon} from '@components';
/* Main Stack Navigator */
/* Modal Screen only affect iOS */
import Savings from 'Savings';
import Loans from 'Loans';
import Home from 'Home';
import Profile from 'Profile';
/* Stack Screen */
import Setting from 'Setting';
import Feedback from 'Feedback';
import ChangePassword from 'ChangePassword';
import ProfileEdit from 'ProfileEdit';
import ContactUs from 'ContactUs';
import AboutUs from 'AboutUs';
import Support from 'Support';
const MainStack = createStackNavigator();
export default function Main() {
return (
<MainStack.Navigator
screenOptions={{
headerShown: false,
}}
initialRouteName="BottomTabNavigator">
<MainStack.Screen
name="BottomTabNavigator"
component={BottomTabNavigator}
/>
<MainStack.Screen name="Support" component={Support} />
<MainStack.Screen name="SavingsTemp" component={Savings} />
<MainStack.Screen
name="BottomTabNavigator"
component={BottomTabNavigator}
/>
<MainStack.Screen name="Setting" component={Setting} />
<MainStack.Screen name="Feedback" component={Feedback} />
<MainStack.Screen name="ChangePassword" component={ChangePassword} />
<MainStack.Screen name="ProfileEdit" component={ProfileEdit} />
<MainStack.Screen name="ContactUs" component={ContactUs} />
<MainStack.Screen name="AboutUs" component={AboutUs} />
</MainStack.Navigator>
);
}
function BottomTabNavigator() {
const {colors} = useTheme();
const font = useFont();
const BottomTab = createBottomTabNavigator();
const design = useSelector(designSelect);
/**
* Main follow return Home Screen design you are selected
* @param {*} design ['basic', 'real_estate','event', 'food']
* @returns
*/
const exportHome = () => {
return Home;
};
return (
<BottomTab.Navigator
initialRouteName="Home"
screenOptions={{
headerShown: false,
}}
tabBarOptions={{
showIcon: true,
showLabel: true,
activeTintColor: colors.primary,
inactiveTintColor: BaseColor.grayColor,
style: {borderTopWidth: 1},
labelStyle: {
fontSize: 12,
fontFamily: font,
paddingBottom: 4,
},
}}>
<BottomTab.Screen
name="Home"
component={exportHome(design)}
options={{
title: 'home',
tabBarIcon: ({color}) => {
return <Icon color={color} name="home" size={20} solid />;
},
}}
/>
<BottomTab.Screen
name="Savings"
component={Savings}
options={{
title: 'Savings',
tabBarIcon: ({color}) => {
return <Icon color={color} name="bookmark" size={20} solid />;
},
}}
/>
<BottomTab.Screen
name="Loans"
component={Loans}
options={{
title: 'Loans',
tabBarIcon: ({color}) => {
return <Icon color={color} name="clipboard-list" size={20} solid />;
},
}}
/>
<BottomTab.Screen
name="Profile"
component={Profile}
options={{
title: 'Profile',
tabBarIcon: ({color}) => {
return <Icon solid color={color} name="user-circle" size={20} />;
},
}}
/>
</BottomTab.Navigator>
);
}
导航/index.js
import React, {useEffect, useState} from 'react';
import {StatusBar, Platform} from 'react-native';
import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';
import {DarkModeProvider, useDarkMode} from 'react-native-dark-mode';
import {useTheme, BaseSetting} from '@config';
import i18n from 'i18next';
import {initReactI18next} from 'react-i18next';
import {useSelector} from 'react-redux';
import {languageSelect, designSelect} from '@selectors';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import {BaseColor, useFont} from '@config';
import {useTranslation} from 'react-i18next';
import {Icon} from '@components';
/* Main Stack Navigator */
/* Modal Screen only affect iOS */
import Loading from 'Loading';
import SignIn from 'SignIn';
import SignUp from 'SignUp';
import ResetPassword from 'ResetPassword';
import Walkthrough from 'Walkthrough';
import Home from 'Home';
import Profile from 'Profile';
import Feedback from 'Feedback';
import ChangePassword from 'ChangePassword';
import ProfileEdit from 'ProfileEdit';
import ContactUs from 'ContactUs';
import AboutUs from 'AboutUs';
import Tab2 from 'Tab2';
import Tab3 from 'Tab3';
import BottomTabNavigator from './BottomTabNavigator';
import {store} from '../store';
const RootStack = createStackNavigator();
export default function Navigator() {
const language = useSelector(languageSelect);
const {theme, colors} = useTheme();
const isDarkMode = useDarkMode();
const [isLoggedInValue, setIsLoggedInValue] = useState(false);
useEffect(() => {
i18n.use(initReactI18next).init({
resources: BaseSetting.resourcesLanguage,
lng: language ?? BaseSetting.defaultLanguage,
fallbackLng: BaseSetting.defaultLanguage,
});
if (Platform.OS === 'android') {
StatusBar.setBackgroundColor(colors.primary, true);
}
StatusBar.setBarStyle(isDarkMode ? 'light-content' : 'dark-content', true);
console.log('<<<<< IS LOGGED IN STATE >>>>>>');
console.log(isLoggedInValue);
console.log('<<<<< IS LOGGED IN STATE >>>>>>');
setIsLoggedInValue(store.getState().isloggedin.isLoggedIn);
}, [colors.primary, isDarkMode, language, isLoggedInValue]);
return (
<DarkModeProvider>
<NavigationContainer theme={theme}>
<RootStack.Navigator
mode="modal"
screenOptions={{
headerShown: false,
}}>
{!isLoggedInValue ? (
<>
<RootStack.Screen
name="Loading"
component={Loading}
options={{gestureEnabled: false}}
/>
<RootStack.Screen name="Walkthrough" component={Walkthrough} />
<RootStack.Screen name="SignIn" component={SignIn} />
<RootStack.Screen name="SignUp" component={SignUp} />
<RootStack.Screen
name="ResetPassword"
component={ResetPassword}
/>
</>
) : (
<>
<RootStack.Screen
name="BottomTabNavigator"
component={BottomTabNavigator}
/>
<RootStack.Screen name="Feedback" component={Feedback} />
<RootStack.Screen
name="ChangePassword"
component={ChangePassword}
/>
<RootStack.Screen name="ProfileEdit" component={ProfileEdit} />
<RootStack.Screen name="ContactUs" component={ContactUs} />
<RootStack.Screen name="AboutUs" component={AboutUs} />
</>
)}
</RootStack.Navigator>
</NavigationContainer>
</DarkModeProvider>
);
}
登录.js
import React, {useState} from 'react';
import {
View,
TouchableOpacity,
KeyboardAvoidingView,
Platform,
Alert,
} from 'react-native';
import {useDispatch} from 'react-redux';
import {BaseStyle, useTheme} from '@config';
import {Header, SafeAreaView, Icon, Text, Button, TextInput} from '@components';
import styles from './styles';
export default function SignIn({navigation, route}) {
const {colors} = useTheme();
const [loading, setLoading] = useState(false);
const [id, setId] = useState('');
const [password, setPassword] = useState('');
const dispatch = useDispatch();
/**
* call when action onLogin
*/
const onLogin = () => {
setLoading(true);
dispatch(setIsLoggedIn(true));
navigation.navigate('Home');
setLoading(false);
};
const offsetKeyboard = Platform.select({
ios: 0,
android: 20,
});
return (
<View style={{flex: 1}}>
<Header
title="sign in"
renderLeft={() => {
return (
<Icon
name="times"
size={20}
color={colors.primary}
enableRTL={true}
/>
);
}}
onPressLeft={() => {
navigation.goBack();
}}
/>
<SafeAreaView style={BaseStyle.safeAreaView} edges={['right', 'left']}>
<KeyboardAvoidingView
behavior={Platform.OS === 'android' ? 'height' : 'padding'}
keyboardVerticalOffset={offsetKeyboard}
style={{flex: 1}}>
<View style={styles.contain}>
<TextInput onChangeText={setId} placeholder="username" value={id} />
<TextInput
style={{marginTop: 10}}
onChangeText={setPassword}
placeholder="Password"
secureTextEntry={true}
value={password}
/>
<Button
style={{marginTop: 20}}
full
loading={loading}
onPress={onLogin}>
'sign_in'
</Button>
<TouchableOpacity
onPress={() => navigation.navigate('ResetPassword')}>
<Text body1 grayColor style={{marginTop: 25}}>
'forgot_your_password'
</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
</SafeAreaView>
</View>
);
}
5
导航/BottomTabNavigator.js
export default function BottomTabNavigator() {
const {colors} = useTheme();
const font = useFont();
const design = useSelector(designSelect);
const BottomTab = createBottomTabNavigator();
const exportHome = () => {
return Home;
};
return (
<BottomTab.Navigator
initialRouteName="Home"
screenOptions={{
headerShown: false,
}}
tabBarOptions={{
showIcon: true,
showLabel: true,
activeTintColor: colors.primary,
inactiveTintColor: BaseColor.grayColor,
style: {borderTopWidth: 1},
labelStyle: {
fontSize: 12,
fontFamily: font,
paddingBottom: 4,
},
}}>
<BottomTab.Screen
name="Home"
component={exportHome(design)}
options={{
title: 'Home',
tabBarIcon: ({color}) => {
return <Icon color={color} name="home" size={20} solid />;
},
}}
/>
<BottomTab.Screen
name="Savings"
component={Tab2}
options={{
title: 'Savings',
tabBarIcon: ({color}) => {
return <Icon color={color} name="bookmark" size={20} solid />;
},
}}
/>
<BottomTab.Screen
name="Loans"
component={Tab3}
options={{
title: 'Loans',
tabBarIcon: ({color}) => {
return <Icon color={color} name="clipboard-list" size={20} solid />;
},
}}
/>
<BottomTab.Screen
name="Profile"
component={Profile}
options={{
title: 'Profile',
tabBarIcon: ({color}) => {
return <Icon solid color={color} name="user-circle" size={20} />;
},
}}
/>
</BottomTab.Navigator>
);
}
最佳答案
我在代码中看不到第二个选项卡导航器,但我看到您在组件内创建了导航器,在我看来,这不是您应该做的。您应该单独创建导航器,而不是在另一个组件内。在 react-navigation
的文档中,他们以这种方式显示,所以他们应该知道他们在做什么,我猜:D
登录和主应用程序屏幕过去由开关导航器管理,但在 react-navigation 5
中,它们转储了开关导航器,而是在导航器组件中支持三元运算符,如下所示
const RootStack = createStackNavigator<RootStackParamList>();
export const RootNavigator = () => {
const isLoggedIn = useReduxSelector(({ authState }) => authState.isLoggedIn);
return (
<RootStack.Navigator screenOptions={{ headerShown: false }}>
{!isLoggedIn ? (
<RootStack.Screen
name="AuthNavigator"
options={{ headerShown: false }}
component={AuthNavigator}
/>
) : (
<>
<RootStack.Screen name="TabNavigator" component={TabNavigator} />
<RootStack.Screen
name="DetailsNavigator"
component={DetailsNavigator}
/>
<RootStack.Screen
name="UserStackNavigator"
component={UserStackNavigator}
/>
<RootStack.Screen name="Announcements" component={Announcements} />
<RootStack.Screen name="Read" component={Read} />
<RootStack.Screen
name="Search"
options={{
...TransitionPresets.FadeFromBottomAndroid,
gestureEnabled: false,
}}
component={Search}
/>
</>
)}
</RootStack.Navigator>
);
};
登录并为您的 redux 分派(dispatch)适当的操作以更改 isLoggedIn 状态后,导航器会自动删除登录页面并回退到其下方的内容。此时,用户无法转到登录或注册屏幕,即使他们想返回多少次也是如此,因为我们将这些屏幕从导航树中删除了。
如果您想返回登录屏幕,您只需注销用户,导航树就会再次包含这些屏幕,您可以使用屏幕的相应按键通过 navigation.navigate
功能导航到它们。
如果您好奇我的选项卡导航器是什么样子,它就像这样
const Tab = createBottomTabNavigator<TabParamList>();
//
const tabNavigatorScreenOptions: (props: {
route: RouteProp<TabParamList, keyof TabParamList>;
navigation: unknown;
}) => BottomTabNavigationOptions = ({ route }) => ({
tabBarIcon: (params) => <TabBarIcon {...params} route={route} />,
tabBarButton: (props) => (
<Pressable
{...props}
style={[props.style, { marginTop: Layout.dimensions.xs_h }]}
/>
),
// tabBarLabel: (props) => <TabBarLabel {...props} route={route} />,
});
export const TabNavigator = () => {
const debug = useReduxSelector(({ info }) => info.debug);
// Logger.debug = debug;
return (
<Tab.Navigator
tabBarOptions={{ adaptive: true, showLabel: false }}
screenOptions={tabNavigatorScreenOptions}
>
<Tab.Screen name="Discover" component={Discover} />
<Tab.Screen name="Library" component={LibraryNavigator} />
<Tab.Screen name="Settings" component={SettingsNavigator} />
{debug && <Tab.Screen name="TestNavigator" component={TestNavigator} />}
</Tab.Navigator>
);
};
代码是 typescript ,但这不应该是逻辑问题。
如果您还有任何疑问,我很乐意为您提供帮助!
祝我的 React Native 开发人员编码愉快!
关于javascript - 如何在 React Native 中登录和注销后在 2 个不同的导航器之间导航,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68096086/