在 React Native 中将导航传递给 App.js [英] Passing navigation to App.js in React Native

查看:65
本文介绍了在 React Native 中将导航传递给 App.js的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我阅读了身份验证流程教程以了解反应导航.我成功集成了它.有一件事我不能上班.它是导航"参与导出默认函数App({ navigation }).

I read Authentication flow tutorial for react navigation. I successfully integrated it. There is one thing I cannot get to work. It's "navigation" part in export default function App({ navigation }).

我需要做什么才能使其正常工作.我得到 undefinednavigation 变量.由于 React Native Firebase 通知,我需要在 App.js 中导航.我集成了 RN Firebase 和 Notifee.

What do I need to do for this to be functional. I get undefined for navigation variable. I need navigation in App.js because of React Native Firebase notifications. I integrated RN Firebase and Notifee.

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

Goal is to listen to foreground and background event and when I get notification and press on it to navigate to specific screen. Without navigation I won't be able to do it.

这是我的 App.js

Here is my 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

Here is my 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,然后导出作为导航类.

you first create a RootNavigation, then you export is as your navigation class.

RootNavigation.js

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
  }
}

拥有上述内容后,您需要在您的应用中引用它.

once you have the above, you need to reference it in your App.

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,如下所示:

once you did the above, you can use it anywhere in your app including App.js like so:

import * as RootNavigation from './path/to/RootNavigation.js';

// ...

RootNavigation.navigate('ChatScreen', { userName: 'Lucy' });

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

这篇关于在 React Native 中将导航传递给 App.js的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆