You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native Tab View页面跳转报错:navigation.navigate未定义

问题描述

在React Native项目中,从MyCoursesPage页面的React Native Tab View路由组件(FirstRoute、SecondRoute)跳转到MyCoursesPage2时,点击onPress触发错误:undefined is an object (evaluating navigation.navigate)。外层MyCoursesPage组件内的onPress可正常工作,但Tab View的路由组件无法获取navigation对象。已配置对应的Stack Navigator。

相关代码

MyCoursesPage代码

import React, {useState} from "react";
import { View, StyleSheet, TouchableOpacity, Image, Dimensions, ScrollView, StatusBar, Text } from 'react-native';
import { SafeAreaView } from "react-native-safe-area-context";
import CustomHeader from "../../components/CustomHeader";
import { IMAGE } from "../../constants/Images";
import { TabView, SceneMap, TabBar } from 'react-native-tab-view';
import * as Progress from 'react-native-progress';


const FirstRoute = ({navigation}) => (   
  <ScrollView> 
  <View style={[styles.scene, { backgroundColor: '#f7f7f7' }]} />
            
  </ScrollView>      
);    
 
function SecondRoute({ navigation }) {       
  return (
  <ScrollView>
  <View style={[styles.scene, { backgroundColor: '#f7f7f7' }]} />
  <TouchableOpacity onPress={() => navigation.navigate("MyCoursesPage2")}>
    
              <View
                style={{
                  borderWidth: 1,
                  borderColor: "#fff",
                  backgroundColor:'#fff',
                  borderRadius: 10,
                  padding: 15,
                  marginHorizontal:20,
                  marginVertical: 15,
                  display:'flex',
                  flexDirection:'row'
                }}
              >
                <Image
                  source={IMAGE.MYCOURSES3}
                  style={{ width: 60, height: 60 }}
                />
                <View>
                          
                <Text style={{fontSize:17, fontWeight:'bold', marginHorizontal:15}}>3D Design Illustration</Text>
                <Text style={{fontSize:14, color:'grey', marginHorizontal:15}}>2hrs 25mins</Text>
                               
              <Progress.Bar style={{marginHorizontal:15, marginVertical:5}} progress={1} width={200} />
              </View>
              
              </View>  
             
   </TouchableOpacity>
  <TouchableOpacity>
    
    <View
      style={{
        borderWidth: 1,
        borderColor: "#fff",
        backgroundColor:'#fff',
        borderRadius: 10,
        padding: 15,
        marginHorizontal:20,
        display:'flex',
        flexDirection:'row'
      }}
    >
      <Image
        source={IMAGE.MYCOURSES4}
        style={{ width: 60, height: 60 }}
      />
      <View>
     
      <Text style={{fontSize:17, fontWeight:'bold', marginHorizontal:15}}>CRM Management</Text>
      <Text style={{fontSize:14, color:'grey', marginHorizontal:15}}>3hrs 20mins</Text>
       
    <Progress.Bar style={{marginHorizontal:15, marginVertical:5}} progress={0.88} width={200} />
    </View>
    
    </View>
   
  </TouchableOpacity>
  <TouchableOpacity>
    
    <View
      style={{
        borderWidth: 1,
        borderColor: "#fff",
        backgroundColor:'#fff',
        borderRadius: 10,
        padding: 15,
        marginHorizontal:20,
        marginVertical:15,
        display:'flex',
        flexDirection:'row'
      }}
    >
      <Image
        source={IMAGE.MYCOURSES5}
        style={{ width: 60, height: 60 }}
      />
      <View>
     
      <Text style={{fontSize:17, fontWeight:'bold', marginHorizontal:15}}>Flutter Mobile Apps</Text>
      <Text style={{fontSize:14, color:'grey', marginHorizontal:15}}>4hrs 50mins</Text>
       
    <Progress.Bar style={{marginHorizontal:15, marginVertical:5}} progress={0.95} width={200} />
    </View>
    
    </View>
   
  </TouchableOpacity>
  <TouchableOpacity>
    
    <View
      style={{
        borderWidth: 1,
        borderColor: "#fff",
        backgroundColor:'#fff',
        borderRadius: 10,
        padding: 15,
        marginHorizontal:20,
        display:'flex',
        flexDirection:'row'
      }}
    >
      <Image
        source={IMAGE.MYCOURSES6}
        style={{ width: 60, height: 60 }}
      />
      <View>
     
      <Text style={{fontSize:17, fontWeight:'bold', marginHorizontal:15}}>3D Icons Set Blender</Text>
      <Text style={{fontSize:14, color:'grey', marginHorizontal:15}}>2hrs 45mins</Text>
       
    <Progress.Bar style={{marginHorizontal:15, marginVertical:5}} progress={0.85} width={200} />
    </View>
    
    </View>
   
  </TouchableOpacity>

  </ScrollView>
  )
}

const initialLayout = { width: Dimensions.get('window').width };


function MyCoursesPage({ navigation }) { 
  const [index, setIndex] = React.useState(0);
  const [routes] = React.useState([
    { key: 'first', title: 'Ongoing' },  
    { key: 'second', title: 'Completed' },    
  ]); 
     
  const renderScene = SceneMap({ 
    first: FirstRoute,  
    second: SecondRoute,
  });



  return (
    <SafeAreaView style={{ flex: 1, backgroundColor:'#f7f7f7' }}>
     
      <CustomHeader title="My Courses" isHome={true} navigation={navigation} />
        
      <View style={{ 
        flexDirection: "row", 
        justifyContent: "flex-end",
        marginTop:-35
      }}>
         <TouchableOpacity >           
      <Image source={IMAGE.MYCOURSES1} style={{width: 22, height:22}}/>
      </TouchableOpacity>           
      <TouchableOpacity >           
      <Image source={IMAGE.MYCOURSES2} style={{width: 22, height:22, marginHorizontal:15}}/>
      </TouchableOpacity>
      </View>
      
     
      <TabView
      navigationState={{ index, routes }}
      renderTabBar={props => (
        <TabBar
          {...props}
          renderLabel={({ route, color }) => (
            <Text style={{ color: '#335ef7', fontWeight:'bold', margin: 8 }}>
              {route.title} 
            </Text>
          )}
          style={{backgroundColor: 'white'}}
        />
      )}
      renderScene={renderScene}  
      onIndexChange={setIndex}   
      initialLayout={initialLayout} 
      style={styles.container}
    />
     
    </SafeAreaView>
  );
}

export default MyCoursesPage;

const styles = StyleSheet.create({
  container: {
    marginTop: StatusBar.currentHeight,
  },
  scene: {
    flex: 1,
  },
});

Stack Navigator代码

import React from "react";
import { createStackNavigator } from "@react-navigation/stack";
import MyCoursesPage from "../pages/MyCourses/MyCoursesPage";
import MyCoursesPage2 from "../pages/MyCourses/MyCoursesPage2"
import MyCoursesDetailsPage from "../pages/MyCourses/MyCoursesDetailsPage";
import Coursedetailscreen from "../pages/MyCourses/Coursedetailscreen";

const StackSetting = createStackNavigator();

function MyCoursesStackNavigator() {
  return (
    <StackSetting.Navigator initialRouteName="MyCoursesPage" screenOptions={{ headerShown: false }}>
      <StackSetting.Screen name="MyCoursesPage" component={MyCoursesPage} />
      <StackSetting.Screen name="MyCoursesPage2" component={MyCoursesPage2} />
      <StackSetting.Screen name="MyCoursesDetailsPage" component={MyCoursesDetailsPage} />
      <StackSetting.Screen name="Coursedetailscreen" component={Coursedetailscreen} />
    </StackSetting.Navigator>
  );
}

export default MyCoursesStackNavigator;
解决方案

方法1:自定义renderScene传递navigation

SceneMap默认不会将外层的navigation对象传递给Tab View的子路由组件,需要手动自定义renderScene函数,将navigation作为props传入:

修改MyCoursesPage中的renderScene部分:

// 替换原有的const renderScene = SceneMap(...)
const renderScene = ({ route }) => {
  switch (route.key) {
    case 'first':
      return <FirstRoute navigation={navigation} />;
    case 'second':
      return <SecondRoute navigation={navigation} />;
    default:
      return null;
  }
};

修改后,FirstRoute和SecondRoute就能正确接收navigation props,调用navigation.navigate即可正常跳转。

方法2:使用useNavigation钩子获取导航对象

如果不想修改renderScene,可以在子路由组件中直接使用React Navigation提供的useNavigation钩子来获取navigation对象:

首先在子组件中导入useNavigation:

import { useNavigation } from '@react-navigation/native';

然后修改FirstRoute和SecondRoute组件:

const FirstRoute = () => {
  const navigation = useNavigation();
  return (   
    <ScrollView> 
      <View style={[styles.scene, { backgroundColor: '#f7f7f7' }]} />
    </ScrollView>      
  );    
};    
 
function SecondRoute() {       
  const navigation = useNavigation();
  return (
    <ScrollView>
      <View style={[styles.scene, { backgroundColor: '#f7f7f7' }]} />
      <TouchableOpacity onPress={() => navigation.navigate("MyCoursesPage2")}>
        {/* 原有组件内容 */}
      </TouchableOpacity>
      {/* 其他组件内容 */}
    </ScrollView>
  )
}

这种方法无需手动传递navigation,实现更简洁,适合大多数场景。

内容的提问来源于stack exchange,提问作者Vaibhav Thakur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 12:10:50