如何结合React Native Router Flux实现react-native-material-bottom-navigation?
Hey Carlos, let's work through how to get react-native-material-bottom-navigation playing nicely with React Native Router Flux (RNRF) without that annoying full content reload issue.
The Core Problem
Putting the BottomNavigation in every page component means every tab press re-mounts the entire page (including the nav itself), which causes the reloads you're seeing. The fix is to move the BottomNavigation to a root layout component that wraps your RNRF scenes, so it stays mounted while only the page content switches.
Step-by-Step Implementation
Here's a concrete example of how to set this up:
1. Import Dependencies & Page Components
First, bring in all the pieces you'll need:
import React, { useState, useEffect } from 'react'; import { View, StyleSheet } from 'react-native'; import { Actions, Router, Scene } from 'react-native-router-flux'; import { BottomNavigation, BottomNavigationTab } from 'react-native-material-bottom-navigation'; // Import your screen components import HomeScreen from './screens/HomeScreen'; import ProfileScreen from './screens/ProfileScreen'; import SettingsScreen from './screens/SettingsScreen';
2. Create a Root Layout with BottomNavigation
This layout will hold the BottomNavigation and render the active screen content:
const MainLayout = () => { const [activeTab, setActiveTab] = useState('home'); // Handle tab presses to trigger RNRF Actions const handleTabPress = (tabId) => { setActiveTab(tabId); switch(tabId) { case 'home': Actions.home(); break; case 'profile': Actions.profile(); break; case 'settings': Actions.settings(); break; default: break; } }; // Sync active tab with RNRF scene changes (for cases like in-app navigation) useEffect(() => { const sceneListener = Actions.addListener('sceneChange', (scene) => { switch(scene.key) { case 'home': setActiveTab('home'); break; case 'profile': setActiveTab('profile'); break; case 'settings': setActiveTab('settings'); break; } }); // Clean up listener on unmount return () => sceneListener.remove(); }, []); return ( <View style={styles.container}> {/* Render the active screen content */} <View style={styles.screenContainer}> {Actions.currentScene === 'home' && <HomeScreen />} {Actions.currentScene === 'profile' && <ProfileScreen />} {Actions.currentScene === 'settings' && <SettingsScreen />} </View> {/* Persistent Bottom Navigation */} <BottomNavigation activeTab={activeTab} onTabPress={handleTabPress} > <BottomNavigationTab id="home" label="Home" icon="home" /> <BottomNavigationTab id="profile" label="Profile" icon="account" /> <BottomNavigationTab id="settings" label="Settings" icon="settings" /> </BottomNavigation> </View> ); };
3. Set Up Your RNRF Router
Wire up the router to use your root layout as the initial scene:
const AppRouter = () => ( <Router> <Scene key="root"> {/* Main layout with persistent bottom nav */} <Scene key="main" component={MainLayout} initial /> {/* Add non-nav screens (like login) here, they won't show the bottom nav */} <Scene key="login" component={LoginScreen} /> </Scene> </Router> ); // Basic styles to fill the screen const styles = StyleSheet.create({ container: { flex: 1, }, screenContainer: { flex: 1, }, }); export default AppRouter;
Key Fixes Explained
- Single BottomNavigation Instance: By placing the nav in the root layout, it only mounts once—no more reloading the nav itself when switching tabs.
- Sync with RNRF Scenes: The
sceneChangelistener ensures the active tab highlights correctly even if you navigate via buttons inside your screens (not just the bottom nav). - No Page-Wide Nav: Remove the BottomNavigation from all your individual screen components—this eliminates the redundant mounts causing your reloads.
If you tried onPress before and it didn't work, it's likely because you were triggering navigation from a nav that was inside the screen component (which would remount everything). This approach keeps the nav separate and controls navigation at the root level.
内容的提问来源于stack exchange,提问作者Carlos Navarro

