Передача навигации в App.js в React Native

Я прочитал Учебник по процессу аутентификации для навигации по реакции. Я успешно интегрировал его. Есть одна вещь, которую я не могу заставить работать. Это "навигационная" часть в export default function App({ navigation }).

Что мне нужно сделать, чтобы это работало. Я получаю undefined для navigation переменной. Мне нужна навигация в App.js из-за уведомлений React Native Firebase . Я интегрировал 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.info("Connection type", state.isInternetReachable); //none
            //console.info("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);

Может ли кто-нибудь помочь мне с этим?

Пожалуйста, опубликуйте соответствующий код.

Ketan Ramteke 14.12.2020 21:33

Конечно, держи :)

FosAvance 14.12.2020 21:38

Не уверен, но пытались ли вы экспортировать функцию по умолчанию () { const navigation = nav; return App(navigation);} или в index.js const expoApp = App(navigation); registerRootComponent(expoApp);

JB_DELR 14.12.2020 23:31
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
3
2 750
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

сначала вы создаете 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

я получил эту ошибку ./utils/navigation/RootNavigation").navigationRef.navigate' не определен

famfamfam 08.04.2022 05:27

должно быть navigationRef.current.navigate, а не navigationRef.navigate

Wen W 08.04.2022 14:51

Другие вопросы по теме