【问题标题】:Use react navigation.navigate inside a normal function - (no hooks allowed i.e. useNavigation)?在普通函数中使用 react navigation.navigate - (不允许使用挂钩,即 useNavigation)?
【发布时间】:2020-02-29 08:35:59
【问题描述】:

我正在尝试将导航到屏幕的功能放在另一个模块中并将其导出,但navigation 不起作用。我尝试使用UseNavigation(),但出现错误,即:Unhandled promise rejection: Invariant Violation: Hooks can only be called inside the body of a function component.

有没有办法在正常功能中使用导航,或其他任何东西。

import React, { useState, useEffect, useCallback } from "react";
import { AsyncStorage, Alert } from "react-native";
import { useNavigation } from "react-navigation-hooks";

export const startMixGame = async (categoryIsChosen, withTimer) => {
  const navigation = useNavigation();

  if (categoryIsChosen) {
    if (withTimer) {
      await AsyncStorage.setItem("useTimer", "true");
      navigation.navigate({
        routeName: "MixedQuestions",
        params: {
          categoryId: "1"
        }
      });
    } else if (!withTimer) {
      // console.log("withTimer", withTimer);

      await AsyncStorage.setItem("useTimer", "false");
      navigation.navigate({
        routeName: "NoTimerMixedQuestions",
        params: {
          categoryId: "1"
        }
      });
    }
  }

};

谢谢

【问题讨论】:

    标签: reactjs react-native react-navigation react-native-navigation


    【解决方案1】:

    是的,使用单例服务来保存对导航的引用,在应用程序的根目录中使用 useEffect 保存单例中的引用,这样您就可以在任何地方使用它。 像这样的:

    class NavigationService {
      constructor() {
        this._navigation = null;
      }
    
      set navigation(nav) {
        this._navigation = nav;
      }
    
      get navigation() {
        return this._navigation;
      }
    }
    
    const navigationService = new NavigationService();
    
    export default navigationService;
    

    在您的主屏幕/视图中

        const HomeScreen = ({navigation}) => {
          useEffect(() => {
            navigationService.navigation = navigation;
          }, [navigation]);
       ....
    

    现在你可以在任何地方这样做

    import navigationService from '../services/navigation';
    
    navigationService.navigation.navigate('Screen');
    

    【讨论】:

    • 您好@Antonio,感谢您的回复。我尝试使用您的代码,但出现错误:Invariant Violation: Render more hooks than during the previous render。是 App.js 中的useEffect,对吧?有什么我可以做的吗?
    • Invariant Violation: Render more hooks than during the previous render @Fotis Tsakiris 您应该始终在功能组件中的任何其他代码之前创建所有挂钩。我的意思是确保所有的钩子都被渲染。不要在条件中创建钩子
    • @Antonio,好的,谢谢!现在我收到另一个错误:TypeError: undefined is not an object (evaluating _NavigationService.default.navigation.navigate) 来自我使用导航的文件。我导入它的方式可能有问题吗?我愿意:import navigationService from '../../../NavigationService'; 因为那里可以找到。我不必做import navigationService from '../services/navigation';(像你一样)对吧?而且,我还把它导入到HomeScreen !
    • 在你的根组件挂载之前不要使用navigationService,否则钩子不会触发navigation var注册。尝试在使用导航之前设置条件,例如if (navigationService.navigation !== null) ...,如果为空则打印控制台日志
    • 非常感谢安东尼奥。它正在工作!我很抱歉大惊小怪。我对HomeScreen 有点困惑。我想我必须将useEffect 放在应用程序启动的App.js 中。但我刚刚意识到,App.js 没有navigation 属性!所以我把它移到了按钮所在的组件上,就完成了!再次感谢!快乐编码;
    【解决方案2】:

    检查这个 https://reactnavigation.org/docs/navigating-without-navigation-prop/

    您可以保存对 NavigationContainer 的引用并使用它进行导航。

    应用

    import AppNavigator from './AppNavigator'
    ...
    render (){
     return (<AppNavigator/>)
    }
    

    AppNavigator

    import * as React from 'react';
    import AppStack from './AppStack';
    import {NavigationContainer} from '@react-navigation/native';
    import NavigationService from './NavigationService';
    
    const AppNavigator = () => {
        return (
            <NavigationContainer
                ref={NavigationService.instance}
            >
                <AppStack/>
            </NavigationContainer>
        );
    };
    export default AppNavigator
    
    

    AppStack

    import {createStackNavigator} from '@react-navigation/stack';
    
    const Stack = createStackNavigator();
    
    
    export default () => {
        return (
            <Stack.Navigator>
    
                 // add all screens here
                 <Stack.Screen
                    name={'Home'}
                    component={HomeCpmponent}
                />
    
            </Stack.Navigator>
        )
    }
    
    import {NavigationContainerRef} from '@react-navigation/native';
    import * as React from 'react';
    import {boundClass} from 'autobind-decorator';
    
    @boundClass
    class NavigationService {
        instance = React.createRef<NavigationContainerRef>();
    
        dispatch(action) {
            this.instance.current?.dispatch(action)
        }
    
        getInstance() {
            return this.instance?.current
        }
    
        canGoBack() {
            return this.getInstance()?.canGoBack()
        }
    
        navigate(routeName: string, params: any) {
            return this.getInstance()?.navigate(routeName, params)
        }
    
    }
    
    export default new NavigationService()
    
    

    您可以使用NavigationService.dispatch()import {CommonActions, StackActions} from '@react-navigation/native'; NavigationService.navigate('home',{id:'test1'}) 或...

    【讨论】:

    • 您好@Ahmad,感谢您的回复,但我收到两个错误:1. 即使在文档中他们也在App.js 中使用了一个函数组件,我得到:Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?%s%s, 。 2. 在RootNavigation.js 中,? 给出错误Expression expected。如果我删除它,应用程序会运行,但是当我使用 func 时,我会得到TypeError: null is not an object (evaluating 'navigationRef.current.navigate)。顺便说一句,我使用import NavigationContainer from './navigation/NavigationContainer'; 。有任何想法吗?谢谢
    • 抱歉,我无法跟进。此外,这对我来说就像我必须改变我的导航系统一样!无论如何,谢谢!
    【解决方案3】:

    实际上,现在我再次看到它,我可以将navigation 作为参数/参数传递,例如:

    export const startMixGame = async (categoryIsChosen, navigation, withTimer) => { ...}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-23
      • 1970-01-01
      • 1970-01-01
      • 2022-10-05
      相关资源
      最近更新 更多