React-Native--01 从React-Navigation开始

从React-Navigation开始

如何创建一个iOS 上面NavigationController + UITabBarController的架构?

直接开始撸代码,撸完再解释:
今天目标是:
1.创建一个工程(今天是2019年4月1日,是最新的React-native version是0.59)
2.查看工程目录
3.导入React-Navigation
4.开始项目编写主界面和子页面
5.开始搭建NavigationController + UITabBarController架构
6.运行项目
7.总结

1.创建一个工程(今天是2019年4月1日,是最新的react-native version是0.59)

到你想创建工程的文件夹路径下,执行如下代码

/**
 * react-native init 固定写法,初始化
 * NavigationProject 工程名字,随便起,无关大雅
 */
$react-native init NavigationProject

image.png

注意:网络好的情况下几十秒就创建完成了

2.查看工程目录

image.png

android:这是android项目的入口
iOS:这是iOS项目的入口
node_modules:用于存放node.js包,里面是一些js的库
.js:项目文件,用于存放逻辑处理,界面代码的
.json:配置性的文件
注:跨平台项目都会生成多个工程入口去对应不同的平台

index.js:相当于原生开发中的main文件,工程的入口,App.js就是一个界面(这里用的是vs code)

image.png

3.导入React-Navigation

image.png

拉起vscode底下蓝色状态栏目部分,选择TERMINAL这一项,这里相当于你的终端,输入:

$yarn add react-navigation
# 或者使用 npm
# $npm install --save react-navigation

等待下载完毕,查看yarn.lock文件中是否存在了React-navigation相关的配置

下列两个步骤一定要去添加

$yarn add react-native-gesture-handler
# or with npm
# $npm install --save react-native-gesture-handler

Link的原生依赖

$react-native link react-native-gesture-handler

对于Android工程,在Android中的MainActivity.java

import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;


@Override
protected ReactActivityDelegate createReactActivityDelegate() {
    return new ReactActivityDelegate(this, getMainComponentName()) {
    @Override
    protected ReactRootView createRootView() {
        return new RNGestureHandlerEnabledRootView(MainActivity.this);
        }
    };
}

image.png

如果开发混编App需要到工程里面去做相应的配置,请参考官网
++ https://reactnavigation.org/docs/zh-Hans/getting-started.html ++

代码编写

1.stack navigator的使用

stack navigator:简单理解就是iOS中的UINavigationController,负责页面的跳转,导航;是一个先进后出的栈。

1.配置一个NavigationContainer
通过:createStackNavigator()这个方法来创建一个NavigationContainer

// 源码
export function createStackNavigator(
    routeConfigMap: NavigationRouteConfigMap,
    stackConfig?: StackNavigatorConfig
): NavigationContainer;

创建一个NavigationContainer需要两个参数:
routeConfigMap:路由配置地图,简单来说可以预先添加几个界面

// 通过源码来查看routeConfigMap
// NavigationRouteConfigMap
export interface NavigationRouteConfigMap {
    [routeName: string]: NavigationRouteConfig;
}

// NavigationRouteConfig
export type NavigationRouteConfig =
    | NavigationComponent
    | ({
        navigationOptions?: NavigationScreenConfig<any>;
        path?: string;
    } & NavigationScreenRouteConfig
);

// NavigationScreenRouteConfig
export type NavigationScreenRouteConfig =
    | NavigationComponent
    | {
        screen: NavigationComponent;
      }
    | {
        getScreen: () => NavigationComponent;
      };

由源码我们可以知道routeConfigMap是一个字符串:一个路由配置构成
可以简单理解为

{字符串(表示路由名字):路由配置}

NavigationRouteConfig:配置是的可以接收三种类型的入参

第一种,传入一个extends NavigationComponent的组建

第二种, 传入{navigationOptions?:NavigationScreenConfig<any>;path?: string};
NavigationScreenConfig:导航页面的相关配置
path:路径

第三种,一个返回NavigationComponent组建的方法

stackConfig?:栈的配置

// StackNavigatorConfig
export interface StackNavigatorConfig
    extends NavigationStackViewConfig,
      NavigationStackRouterConfig {
    containerOptions?: any;
}

// NavigationStackViewConfig
export interface NavigationStackViewConfig {
    mode?: 'card' | 'modal';
    headerMode?: HeaderMode;
    headerBackTitleVisible?: boolean;
    headerTransitionPreset?: 'fade-in-place' | 'uikit';
    headerLayoutPreset?: 'left' | 'center';
    cardShadowEnabled?: boolean;
    cardOverlayEnabled?: boolean;
    cardStyle?: StyleProp<ViewStyle>;
    transparentCard?: boolean;
    transitionConfig?: (
      transitionProps: NavigationTransitionProps,
      prevTransitionProps: NavigationTransitionProps,
      isModal: boolean
    ) => TransitionConfig;
    onTransitionStart?: (
      transitionProps: NavigationTransitionProps,
      prevTransitionProps?: NavigationTransitionProps
    ) => Promise<void> | void;
    onTransitionEnd?: (
      transitionProps: NavigationTransitionProps,
      prevTransitionProps?: NavigationTransitionProps
    ) => void;
}

// NavigationStackRouterConfig
export interface NavigationStackRouterConfig {
    headerTransitionPreset?: 'fade-in-place' | 'uikit';
    initialRouteName?: string;
    initialRouteParams?: NavigationParams;
    paths?: NavigationPathsConfig;
    defaultNavigationOptions?: NavigationScreenConfig<NavigationScreenOptions>;
    navigationOptions?: NavigationScreenConfig<NavigationScreenOptions>;
    initialRouteKey?: string;
}

一个简单例子

1.创建两个界面Index(index.js),Details(details.js)

2.编写App.js,至于Index.js(这个是系统的,为了和系统区分,我这里用了一个index,小写的)无需做任何更改;

// 导入createAppContainer, createStackNavigator两个方法
import { createAppContainer, createStackNavigator } from 'react-navigation';
// 这是我创建的两个界面
import Index from './component/index/index.js';
import Details from './component/details/details.js';

// 通过createStackNavigator创建一个NavigationContainer
const AppNavigator = createStackNavigator({
  Home: {
    screen: Index,
  },
  Details: {
    screen: Details,
  },
}, {
    initialRouteName: 'Home',
});

// 通过createAppContainer创建一个可以导出的NavigationContainer
export default createAppContainer(AppNavigator);

上述的操作,让很多无法理解createStackNavigator()和createAppContainer()创建出来的类型都是一样的
理论上我们可以写下这样代码:

import React, {Component} from "react"
import { createAppContainer, createStackNavigator } from 'react-navigation';
import Index from './component/index/index.js';
import Details from './component/details/details.js';

const AppNavigator = createStackNavigator({
  Home: {
    screen: Index,
  },
  Details: {
    screen: Details,
  },
}, {
    initialRouteName: 'Home',
});

export default class App extends Component {
  render(){
    return (
        <AppNavigator />
    );
  }
}

// export default createAppContainer(AppNavigator);

啪一下,运行报错了

image.png

报错的信息,是

Invariant Violation: The navigation prop is missing for this navigator. In react-navigation 3 you must set up your app container directly. 

换言之,就是固定写法,react-navigation 3采用的第一种方式,我当时的想法是错误的。

index.js

import React, {Component} from 'react'
import {
    View,
    Text,
    StyleSheet
} from 'react-native'

export default class Index extends Component {
    render() {
        return (
            <View style={styles.container}>
              <Text style={styles.welcome}>Welcome to React Native!</Text>
              <Text style={styles.instructions }
                    onPress={()=>{this.props.navigation.navigate('Details')}}
              >To get started, edit Index.js</Text>
            </View>
        ); 
    }
}

const styles = StyleSheet.create({
    container: {
      flex: 1,
      justifyContent: 'center',
      alignItems: 'center',
      backgroundColor: '#F5FCFF',
    },
    welcome: {
      fontSize: 20,
      textAlign: 'center',
      margin: 10,
    },
    instructions: {
      textAlign: 'center',
      color: '#333333',
      marginBottom: 5,
    },
});
  

details.js


import React, {Component} from 'react'
import {
    View,
    Text,
    StyleSheet
} from 'react-native'

export default class Details extends Component {
    render() {
        return (
            <View style={styles.container}>
              <Text style={styles.welcome}>Welcome to React Native!</Text>
              <Text style={styles.instructions} 
                    onPress={()=>{this.props.navigation.navigate('Home')}}
              >go to home </Text>

              <Text style={styles.instructions}
                    onPress={()=>this.props.navigation.goBack()}
              > go back </Text>

              <Text style={styles.instructions}
                    onPress={()=>this.props.navigation.push('Details')}
              > go to new details </Text>

              <Text style={styles.instructions}
                    onPress={()=>this.props.navigation.navigate('Details')}
              > go to details </Text>
            </View>
        ); 
    }
}

const styles = StyleSheet.create({
    container: {
      flex: 1,
      justifyContent: 'center',
      alignItems: 'center',
      backgroundColor: '#F5FCFF',
    },
    welcome: {
      fontSize: 20,
      textAlign: 'center',
      margin: 10,
    },
    instructions: {
      textAlign: 'center',
      color: '#333333',
      marginBottom: 5,
    },
});
  

查看结果:


StackNavigator.gif

我们可以打印一下this.props

// 在render()方法返回之前添加打印代码
console.log("\n details this.props", this.props);
image.png

这里我们可以看见在props中有navigation的属性,换言之,在栈里面的页面就会有一个有值的navigation属性

安利一个调试方式

网上很多教程使用chrome浏览器进行调试,对于小白来说这种调试方式很不友好,很多iOS或者Android转过来的童鞋们还是习惯的IDE里面去看报错信息。让vs code可以打印js log
1.调试操作

image.png

2.添加调试


image.png

1.这里需要注意的是,开始调试之前,请关掉之前打开调试,否则它显示调试正在进行,无法启动。

2.Android 模拟器无法启动,并提示路径不对,请将生成Android文件导入Android Studio中,Android Studio将帮你完成余下配置

3.心细的童鞋可能会发现我的界面有些不同,是因为我在准备截图的期间去换一次主题和换了一个目录,前面几张截图是之前截下来的,所以会有些写出入。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容