簡體   English   中英

在 React Native 中將導航傳遞給 App.js

[英]Passing navigation to App.js in React Native

我閱讀了用於反應導航的身份驗證流程教程 我成功地整合了它。 有一件事我不能去上班。 它是export default function App({ navigation })中的“導航”部分。

我需要做什么才能使其正常工作。 我的navigation變量undefined 由於React Native Firebase 通知,我需要在 App.js 中導航。 我集成了 RN Firebase 和Notifee

目標是收聽前台和后台事件,當我收到通知並按下它以導航到特定屏幕時。 沒有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 ,然后導出為您的導航 class。

根導航.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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM