react-navigation 3.x 使用

本文深入讲解React Navigation的安装与配置,包括react-navigation、react-native-gesture-handler的使用,以及iOS和Android上的特定设置。详细解释了顶部和底部导航的样式属性,如headerMode、tabBarOptions等,并提供了丰富的示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 官网文档:https://reactnavigation.org/docs/zh-Hans/getting-started.html

1、安装react-navigation

yarn add react-navigation
# or with npm
# npm install --save react-navigation

2、安装 react-native-gesture-handler。 如果你使用 Expo,就什么都不需要做,他已经包含在 SDK 中 了

yarn add react-native-gesture-handler
# or with npm
# npm install --save react-native-gesture-handler

Link 所有的原生依赖

react-native link react-native-gesture-handler

iOS 啥都不用做

为了完成 react-native-gesture-handler在 Android 上的安装,请确保在 MainActivity.java 上完成如下修改:

import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;

public class MainActivity extends ReactActivity {

    ...

    @Override
    protected ReactActivityDelegate createReactActivityDelegate() {
        return new ReactActivityDelegate(this, getMainComponentName()) {
            @Override
            protected ReactRootView createRootView() {
                return new RNGestureHandlerEnabledRootView(MainActivity.this);
            }
        };
    }
}

 

 顶部导航

import { createStackNavigator, createAppContainer } from 'react-navigation'

const RootStack = createStackNavigator({})

const AppContainer = createAppContainer(RootStack); //与2.x不同,需要用到createAppContainer

export default class Navigation extends Component {
    render() {
        return (
            <AppContainer/> //2.x返回的是 <RootStack/>
        )
    }
}
 

头部导航栏样式属性

路由的选项:

path:路由中设置的路径的覆盖映射配置

initialRouteName:设置 stack navigator 的默认页面, 必须是路由配置中的某一个

initialRouteParams:初始路由参数

defaultNavigationOptions:用于屏幕的默认导航选项

视觉选项:

mode: 定义渲染和转换的样式

  • card:使用标准的 iOS 和 Android 屏幕转换, 这是默认设置
  • modal:iOS独有的使屏幕从底部画出,在 Android 上无效

headerMode:返回上级页面时动画效果

  • float:呈现一个位于顶部的单个页眉, 并在屏幕被更改时进行动画显示, 这是 iOS 上常见的模式
  • screen:每个屏幕都有一个标头, 并且页眉随屏幕一起淡入和淡出, 这是 Android 的常见模式
  • none:无动画

用于导航器内部页面的navigationOptions:

  • header:可以设置一些导航的属性,如果隐藏顶部导航栏只要将这个属性设置为null
  • headerTitle:设置导航栏标题
  • headerBackImage:在标题的后退按钮中显示自定义图片
  • headerBackTitle:设置跳转页面左侧返回箭头后面的文字,默认是上一个页面的标题。可以自定义,也可以设置为null
  • headerTruncatedBackTitle:设置当上个页面标题不符合返回箭头后的文字时,默认改成"返回"
  • headerRight:在标题栏右侧展示的 React 组件
  • headerLeft:在标题栏左侧展示的 React 组件
  • headerStyle:设置导航条的样式。背景色,宽高等
  • headerTitleStyle:设置导航栏文字样式
  • headerBackTitleStyle:设置导航栏‘返回’文字样式
  • headerLeftContainerStyle:自定义 headerLeft 组件容器的样式,例如,增加 padding
  • headerRightContainerStyle:自定义 headerRight 组件容器的样式,例如,增加 padding
  • headerTitleContainerStyle:自定义 headerTitle 组件容器的样式,例如,增加 padding
  • headerTintColor:设置导航栏颜色
  • headerPressColorAndroid:安卓独有的设置颜色纹理,需要安卓版本大于5.0
  • headerTransparent:标头背景是否透明
  • headerBackground:将其与 headerTransparent 一起使用, 以提供要在标头背景下呈现的组件
  • gesturesEnabled:是否可以使用手势关闭此页面,iOS默认支持,安卓默认关闭    

 

底部导航样式属性


initialRouteName: 第一次加载时初始选项卡路由的 routeName

order:定义选项卡顺序的 routeNames 数组

tabBarOptions

  • activeTintColor:标签和图标选中颜色
  • activeBackgroundColor:导航选中背景色
  • inactiveTintColor:标签和图标未选中颜色
  • inactiveBackgroundColor:导航未选中背景色
  • showIcon:是否显示 Tab 的图标,默认不显示
  • style:选项卡栏的样式对象
  • labelStyle:选项卡标签的样式对象
  • tabStyle:选项卡的样式对象 

 

示例:

import React, { Component } from 'react'

import { createStackNavigator, createBottomTabNavigator, createAppContainer } from 'react-navigation'

import Home from './Home'
import Mine from './Mine'

const StackNavigator = createStackNavigator(
    {
        Home,
        Mine,
    },
    {
        initialRouteName: 'Home',
        defaultNavigationOptions: {
            headerStyle: {
                // backgroundColor: '#f4511e',
            },
            headerBackTitle: null,
            // headerTintColor: '#fff',
            headerTitleStyle: {
                fontWeight: 'bold',
            },
            header: null
        }
    }
)
const HomeStack = createStackNavigator({Home});
const MineStack = createStackNavigator({Mine});

const BottomTabNavigator = createBottomTabNavigator(
    {
        Home,
        Mine,
    },
    {
        initialRouteName: 'Home', //第一次加载时初始选项卡路由的 routeName
        order: ['Mine','Home'], //定义选项卡顺序的 routeNames 数组
        tabBarOptions: {
            activeTintColor: 'red',//标签和图标选中颜色
            activeBackgroundColor: 'yellow',//导航选中背景色
            inactiveTintColor: '#000', //标签和图标未选中颜色
            inactiveBackgroundColor: 'white',//导航未选中背景色
            showIcon: true,//是否显示 Tab 的图标,默认不显示
            style: {
                backgroundColor: 'yellow',//tabBar背景色
                height: 49
            },
            // labelStyle 选项卡标签的样式对象
            // tabStyle 选项卡的样式对象
        },
    }
)

// const AppContainer = createAppContainer(StackNavigator); 顶部导航
const AppContainer = createAppContainer(BottomTabNavigator); //底部导航

export default class Navigation extends Component {
    render() {
        return (
            <AppContainer/>
        )
    }
}

还有一些不常用的属性与样式没有用到,具体的可以查看官方:API

 

附加:带有icon图标的底部导航,用到了 nativebase 与 react-native-vector-icons

import React, { Component } from 'react';
import { createAppContainer, createBottomTabNavigator } from 'react-navigation'
import { Icon } from 'native-base';

import App from './App'
import Car from './Car'
import Camera from './Camera'
import Search from './Search'

const SELECTED_COLOR = 'white';
const UNSELECTED_COLOR = '#000';
const SELECTED_BGCOLOR = 'blue';
const UNSELECTED_BGCOLOR = 'deepskyblue';
const ORDER = ['App','Search','Camera','Car'];

export class TabBarIcon extends Component {
    render() {
        return(
            <Icon name={this.props.name}
                style={{
                    marginBottom: -5,
                    marginRight: 2,
                    fontSize: 24,
                    color: this.props.color,
                }}
            />
        )
    }
}
 
const BottomTabNavigator = createBottomTabNavigator(
    {
        App: {
            screen: App,
            navigationOptions: {
                tabBarLabel: '首页',
                tabBarIcon:({focused}) => (
                    <TabBarIcon
                        focused={focused}
                        name={'apps'}
                        color={focused ? SELECTED_COLOR : UNSELECTED_COLOR}
                    />
                )
            }
        },
        Car: {
            screen: Car,
            navigationOptions: {
                tabBarLabel: '汽车',
                tabBarIcon:({focused}) => (
                    <TabBarIcon
                        focused={focused}
                        name={'car'}
                        color={focused ? SELECTED_COLOR : UNSELECTED_COLOR}
                    />
                )
            }
        },
        Camera: {
            screen: Camera,
            navigationOptions: {
                tabBarLabel: '相机',
                tabBarIcon:({focused}) => (
                    <TabBarIcon
                        focused={focused}
                        name={'camera'}
                        color={focused ? SELECTED_COLOR : UNSELECTED_COLOR}
                    />
                )
            }
        },
        Search: {
            screen: Search,
            navigationOptions: {
                tabBarLabel: '搜索',
                tabBarIcon:({focused}) => (
                    <TabBarIcon
                        focused={focused}
                        name={'search'}
                        color={focused ? SELECTED_COLOR : UNSELECTED_COLOR}
                    />
                )
            }
        }
    },
    {
        initialRouteName: 'App',
        order: ORDER,
        tabBarOptions: {
            activeTintColor: SELECTED_COLOR,
            activeBackgroundColor: SELECTED_BGCOLOR,
            inactiveTintColor: UNSELECTED_COLOR,
            inactiveBackgroundColor: UNSELECTED_BGCOLOR,
            style: {
                backgroundColor: 'pink',
            },
            labelStyle: {
                paddingBottom: 5,
                fontSize: 14,
            }
        }
    }
)
const AppContainer = createAppContainer(BottomTabNavigator); 

export default class FooterTabsExample extends Component {
    render() {
        return (
            <AppContainer/>
        )
    }
}

效果图:


tabBarIcon:({focused}) => (
    <TabBarItem
        focused={focused}
        normalImage={require('../icon/home.png')}
        selectedImage={require('../icon/home_selected.png')}
    />
)

 export class TabBarItem extends Component {
    render() {
        return(
            <Image source={ this.props.focused 
                ? this.props.selectedImage 
                : this.props.normalImage }
                style={ { width:24,height:24 } }
            />
        )
    }
}

 

D:\AwesomeProject>npm ls react AwesomeProject@0.0.1 D:\AwesomeProject +-- @ant-design/icons-react-native@2.3.2 | `-- react@17.0.2 deduped +-- @ant-design/react-native@5.4.2 | +-- @floating-ui/react-native@0.10.7 | | `-- react@17.0.2 deduped | +-- rc-field-form@2.7.0 | | `-- react@17.0.2 deduped | +-- rc-util@5.44.4 | | `-- react@17.0.2 deduped | +-- react-native-collapsible@1.6.2 | | `-- react@17.0.2 deduped | +-- react-native-modal-popover@2.1.3 | | `-- react@17.0.2 deduped | `-- react@17.0.2 deduped +-- @react-native-community/cameraroll@4.1.2 | `-- react@17.0.2 deduped +-- @react-native-community/masked-view@0.1.11 | `-- react@17.0.2 deduped +-- @react-native-community/segmented-control@2.2.2 | `-- react@17.0.2 deduped +-- @react-native-community/slider@3.0.3 | `-- react@17.0.2 deduped +-- @react-native-community/viewpager@4.2.4 | `-- react@17.0.2 deduped +-- @react-native-picker/picker@1.16.8 | `-- react@17.0.2 deduped +-- @react-navigation/native-stack@6.11.0 | +-- @react-navigation/elements@1.3.31 | | `-- react@17.0.2 deduped | `-- react@17.0.2 deduped +-- @react-navigation/native@6.1.18 | +-- @react-navigation/core@6.4.17 | | +-- react@17.0.2 deduped | | `-- use-latest-callback@0.2.4 | | `-- react@17.0.2 deduped invalid: "^16.0.0" from node_modules/react-native-elements/node_modules/react-native-ratings | `-- react@17.0.2 deduped +-- @rneui/base@4.0.0-rc.8 | `-- react-native-ratings@8.1.0 | `-- react@17.0.2 deduped +-- react-native-elements@1.2.7 | `-- react-native-ratings@6.5.0 | `-- react@17.0.2 deduped invalid: "^16.0.0" from node_modules/react-native-elements/node_modules/react-native-ratings +-- react-native-exception-handler@2.10.10 | `-- react@17.0.2 deduped +-- react-native-image-picker@3.8.1 | `-- react@17.0.2 deduped +-- react-native-image-zoom-viewer@3.0.1 | +-- react-native-image-pan-zoom@2.1.12 | | `-- react@17.0.2 deduped invalid: "^16.0.0" from node_modules/react-native-elements/node_modules/react-native-ratings | `-- react@17.0.2 deduped +-- react-native-linear-gradient@2.8.3 | `-- react@17.0.2 deduped +-- react-native-permissions@3.8.0 | `-- react@17.0.2 deduped +-- react-native-reanimated@2.14.4 invalid: ">=3.10.1" from node_modules/@ant-design/react-native | `-- react@17.0.2 deduped +-- react-native-safe-area-context@3.3.2 | `-- react@17.0.2 deduped +-- react-native-screens@3.15.0 | +-- react-freeze@1.0.4 | | `-- react@17.0.2 deduped invalid: "^16.0.0" from node_modules/react-native-elements/node_modules/react-native-ratings | `-- react@17.0.2 deduped +-- react-native-svg-charts@5.4.0 | `-- react@17.0.2 deduped +-- react-native-webview@11.26.1 | `-- react@17.0.2 deduped +-- react-native@0.68.0 | +-- react-shallow-renderer@16.14.1 | | `-- react@17.0.2 deduped invalid: "^16.0.0" from node_modules/react-native-elements/node_modules/react-native-ratings | +-- react@17.0.2 deduped | `-- use-subscription@1.11.0 | +-- react@17.0.2 deduped invalid: "^16.0.0" from node_modules/react-native-elements/node_modules/react-native-ratings | `-- use-sync-external-store@1.5.0 | `-- react@17.0.2 deduped invalid: "^16.0.0" from node_modules/react-native-elements/node_modules/react-native-ratings +-- react-redux@7.2.9 | `-- react@17.0.2 deduped +-- react-test-renderer@17.0.2 | `-- react@17.0.2 deduped `-- react@17.0.2 npm error code ELSPROBLEMS npm error invalid: react@17.0.2 D:\AwesomeProject\node_modules\react npm error A complete log of this run can be found in: C:\Users\临时\AppData\Local\npm-cache\_logs\2025-08-01T01_11_42_653Z-debug-0.log
最新发布
08-02
<think>好的,我现在需要分析用户提供的`npm ls react`输出,找出可能导致React Hooks错误的原因。首先,用户之前遇到了“Invalid hook call”错误,这通常与React版本不一致或多个实例有关。 首先看用户的依赖树,最顶层的`react`版本是17.0.2,大部分依赖都标记了`deduped`(去重),说明它们共享了顶层的React实例。但注意到有几个依赖项标记了`invalid`,例如: - `node_modules/react-native-elements/node_modules/react-native-ratings`中要求`react@^16.0.0`,但实际使用的是17.0.2。 - `react-native-image-pan-zoom`、`react-freeze`、`react-shallow-renderer`、`use-subscription`、`use-sync-external-store`等依赖也有类似的`invalid`提示,都是因为它们的`peerDependencies`要求React版本为16.x,但项目中实际用了17.0.2。 另外,还有一个更严重的问题:`react-native-reanimated`标记为`invalid`,因为`@ant-design/react-native`要求它的版本`>=3.10.1`,但用户安装的是2.14.4,版本不匹配。 这些版本冲突可能导致React实例不一致或依赖解析错误,从而引发Hooks调用异常。具体来说: 1. **Peer Dependency 不兼容**:部分依赖(如`react-native-ratings`)的`peerDependencies`要求React 16.x,但项目使用React 17.x,虽然npm/yarn可能允许安装,但可能导致运行时问题,因为这些库可能未完全兼容React 17的Hooks机制。 2. **react-native-reanimated 版本不匹配**:`@ant-design/react-native`需要`react-native-reanimated >=3.10.1`,但用户安装了2.14.4,这可能导致该库无法正确初始化,进而影响React Native的AppRegistry注册,引发第二个错误(“Module AppRegistry is not registered”)。 3. **依赖解析混乱**:尽管大部分依赖共享了顶层的React 17.0.2,但部分子依赖的`invalid`标记可能导致npm在解析时生成不一致的模块树,可能间接导致React实例被多次加载(例如某些库可能尝试从自己的`node_modules`中引入React)。 解决步骤应针对这些具体的版本冲突: - **升级 react-native-reanimated 到符合要求的版本**(>=3.10.1),以满足`@ant-design/react-native`的依赖需求。 - **处理 react-native-ratings 等库的React版本不兼容**:检查`react-native-elements`和`react-native-ratings`的版本是否有支持React 17的更新版本,或者考虑替换为其他兼容的组件库。 - **清理并重新安装依赖**:删除`node_modules`和锁文件,重新安装以确保依赖解析正确。 - **检查 peerDependencies 警告**:安装时注意npm/yarn的警告信息,手动安装符合要求的peer依赖(如果必要)。 </think>根据你提供的`npm ls react`输出,问题主要集中在**依赖版本冲突**和**Peer Dependency 不兼容**,这是导致“Invalid hook call”和“AppRegistry未注册”错误的核心原因。以下是具体分析和解决方法: ### 一、关键问题定位 从依赖树可以看到两个核心冲突: #### 1. `react-native-reanimated` 版本不匹配 `@ant-design/react-native` 要求 `react-native-reanimated >=3.10.1`,但你当前安装的是 `2.14.4`(标记为`invalid`)。 这会导致 `@ant-design/react-native` 无法正常初始化,可能引发React Native核心模块(如AppRegistry)加载失败,从而出现“Module AppRegistry is not registered”错误。 #### 2. 多个依赖的 Peer Dependency 与 React 17 不兼容 例如: - `react-native-ratings`(来自`react-native-elements`)要求 `react@^16.0.0`,但实际使用 `17.0.2`(标记为`invalid`); - `react-freeze`、`react-shallow-renderer`等依赖也存在类似的React 16.x 版本要求,但项目用了React 17.x。 虽然npm允许安装不兼容的Peer Dependency,但这些库可能未完全适配React 17的Hooks机制,导致Hooks调用上下文异常,引发“Invalid hook call”错误。 ### 二、解决步骤 #### 1. 修复 `react-native-reanimated` 版本冲突 `@ant-design/react-native` 需要 `react-native-reanimated >=3.10.1`,而React Native 0.68.x 兼容的 `react-native-reanimated` 最新版本是 **3.x**(需确认兼容性)。 **操作步骤**: ```bash # 卸载旧版本 npm uninstall react-native-reanimated # 安装兼容React Native 0.68.x的最新3.x版本(例如3.3.0,具体版本需查官方文档) npm install react-native-reanimated@3.3.0 ``` #### 2. 解决 `react-native-ratings` 等库的React版本不兼容 `react-native-ratings` 6.5.0(来自`react-native-elements@1.2.7`)仅支持React 16.x,而你使用React 17.x。 **解决方案**: - **升级 `react-native-elements` 到更高版本**:新版本可能已修复Peer Dependency问题。例如,`react-native-elements@4.x` 可能支持React 17/18。 执行:`npm install react-native-elements@latest`(注意检查是否兼容React Native 0.68.x)。 - **替换为其他组件库**:如果升级后仍有问题,考虑使用其他兼容React 17的评分组件(如`react-native-star-rating`)。 #### 3. 清理依赖并重新安装 版本冲突可能导致缓存残留,需彻底清理后重新安装: ```bash # 删除依赖和锁文件 rm -rf node_modules package-lock.json # 重新安装 npm install ``` #### 4. 验证依赖一致性 重新安装后,再次运行 `npm ls react`,确认所有`invalid`标记消失,且所有依赖指向同一React 17.0.2实例。 ### 三、额外注意事项 - **React Native 0.68.x 兼容版本**:确保所有依赖(如`@ant-design/react-native`)兼容React Native 0.68.x。例如,`@ant-design/react-native@5.4.2` 是否支持0.68.x需查看官方文档。 - **Hooks 调用检查**:即使依赖修复,仍需确认代码中Hooks是否在函数组件顶层调用(无循环/条件/类组件中调用)。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值