如何在React Native中用react-navigation更新tab栏角标且不重载导航?
React Native Tab栏角标更新不跳转解决方案
问题根因
你的实现中直接将未读计数的Redux状态绑定到了根导航器组件的props上,未读计数变更触发Redux状态更新时,整个根导航器会被重新初始化,导航栈历史记录被清空,就会自动跳回tab主导航页。
解决方案
方案一:自定义TabBar组件(推荐)
将角标数据获取逻辑从根导航器移到独立的TabBar组件内部,仅TabBar会随未读计数重渲染,不会影响整个导航栈:
// 自定义TabBar组件 import { View, Text, TouchableOpacity } from 'react-native'; import { Badge } from 'react-native-elements'; import { connect } from 'react-redux'; const CustomTabBar = ({ state, descriptors, navigation, unreadMsgCount, unreadNotifyCount }) => { return ( <View style={{ flexDirection: 'row', paddingVertical: 8, borderTopWidth: 1, borderTopColor: '#eee' }}> {state.routes.map((route, index) => { const { options } = descriptors[route.key]; const label = options.tabBarLabel ?? options.title ?? route.name; const isFocused = state.index === index; // 匹配tab添加角标 let badge = null; if (route.name === 'Message' && unreadMsgCount > 0) { badge = <Badge value={unreadMsgCount} status="error" containerStyle={{ position: 'absolute', top: -4, right: -10 }} /> } if (route.name === 'Notification' && unreadNotifyCount > 0) { badge = <Badge value={unreadNotifyCount} status="error" containerStyle={{ position: 'absolute', top: -4, right: -10 }} /> } const onPress = () => { const event = navigation.emit({ type: 'tabPress', target: route.key, canPreventDefault: true, }); if (!isFocused && !event.defaultPrevented) { navigation.navigate(route.name); } }; return ( <TouchableOpacity accessibilityRole="button" accessibilityState={{ selected: isFocused }} onPress={onPress} style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }} key={route.key} > <Text style={{ color: isFocused ? '#2196F3' : '#666' }}>{label}</Text> {badge} </TouchableOpacity> ); })} </View> ) } // 关联Redux状态 const mapStateToProps = state => ({ unreadMsgCount: state.message.unreadCount, unreadNotifyCount: state.notification.unreadCount }) const ConnectedTabBar = connect(mapStateToProps)(CustomTabBar); // 导航器中使用自定义TabBar const Tab = createBottomTabNavigator(); function MainTabNavigator() { return ( <Tab.Navigator tabBar={props => <ConnectedTabBar {...props} />}> <Tab.Screen name="Home" component={HomeScreen} /> <Tab.Screen name="Message" component={MessageStack} /> <Tab.Screen name="Notification" component={NotificationStack} /> </Tab.Navigator> ) }
方案二:通过setOptions动态更新角标
如果不需要自定义TabBar样式,可直接监听Redux状态变化,调用导航API更新角标,不会触发导航器重载:
// 可在App入口或者Tab首页引入该hook import { useSelector } from 'react-redux'; import { useNavigation } from '@react-navigation/native'; import { useEffect } from 'react'; export const useTabBadgeUpdater = () => { const navigation = useNavigation(); const unreadMsgCount = useSelector(state => state.message.unreadCount); const unreadNotifyCount = useSelector(state => state.notification.unreadCount); // 更新消息tab角标 useEffect(() => { // 嵌套导航可通过getParent()获取父级tab导航对象 const tabNavigation = navigation.getParent('MainTab'); tabNavigation?.setOptions({ tabBarBadge: unreadMsgCount > 0 ? unreadMsgCount : undefined }) }, [unreadMsgCount, navigation]); // 更新通知tab角标 useEffect(() => { const tabNavigation = navigation.getParent('MainTab'); tabNavigation?.setOptions({ tabBarBadge: unreadNotifyCount > 0 ? unreadNotifyCount : undefined }) }, [unreadNotifyCount, navigation]); }
额外排查点
检查你的Redux reducer是否误修改了导航相关状态:如果你将导航状态也存储在Redux中,更新未读计数时如果意外返回了新的导航状态对象,也会触发导航重置,需保证reducer只修改和未读计数相关的状态字段。
内容的提问来源于stack exchange,提问作者user2482671
相关产品推荐
相关产品推荐

