如何在传递children的Layout组件中使用Redux connect()
Hey there, let's work through getting your Layout component connected to Redux while keeping your children (the navigation stack) intact and tracking the current routeName properly. Here's a step-by-step breakdown tailored to your app structure:
Since your Layout wraps the NavigationContainer, you'll want to listen for route changes at the app level (where the navigation container lives) and dispatch those updates to Redux. This keeps your Layout focused on rendering, not navigation logic.
import { NavigationContainer, useNavigationContainerRef } from '@react-navigation/native'; import { Provider } from 'react-redux'; import { PersistGate } from 'redux-persist/integration/react'; import Layout from './Layout'; import store from './redux/store'; import persistor from './redux/persistConfig'; function App() { // Create a ref to access the navigation container's state const navigationRef = useNavigationContainerRef(); useEffect(() => { // Handle initial route load if (navigationRef.isReady()) { const initialRoute = navigationRef.getCurrentRoute().name; store.dispatch({ type: 'SET_CURRENT_ROUTE', payload: initialRoute }); } // Listen for navigation state changes const unsubscribe = navigationRef.addListener('state', (state) => { const currentRouteName = state.routes[state.index].name; store.dispatch({ type: 'SET_CURRENT_ROUTE', payload: currentRouteName }); }); // Clean up listener on unmount return unsubscribe; }, [navigationRef]); return ( <Provider store={store}> <PersistGate loading={null} persistor={persistor}> <Layout> <NavigationContainer ref={navigationRef}> {/* Your existing stack navigator setup goes here */} <Stack.Navigator> {/* Your screen components */} </Stack.Navigator> </NavigationContainer> </Layout> </PersistGate> </Provider> ); } export default App;
Make sure your reducer handles the SET_CURRENT_ROUTE action to store the active route name:
// redux/reducers/appReducer.js const initialState = { currentRouteName: '', }; export const appReducer = (state = initialState, action) => { switch (action.type) { case 'SET_CURRENT_ROUTE': return { ...state, currentRouteName: action.payload, }; default: return state; } };
Don't forget to add this reducer to your root reducer if you haven't already!
Now you can connect Layout to Redux to access the currentRouteName prop. The key thing to remember here is that connect won't block your children prop — just make sure you still render it in the component:
// Layout.js import { connect } from 'react-redux'; const Layout = ({ children, currentRouteName }) => { return ( <div className="app-layout"> {/* Use currentRouteName to adjust your top bar here */} <TopBar activeRoute={currentRouteName} /> {/* Keep rendering the navigation stack/children */} {children} </div> ); }; // Map Redux state to component props const mapStateToProps = (state) => ({ currentRouteName: state.app.currentRouteName, // Match your reducer's path }); // Connect Layout to Redux export default connect(mapStateToProps)(Layout);
- Forgetting the initial route: The listener won't fire on the first load, so we check
navigationRef.isReady()to dispatch the initial route name. - Breaking children rendering: As long as you include
{children}in your Layout's JSX, the navigation stack will render normally —connectpasses through all parent props (including children) by default. - Accessing navigation context in Layout: Since Layout wraps the
NavigationContainer, it can't access navigation hooks likeuseRoutedirectly. That's why we handle the listening in App.js instead.
内容的提问来源于stack exchange,提问作者asdfghjklm

