Closed DengZhouLi closed 6 years ago
@Ashoat Thank you for putting this new version. I would like to get some more context on the required setup for handling the back button integration.
From following the redux-integration docs, I don't clearly get how to connect the HOC to be able to handle it like this:
/* more setup code here! this is not a runnable snippet */
return <AppNavigator navigation={navigation} />;
So I choose to connect separately the AppNavigator
using the reduxifyNavigator
. This way it works but I'm not certain if this would be the best approach. I would like to understand how to pass navigation
as prop as shown on the docs.
This is what i'm currently doing:
// Setup navigator
const MainStack = createStackNavigator(routesConfig);
const Drawer = createDrawerNavigator(
{
Main: { screen: MainStack },
},
{
contentComponent: NavigationDrawer,
},
);
export const AppNavigator = createStackNavigator(
{
Splash: {
screen: SplashScreen,
description: 'Loading screen',
},
Drawer: {
screen: Drawer,
description: 'main drawer',
},
},
{
initialRouteName: 'Splash',
headerMode: 'none',
},
);
// Create middleware and connect
export const appNavigatorMiddleware = createReactNavigationReduxMiddleware(
'root',
state => state.nav,
);
const mapNavStateProps = state => ({
state: state.nav,
});
const reduxAppNavigator = reduxifyNavigator(AppNavigator, 'root');
const AppNavigatorWithState = connect(mapNavStateProps)(reduxAppNavigator);
// create nav component
export default class ReduxNavigation extends PureComponent {
componentDidMount() {
BackHandler.addEventListener("hardwareBackPress", this.onBackPress);
}
componentWillUnmount() {
BackHandler.removeEventListener("hardwareBackPress", this.onBackPress);
}
onBackPress = () => {
const { dispatch, nav } = this.props;
if (nav.index === 0) {
return false;
}
dispatch(NavigationActions.back());
return true;
};
render() {
return <AppNavigatorWithState />;
}
}
Thanks in advance
Looks like the Redux integration docs need to be updated. If anybody can do a PR on this file to update them, it would be much appreciated.
The long and short of it is that reduxNavigator
handles the navigation
property mentioned in the docs. You pass it dispatch
and state
, and it converts those to navigation
and passes it to your root navigator component (the one you passed to reduxNavigator
).
@jhesgodi: The only thing I would change in your code is that instead of calling connect
twice - once on ReduxNavigation
and once on reduxAppNavigator
- I would call it just once, on ReduxNavigation
, and pass the dispatch
and state
props in from ReduxNavigation
directly to reduxAppNavigator
. If you fix that up you'll have the right code to update the docs to!
Thanks for the help @Ashoat.
For anyone else looking for clues, this was my final working output
// Setup navigator
const MainStack = createStackNavigator(routesConfig);
const Drawer = createDrawerNavigator(
{
Main: { screen: MainStack },
},
{
contentComponent: NavigationDrawer,
},
);
export const MainNavigator = createStackNavigator(
{
Splash: {
screen: SplashScreen,
description: 'Loading screen',
},
Drawer: {
screen: Drawer,
description: 'Main drawer',
},
},
{
initialRouteName: 'Splash',
headerMode: 'none',
},
);
// Create middleware and connect
export const appNavigatorMiddleware = createReactNavigationReduxMiddleware(
'root',
state => state.nav,
);
const AppNavigator = reduxifyNavigator(MainNavigator, 'root');
// create nav component
class ReduxNavigation extends PureComponent {
componentDidMount() {
BackHandler.addEventListener("hardwareBackPress", this.onBackPress);
}
componentWillUnmount() {
BackHandler.removeEventListener("hardwareBackPress", this.onBackPress);
}
onBackPress = () => {
const { navigation, dispatch } = this.props;
if (navigation.index === 0) {
return false;
}
dispatch(NavigationActions.back());
return true;
};
render() {
const { navigation, dispatch, width, height } = this.props
const screenProps = { width, height, /*...*/ }
return <AppNavigator
state={navigation}
dispatch={dispatch}
screenProps={screenProps} // optional
/>;
}
}
const mapStateToProps = state => ({
navigation: state.nav,
// other optional props
width: state.system.layout.width,
height: state.system.layout.height - state.system.metrics.statusBarHeight,
});
export default connect(mapStateToProps)(ReduxNavigation);
You should really put this into the README :)
PRs welcome! We have a little pseudocode snippet for the back button at the bottom of the README, but it could always be improved. The snippet above is probably a bit more verbose than we need, but definitely open to improvements.
https://reactnavigation.org/docs/en/redux-integration.html#handling-the-hardware-back-button-in-android