通过编写的第二篇文章可以成功创建一个新项目,即直接利用以下语句创建:
//命令行创建项目:
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. 运行效果:
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表示。
这篇文章利用了一个很简单的例子去具体解析了React Native的基本代码,最主要想理解组件的概念,由此可以更好的去理解别人的代码,,接下去为了更好的入门,会继续写两篇文章分别介绍React Native用到的js基础、react基础,以及介绍组件的生命周期。
正在写React Native的学习教程ing,是一边研究一边编写的,已有的成果如下:
1) React Native 简介与入门
2) React Native 环境搭建和创建项目(Mac)
3) React Native 开发之IDE