Since version 0.44, Facebook has abandoned the Navigator interface to control the route jump of RN applications, and recommends using the React-Navigation library to realize the navigation and jump functions of applications. This article will not only introduce the learning and use of react navigation, but also introduce the past use of Navigator interface and how they can achieve centralized management of route hops in the application. The author will not introduce too much about the use of properties and methods of Navigator and React navigation. The author aims to learn and understand the use of stack routing in React Native.
Stack concept understanding
For single page application (SPA) routing in mobile apps, you can interpret it as follows:
- APP == Set of playing cards (including deck)
- Stack container (StackNavigator or StackNavigator in React-Navigation) == card box
- Page (route) == card
Now we go to the empty card inside the box into the card J, is this your initialization page, you can add a card Q, J, covered the brand, you can see the page in your application becomes a brand Q, this operation is a PUSH, and then you put the card Q out of the card in the box, you can return to the previous card J, this operation is POP, In a PUSH operation, you can only put one object in a row over and over again. This object may be a card, but it may also be a container containing multiple pages of the same class, such as your Tab container page. This is the simplest single page jump and return route operation, and other related operations are as follows:
- Reset:In A box that already has cards J, Q and K, take all the cards out at once and put them in card A. This process is to reset your entire route.
- PopTo (return to specified page) :The J, Q, K have card box in the face of each card to subscript 0, in sequence, is actually an array structure, the current case, you can see the sign K, you pop () returns to Q is equivalent to popTo (1), you can also use popTo (0), so you disposable away the top brand Q, K, You only have a jack left in your deck, which is equivalent to returning multiple pages in sequence at once;
- GetCurrentRoutes (get all current routes) :By subscript 0,1,2 for each card in a box that already has cards J, Q, and K, you can obtain the routing array of the concept of the card box. You can specify the operation of the current card in the box.
Extension: Your App is your card box, you can only operate on the cards that are already in your card box, of course, you can also take a new card and put it into the card box, but if your card is not in your card box, you can’t operate, so sometimes if the card is not in your card box, You will not succeed in manipulating a non-existent page object using concepts such as notifier and observation.
Navigator use and encapsulation
Click on the official documentation
After version 0.44, Navigator has been removed from the React-Native library. If you need to import Navigator, do as follows:
// install
$npm install React-native-deprecated-custom-components --save
// import API
import CustomerComponents, {Navigator} from 'react-native-deprecated-custom-components';Copy the code
For single-page application in actual projects, we can encapsulate Navigator as a component, and convert each page as a scene of Navigator, and only call corresponding methods when various operations such as jump, return and animation are realized in the page.
class APP extends Component {
constructor(props) {
super(props);
this._renderScene = this._renderScene.bind(this);
this.state = {};
}
/* eslint-disable */
_renderScene(route, navigator) {
let Component = route.component;
return( <Component {... route} navigator={navigator} passProps={route.passProps} callback={route.callback} /> ); } render() { return ( <View style={{ flex: 1 }}> <Navigator ref="navigator" renderScene={this._renderScene} configureScene={(route) => ({ ... route.sceneConfig || Navigator.SceneConfigs.HorizontalSwipeJump, gestures: route.gestures })} initialRoute={{ component: Login }} /> <LoadingView isVisible={this.props.showLoading} /> </View> ) } }Copy the code
In addition to scene transformation and other operations, this component can also integrate some global operations to control App, such as Loading Settings, network status check and other Settings, which do not need to be set separately in each page. Try to implement similar defaults for controlling your app in one place
Jump or other operations in the actual page:
_jumpPage() {
const { navigator } = this.props;
if (navigator) {
navigator.push({
component: TabBarList, //next route
sceneConfig: Navigator.SceneConfigs.FloatFromBottomAndroid, // animated config
callback: (a)= > {} //callback
passProps: { //transfer parameters
tabs: 'home'.activeTab: 'home'.onPressHandler: this.props.goToPage } }); }}Copy the code
React Navigation understand and use
Click on the official documentation
The Navigator used for routing control before The React-Native version 0.44 was very stable and had almost no bugs, but the jump effect was always criticized. When jumping, the animation was obviously inferior to that of the native App. After 0.44, Facebook recommends using the React-Navigation library for page hops, TAB transitions, and sidebar swiping.
React-navigation mainly includes navigation, bottom TAB, top TAB, sideslip, etc. It is very powerful and the experience is close to native. The following will be introduced one by one:
- Navigation – > StackNavigator
- Bottom or top TAB -> TabNavigator
I won’t cover the use of sideslip DrawerNavigator in this article, but check out this recommended blog post with the Demo
StackNavigator
StackNavigator is functionally equivalent to the original Navigator, but it has a different implementation and a very good jump experience. It is also very simple to use, which is basically a trilogy:
- Routing Configuration (page registration) :
const routeConfigs = {
Login: { screen: Login },
TabBar: { screen: TabBarContainer },
Feedback: { screen: Feedback },
};Copy the code
- Default configuration:
const stackNavigatorConfig = {
initialRouteName: 'Login'.navigationOptions: {
headerBackTitle: null.headerTintColor: 'white'.showIcon: true.swipeEnabled: false.animationEnabled: false.headerStyle: {
backgroundColor: '#f2f2f2'}},mode: 'card'.paths: 'rax/: Login'.headerMode: 'float'.transitionConfig: (() = > ({
screenInterpolator: CardStackStyleInterpolator.forHorizontal // android's config about jump to next page
})),
onTransitionStart: (a)= > {},
onTransitionEnd: (a)= >{}};Copy the code
- Container generation and initialization:
const Nav = StackNavigator(routeConfigs, stackNavigatorConfig);
export default class QQDrawerHome extends Component {
render() {
return(
<Nav/>); }}Copy the code
Add the new page to the routeConfigs. StackNavigator will map the registration page to the KEY used in the registration. When switching between pages, you just need to do this:
_jumpPage() {
const { navigation } = this.props;
if (navigation) {
const { navigation } = this.props;
navigation.navigate('TabBar'); }}Copy the code
When skipping with parameters:
_jumpPage() {
const { navigation } = this.props;
if (navigation) {
const { navigation } = this.props;
navigation.navigate('TabBar', {
visible: false.title: 'home'}); }}Copy the code
On the next page you can get the parameters and set the header or other parameters:
static navigationOptions = ({ navigation }) = > {
const { state } = navigation;
const { title } = state.params;
return {
title: title,
};
};Copy the code
Other operations such as reset and setParams can be used in components as described in this article, or you can reset the route directly in the page jump function, like this:
const resetAction = NavigationActions.reset({
index: 0.actions: [
NavigationActions.navigate({ routeName: 'Login'})]})this.props.navigation.dispatch(resetAction)Copy the code
TabNavigator
Before version 0.44, we used the framework react-native tab-navigator or react-native scrollable tab-view to implement Tab pages. TabNavigator is now recommended in the React-Navigation library after 0.44, which is similar to StackNavigator:
const routeConfigs = {
Message: {screen:QQMessage,
navigationOptions: {
tabBarLabel: 'message'.tabBarIcon: ({ tintColor }) = >( <Image source={require('./notif-icon.png')} style={[styles.icon, {tintColor: TintColor}] />),}}, Contact:{screen:QQContact, navigationOptions: {tabBarLabel: 'Contact ', tabBarIcon: ({ tintColor }) => ( <Image source={require('./notif-icon.png')} style={[styles.icon, {tintColor: tintColor}]} />), } }, }; const tabNavigatorConfig = { tabBarComponent:TabBarBottom, tabBarPosition:'bottom', swipeEnabled:false, animationEnabled:false, lazy:true, initialRouteName:'Message', backBehavior:'none', TabBarOptions: {activeTintColor: 'RGB (78187251), activeBackgroundColor:' white 'inactiveTintColor:' RGB (127131146), inactiveBackgroundColor:'white', labelStyle:{ fontSize:12 } } } export default TabNavigator(routeConfigs, tabNavigatorConfig);Copy the code
Some notes and current issues about using TabNavigator:
- If you don’t even use StackNavigator and want to use TabNavigator directly, use another third-party framework that comes with StackNavigator and you have to make sure TabNavigator is in StackNavigator. TabNavigator works well.
- If you use a TabNavigator on your current page, the TabNavigator container component should be the top component of the current page. Otherwise, you will not be able to get the Router array in the TAB.
- As for the nested use of TabNavigator, that is, TabNavigator is used again in one screen of TabNavigator to form a page, sub-components cannot be rendered under Android platform, the page is blank, and the inner Tab is basically invalid. Or if your inner Tab container uses another third-party framework such as react-native tab-View, the problem will still exist.
Centralized encapsulation of StackNavigator routes
This section integrates some Redux knowledge, and it is recommended that you check out the official Redux documentation to learn more about Redux. AddNavigationHelpers is the interface that allows you to add Redux management to your own routing data. Actions in navigators such as setParams are packaged directly into components to form the page call interface.
The following is the author’s encapsulation component, similar to the previous encapsulation Navigator component encapsulation centralized management component idea code, we also encapsulated StackNavigator into a component as the management center
. const AppNavigator = StackNavigator(RouteConfigs, stackNavigatorConfig);// eslint-disable-line
class MainContainer extends Component {
constructor(props) {
super(props);
this.resetRouteTo = this.resetRouteTo.bind(this);
this.resetActiveRouteTo = this.resetActiveRouteTo.bind(this);
this.backTo = this.backTo.bind(this);
this.setParamsWrapper = this.setParamsWrapper.bind(this);
this.state = {};
}
resetRouteTo(route, params) {
const { dispatch } = this.props;
if (dispatch) {
dispatch(
NavigationActions.reset({
index: 0.actions: [NavigationActions.navigate({ routeName: route, params: params })],
})
);
}
}
resetActiveRouteTo(routeArray, activeIndex) {
const { dispatch } = this.props;
if (dispatch) {
const actionsArray = [];
for (let i = 0; i < routeArray.length; i++) {
actionsArray.push(NavigationActions.navigate({ routeName: routeArray[i] }));
}
const resetAction = NavigationActions.reset({
index: activeIndex,
actions: actionsArray,
});
dispatch(resetAction);
}
}
backTo(key) {
const { dispatch } = this.props;
if (dispatch) {
dispatch(
NavigationActions.reset({
key: key
})
);
}
}
setParamsWrapper(params, key) {
const { dispatch } = this.props;
if (dispatch) {
const setParamsAction = NavigationActions.setParams({
params: params,
key: key,
});
dispatch(setParamsAction);
}
}
render() {
const { dispatch, navigationState, screenProps } = this.props;
return( <View style={{ flex: 1 }} onStartShouldSetResponder={() => dismissKeyboard()} > <StatusBar barStyle="light-content" /> <AppNavigator navigation={addNavigationHelpers({ dispatch: dispatch, state: navigationState, resetRouteTo: (route, params) => this.resetRouteTo(route, params), resetActiveRouteTo: (routeArray, activeIndex) => this.resetActiveRouteTo(routeArray, activeIndex), backTo: (key) => this.backTo(key), setParamsWrapper: (params, key) => this.setParamsWrapper(params, key) })} screenProps={screenProps} /> <Loading isVisible={true} mode="alipay" /> </View> ); } } const mapStateToProps = (state) => { const newNavigationState = state.navReducer; if (state.screenProps) { newNavigationState.params = { ... state.params, ... state.screenProps }; } return { navigationState: newNavigationState, screenProps: state.screenProps }; }; export default connect(mapStateToProps)(MainContainer); .Copy the code
For data bound to the navReducer file, please refer to the official documents of redux and React-Navigation, which are not listed in this document
In this way, when the page uses reset, setParams and other operations, it can be directly used as before, such as resetting the route:
_jumpPage() {
const { navigation } = this.props;
if (navigation) {
navigation.resetRouteTo('TabBar', { title: 'home'.selectedTab: 'home'}); }}Copy the code
Write in the last
It is the first time for me to write a blog. If there is any inadequacy, or some of the questions above are wrong, we welcome your criticism and correction. We can learn and make progress together.
Relevant articles can be referred to:
ReactNative’s new favorite, React-Navigation
React Native Future navigator: Use React navigation in detail