通过React Native 环境搭建和创建项目(Mac)可以成功创建一个新项目,即直接利用以下语句创建:
- //命令行创建项目:
- react-native init AwesomeProject
创建成功后,刚入门的我们主要关注两个文件:
1)iOS项目目录下的AppDelegate.m
为将iOS项目连接js文件的入口,以及相关初始化操作。
2)根目录下的index.ios.js
为iOS对应的js入口文件。
一、 解析iOS项目中的AppDelegate.m
1. AppDelegate.m 代码如下:
- #import "AppDelegate.h"
- // React Native相关头文件
- #import "RCTBundleURLProvider.h"
- #import "RCTRootView.h"
- @implementation AppDelegate
- - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
- {
- NSURL *jsCodeLocation;
- /*
- 当应用开始运行的时候,RCTRootView将会从以下的URL中加载应用:(本地调试的时候是直接在本地服务器中的index.ios加载,发布时设置有所不同)
- 重新调用了你在运行这个App时打开的终端窗口,它开启了一个 packager 和 server 来处理上面的请求。
- 在 Safari 中打开那个 URL;你将会看到这个 App 的 JavaScript 代码
- */
- [[RCTBundleURLProvider sharedSettings] setDefaults];
- jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
- // RCTRootView是一个UIView容器,承载着React Native应用。同时它也提供了一个联通原生端和被托管端的接口。
- RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
- moduleName:@"AwesomeProject"
- initialProperties:nil
- launchOptions:launchOptions];
- rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
- self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- UIViewController *rootViewController = [UIViewController new];
- rootViewController.view = rootView;
- self.window.rootViewController = rootViewController;
- [self.window makeKeyAndVisible];
- return YES;
- }
- @end
2. RCTRootView
RCTRootView将React Natvie视图封装到原生组件中。(用户能看到的一切内容都来源于这个RootView,所有的初始化工作也都在这个方法内完成。)
解析:
通过RCTRootView的初始化函数你可以将任意属性传递给React Native应用。
参数initialProperties必须是NSDictionary的一个实例。
这一字典参数会在内部被转化为一个可供JS组件调用的JSON对象。
- NSArray *imageList = @[@"http://foo.com/bar1.png",
- @"http://foo.com/bar2.png"];
- NSDictionary *propsDict = @{@"images" : imageList};
- RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
- moduleName:@"AwesomeProject"
- initialProperties: propsDict
- launchOptions:launchOptions];
在js文件中,则是通过this.props.images调用上面定义的参数。
this为AppRegistry.registerComponent注册的组件(下面会讲到)
RCTRootView同样提供了一个可读写的属性appProperties。在appProperties设置之后,React Native应用将会根据新的属性重新渲染。当然,只有在新属性和之前的属性有区别时更新才会被触发。
(注意:1.可以随时更新属性,但是更新必须在主线程中进行,读取则可以在任何线程中进行。2.更新属性时并不能做到只更新一部分属性)
- NSArray *imageList = @[@"http://foo.com/bar3.png",
- @"http://foo.com/bar4.png"];
- rootView.appProperties = @{@"images" : imageList};
二、解析js入口文件(index.ios.js)
1. index.ios.js 代码如下:
- 'use strict'; // 全局进入严格模式(目前发现不用也行)
- /**<
- 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
- 消除代码运行的一些不安全之处,保证代码运行的安全;
- 提高编译器效率,增加运行速度;
- 为未来新版本的Javascript做好铺垫。
- */
- //导入一些必要的模块
- //React Native内置的组件可以直接通过import { xxx } from 'react-native' 进行导入,当然也可以自定义组件。
- import React, { Component } from 'react';
- import {
- AppRegistry,
- StyleSheet,
- Text,
- View,
- TouchableOpacity
- } from 'react-native';
- //类,这是默认的载入类,继承自Component,Component类(组件)似于Android和iOS中的View
- //这里为创建一个组件
- class AwesomeProject extends Component {
- //构造器 ,每个组件都拥有自己的属性(props)和状态(state)
- //调用this.setState更改状态text或者isTouchDown时,组件会触发render函数进行渲染更新
- constructor(props) {
- super(props);
- this.state = {
- text:'Welcome to React Native!',
- isTouchDown:false
- };
- }
- //在最初的渲染之前调用一次,可在里面进行预处理操作
- //在React中,设置this.state会导致重新渲染,但是componentWillMount设置this.state并不会对导致render调用多次
- //之后会对component的生命周期进一步解释
- componentWillMount() {
- }
- //渲染函数,用来渲染实际的Component可视部分
- render() {
- //var定义变量,根据状态值改变对应值
- var welcomeText = this.state.text;
- var bgcolor;
- if (this.state.isTouchDown) {
- bgcolor = '#c5c5ab';
- } else {
- bgcolor = '#F5FCFF';
- }
- console.log('testtststststts');
- //返回的即界面显示内容
- return (
- <View style={[styles.container, {backgroundColor: bgcolor}]}>
- <Text style={styles.welcome}>
- {welcomeText}
- </Text>
- <Text style={styles.instructions}>
- To get started, edit index.android.js
- </Text>
- <Text style={styles.instructions}>
- Shake or press menu button for dev menu
- </Text>
- <TouchableOpacity onPress={this.touchDown.bind(this)}>
- <Text style={[styles.instructions, {backgroundColor: 'green'}]}>
- test touch Me
- </Text>
- </TouchableOpacity>
- </View>
- );
- }
- // 自定义函数
- touchDown() {
- // console.log 控制台打印,可打印值,多用于调试
- console.log('>>', this.isTouchDown);
- if (!this.state.isTouchDown) {
- this.setState({
- text:'Test Touch Down Success',
- isTouchDown:true
- });
- } else {
- this.setState({
- text:'Test Touch Down Again Success',
- isTouchDown:false
- });
- }
- }
- }
- //定义样式
- 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,
- },
- });
- //AppRegistry 定义了App的入口,并提供了根组件。
- //***个'AwesomeProject'要与AppDelegate里注册的moduleName一致
- //第二个AwesomeProject则是入口组件,即上面定义的Component类
- AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);
2. 运行效果:
简单运行效果.png
3. 基础概念解释
1)组件
代码中的 Text, View, TouchableOpacity均为基础组件。AwesomeProject则是自己创建的组件,也作为项目的入口组件。
在React Native项目中,所有展示的界面,都可以看做是一个组件(Component)只是功能和逻辑上的复杂程度不同。每一个是许许多多小的组件拼成的,每个小的组件也有自己对应的逻辑。
2)组件的状态与属性
组件本质上是状态机,输入确定,输出一定确定。组件把状态与结果一一对应起来,组件中有state与prop(状态与属性)。
属性(props)是标签里面的属性, 组件之前通过标签的属性来传递数据,由父组件传递给子组件(单向的属性传递)。
如果component的某些状态由外部所决定,并且会影响到component的render,那么这些状态就应该用props表示。
例如:一个下拉菜单的component,有哪些菜单项,是由这个component的使用者和使用场景决定的,那么“菜单项”这个状态,就应该用props表示,并且由外部传入。
状态(state)是子组中的状态,内部的事件方法或者生命周期方法都可以调用this.setState来变更,当状态发生变化的同时,组件也会触发render函数进行渲染更新。
如果component的某些状态需要被改变,并且会影响到component的render,那么这些状态就应该用state表示。
例如:一个购物车的component,会根据用户在购物车中添加的产品和产品数量,显示不同的价格,那么“总价”这个状态,就应该用state表示。