将导航传递到React Native中的App.js



我阅读了react导航的身份验证流教程。我成功地整合了它。有一件事我无法工作。它是"导航";CCD_ 1中的一部分。

我需要做些什么才能使它发挥作用。我得到navigation变量的undefined。由于React Native Firebase通知,我需要在App.js中导航。我集成了RN Firebase和Notife。

目标是收听前台和后台事件,当我收到通知时,按下它导航到特定的屏幕。如果没有navigation,我将无法做到这一点。

这是我的App.js

import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import LoginScreen from './src/screens/LoginScreen.js'
import HomeScreen from './src/screens/tabs/HomeScreen.js'
import LogoutScreen from './src/screens/tabs/LogoutScreen.js'
import ContactsScreen from './src/screens/tabs/home/ContactsScreen.js'
import ConfirmPhoneNumberScreen from './src/screens/ConfirmPhoneNumberScreen.js'
import { createStackNavigator } from '@react-navigation/stack';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { ActivityIndicator, View, Text, Alert, Platform } from "react-native";
import { AppStyles } from "./src/AppStyles";
import Auth from './src/helpers/Auth.js';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import NetInfo from "@react-native-community/netinfo";
import NoInternetScreen from './src/screens/NoInternetScreen.js';
import Trans from './src/helpers/Trans.js';
import Toast from 'react-native-toast-message';
import Firebase from './src/push_notifications/Firebase.js';
import messaging from '@react-native-firebase/messaging';
import LatestMessagesScreen from './src/screens/messages/LatestMessagesScreen.js';
const AuthContext = React.createContext();
const Stack = createStackNavigator();
const BottomTabs = createBottomTabNavigator();
const FirebaseClass = new Firebase();
const AuthClass = new Auth();
function App({navigation}) {
const [state, dispatch] = React.useReducer(
(prevState, action) => {
switch (action.type) {
case 'RESTORE_TOKEN':
return {
...prevState,
userToken: action.token,
isLoading: false,
};
case 'SIGN_IN':
return {
...prevState,
isSignout: false,
userToken: action.token,
};
case 'SIGN_OUT':
return {
...prevState,
isSignout: true,
userToken: null,
};
case 'INTERNET_IS_ON':
return {
...prevState,
showNoInternetPage: false,
};
case 'INTERNET_IS_OFF':
return {
...prevState,
showNoInternetPage: true,
};
}
},
{
isLoading: true,
isSignout: false,
userToken: null,
showNoInternetPage: false,
}
);
React.useEffect(() => {
const unsubscribe = NetInfo.addEventListener(state => {
if (false === state.isInternetReachable && false === state.isConnected) {
dispatch({ type: 'INTERNET_IS_OFF' });
} else {
dispatch({ type: 'INTERNET_IS_ON' });
}
//console.log("Connection type", state.isInternetReachable); //none
//console.log("Is connected?", state.isConnected); //false
});
// Fetch the token from storage then navigate to our appropriate place
const bootstrapAsync = async () => {
let userToken;
try {
userToken = await AsyncStorage.getItem('@passwordAccessToken');
} catch (e) {
// Restoring token failed
}
// After restoring token, we may need to validate it in production apps
// This will switch to the App screen or Auth screen and this loading
// screen will be unmounted and thrown away.
dispatch({ type: 'RESTORE_TOKEN', token: userToken });
};
bootstrapAsync();
FirebaseClass.requestUserPermission();

}, []);
const authContext = React.useMemo(
() => ({
confirmPhoneNumber: async data => {
data.navigation.navigate('ConfirmPhoneNumberScreen')
},
signIn: async data => {
// In a production app, we need to send some data (usually username, password) to server and get a token
// We will also need to handle errors if sign in failed
// After getting token, we need to persist the token using `AsyncStorage`
// In the example, we'll use a dummy token
await AuthClass.getPasswordGrandTypeToken();
const accessToken = await AsyncStorage.getItem('@passwordAccessToken');
FirebaseClass.getPushToken();
dispatch({ type: 'SIGN_IN', token: accessToken });
},
signOut: () => {
AsyncStorage.removeItem('@passwordAccessToken');
dispatch({ type: 'SIGN_OUT' })
},
signUp: async data => {
// In a production app, we need to send user data to server and get a token
// We will also need to handle errors if sign up failed
// After getting token, we need to persist the token using `AsyncStorage`
// In the example, we'll use a dummy token
dispatch({ type: 'SIGN_IN', token: 'dummy-auth-token' });
},
}),
[]
);
createBottomTabs = () => {
const { signOut } = React.useContext(AuthContext);
return (
<BottomTabs.Navigator>
<BottomTabs.Screen name='HomeTab'
component={HomeScreen}
options={{
title: Trans.t('app.tabbar_home'),
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="home" color={color} size={size} />
)
}}></BottomTabs.Screen>
<BottomTabs.Screen name='LogoutTab' component={LogoutScreen}
options={{
title: Trans.t('app.tabbar_logout'),
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="logout" color={color} size={size} />
)
}}
listeners={{
tabPress: e => {
e.preventDefault();
Alert.alert(   // Shows up the alert without redirecting anywhere
Trans.t('alert.confirmation_title'),
Trans.t('alert.confirmation_body'),
[
{ text: Trans.t('alert.yes'), onPress: () => { signOut(); } },
{ text: Trans.t('alert.no') }
]
);
}
}}
></BottomTabs.Screen>
</BottomTabs.Navigator>
)
}

if (state.isLoading) {
// We haven't finished checking for the token yet
return (
<ActivityIndicator
style={{ marginTop: 200 }}
size="large"
color={AppStyles.color.tint}
/>
);
}

return (
<NavigationContainer>
<AuthContext.Provider value={authContext}>
<Stack.Navigator>
{(state.showNoInternetPage) ?
<>
<Stack.Screen
name="NoInternet"
component={NoInternetScreen}
options={{
headerTitle: Trans.t('app.no_internet_header')
}}
></Stack.Screen>
</> : (state.userToken == null) ? (
<>
<Stack.Screen name="Login" component={LoginScreen}
options={{
headerTitle: Trans.t('app.login_or_register_header'),
headerTitleAlign: 'center'
}} />
<Stack.Screen
name="ConfirmPhoneNumberScreen"
component={ConfirmPhoneNumberScreen}
options={{ headerTitle: Trans.t('app.confirm_phone_number_header') }} />
</>
) : (
<>
<Stack.Screen name="Home"
children={createBottomTabs}
options={{
headerTitle: Trans.t('app_name'),
headerTitleAlign: 'center'
}}></Stack.Screen>
<Stack.Screen
name='Contacts'
component={ContactsScreen}
></Stack.Screen>
<Stack.Screen
name='LatestMessages'
options={{
headerTitle: Trans.t('latest_messages_screen.header_title')
}}
component={LatestMessagesScreen}
></Stack.Screen>
</>
)}
</Stack.Navigator>
<Toast ref={(ref) => Toast.setRef(ref)} />
</AuthContext.Provider>
</NavigationContainer>
);
}
export default App;
export { AuthContext };

这是我的index.js

import { registerRootComponent } from 'expo';
import App from './App';
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
// It also ensures that whether you load the app in the Expo client or in a native build,
// the environment is set up appropriately
registerRootComponent(App);

有人能帮我吗?

首先创建一个RootNavigation,然后将其导出为导航类。

RootNavigation.js

import * as React from 'react';
export const isReadyRef = React.createRef();
export const navigationRef = React.createRef();
export function navigate(name, params) {
if (isReadyRef.current && navigationRef.current) {
// Perform navigation if the app has mounted
navigationRef.current.navigate(name, params);
} else {
// You can decide what to do if the app hasn't mounted
// You can ignore this, or add these actions to a queue you can call later
}
}

一旦你有了以上内容,你需要在你的应用程序中引用它。

import { navigationRef, isReadyRef } from './RootNavigation';
React.useEffect(() => {
return () => {
isReadyRef.current = false
};
}, []);
return (
<NavigationContainer ref={navigationRef}
onReady={() => {
isReadyRef.current = true;
}}>
<AuthContext.Provider value={authContext}>

一旦你完成了以上操作,你就可以在你的应用程序中的任何地方使用它,包括像这样的app.js:

import * as RootNavigation from './path/to/RootNavigation.js';
// ...
RootNavigation.navigate('ChatScreen', { userName: 'Lucy' });

来源:https://reactnavigation.org/docs/navigating-without-navigation-prop

最新更新