React Native 是Facebook推出用JavaScript开发iOS和Android应用框架,它跟Cordova和Titanium等用JavaScript创建原生应用的框架有本质的不同,React Native通过编译出来的包就是个原生应用而不是嵌入Web的hybrid应用。所有它的性能比其它开发原生应用的JavaScript框架高出很多。
Build native mobile apps using JavaScript and React
React Native实现一套机制用于JS层于原生模块层通信。(详细介绍文章 )
React Native 优缺点优点:
使用React思想涉足移动端开发,提高原生开发效率。
能够利用JavaScript特性进行免安装快速更新。
相对于其它Hybird框架性能更好。
缺点:
React Native无法做到只用JavaScript开发原生应用!开发必须要有原生应用开发的经验
性能无法达到原生应用。
学习门槛高,学习成本大。Web开发者需要了解原生开发细节,原生开发者需要理解React开发思想。
本文只介绍React Native开发涉及到前端部分!因为博主完全不懂原生应用开发 :)
基础 React Native沿袭了 React组件化开发思想,UI开发方式和数据管理方式和React一样。
数据状态 React Native中有两种方式用于控制数据:props
和state
。props
是在父组件中指定,而且一经指定就无法更改。而state
是在组件初始化构造函数constructor
中声明的。在组件的生命周期和方法内可以通过setState
方法改变它的值。
创建一个组件显示父组件传递的信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import React, { Component } from 'react' ;import { AppRegistry, Text, View } from 'react-native' ;class Greeting extends Component { render () { return ( <Text > {this.props.name}!</Text > ) } }; export default class LotsOfGreetings extends Component { render () { return ( <View style ={{alignItems: 'center '}} > <Greeting name ='Rexxar' /> <Greeting name ='Jaina' /> <Greeting name ='Valeera' /> </View > ) } }; AppRegistry.registerComponent('ProjectName' , ()=> LotsOfGreetings);
创建一个组件,每个1秒钟就闪屏一次。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import React, { Component } from 'react' ;import { AppRegistry, Text, View } from 'react-native' ;class Blink extends Component { constructor (props ) { super (props); this .state = {isShowingText : true }; setInterval ( () => { this .setState(previousState => { return {isShowingText : !previousState.isShowingText}; }) }, 1000 ) } render () { let display = this .state.isShowingText ? this .props.text : ' ' ; return ( <Text > {display}</Text > ) } }; export default class BlinkApp extends Component { render () { return ( <View > <Blink text ='I love to bink' /> <Blink text ='Yes blinking is so great' /> <Blink text ='Why did they ever take this out of HTML' /> <Blink text ='Look at me look at me look at me' /> </View > ) } }; AppRegistry.registerComponent('ProjectName' , () => BlinkApp);
在构建复杂的应用时,使用setState
更新数据并不是明智的选择。对于复杂的数据业务,应该使用数据管理器控制数据的流向。Redux 是目前流行的数据管理框架。
样式 React Native中可以通过JavaScript来写样式,语法类似于CSS只是属性名使用的是驼峰命名法。例如:background-color
改为backgroundColor
。
通过StyleSheet.create
集中定义组件的样式(类似将样式写在<style></style>
)。将StyleSheet.create
中定义的样式赋予组件上的style
属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import React, { Component } from 'react' ;import { AppRegistry, StyleSheet, Text, View } from 'react-native' ;export default class LotsOfStyles extends Component { render ( ) { return ( <View > <Text style ={styles.red} > just red</Text > <Text style ={styles.bigblue} > just bigblue</Text > <Text style ={[styles.bigblue, styles.red ]}> bigblue, then red</Text > <Text style ={[styles.red, styles.bigblue ]}> red, then bigblue</Text > </View > ); } } const styles = StyleSheet.create({ bigblue : { color : 'blue' , fontWeight : 'bold' , fontSize : 30 , }, red : { color : 'red' , }, }); AppRegistry.registerComponent('LotsOfStyles' , () => LotsOfStyles);
如上所示,如果style
有多个值应该将它们用如一个数组中。
React Native中使用flexbox布局页面,它的语法和Web的CSS基本一致,它们不同点是,flexDirection
的默认值是column
而不是row
。而flex
只能指定一个数字。 React Native中组件设计的尺寸方式是指定固定的width
和height
。而它们都是没有单位的,它们于设备像素密度无关的逻辑像素点,在不用尺寸的屏幕上都显示成一样的大小。
网络请求 React Native提供了和Web标准一致的Fetch API 用于网络请求数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 fetch('https://mywebsite.com/endpoint' ,{ method : 'POST' , headers : { 'Accept' : 'application/json' , 'Content-Type' : 'application/json' }, body : JSON .stringify({ firstParam : 'yourValue' , secondParam : 'yourOtherValue' , }) }).then( response => response.json()) .then( responseJson => { return responseJson.movies; }).catch ( error => { console .error(error); });
提交数据的格式关键取决于 headers 中的 Content-Type 。不同的 Content-Type 对应的body的格式也有区别。是使用传统的 application/x-www-form-urlencoded 还是目前流行的 application/json 需要前后端沟通好。
React Native也支持WebSocket 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 var ws = new WebSocket('ws://host.com/path' );ws.onopen = () => { ws.send('something' ); }; ws.onmessage = (e ) => { console .log(e.data); }; ws.onerror = (e ) => { console .log(e.message); }; ws.onclose = (e ) => { console .log(e.code, e.reason); };
通用组件 TextInput
键盘输入文本的基本组件。通过给onChangeText
属性赋予方法,每当输入框文本变化时会触发该绑定的方法。而通过给onSubmitEditing
属性赋予方法,当用户点击提交按钮是会触发该方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import React, { Component } from 'react' ;import { AppRegistry, Text, TextInput, View } from 'react-native' ;export default class PizzaTranslator extends Component { constructor (props ) { super (props); this .state = {text : '' }; } render ( ) { return ( <View style ={{padding: 10 }}> <TextInput style ={{height: 40 }} placeholder ="Type here to translate!" onChangeText ={(text) => this.setState({text})} /> <Text style ={{padding: 10 , fontSize: 42 }}> {this.state.text.split(' ').map((word) => word && '🍕').join(' ')} </Text > </View > ); } } AppRegistry.registerComponent('AwesomeProject' , () => PizzaTranslator);
TextInput
组件属性支持还自动获取焦点(autoFocus)、自动大小写(autoCapitalize)、多种不同的键盘(keyboardType)
ScrollView
是个通用的滑动容器,其中可以放置多个组件和视图,但是它适合列表数量不多且固定的滑动。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import React, { Component } from 'react' ;import { AppRegistry, ScrollView, Image, Text } from 'react-native' ;export default class IScrolledDownAndWhatHappenedNextShockedMe extends Component { render ( ) { return ( <ScrollView > <Text style ={{fontSize:96}} > Scroll me plz</Text > <Image source ={require( '/react-native /img /favicon.png ')} /> <Image source ={require( '/react-native /img /favicon.png ')} /> <Image source ={require( '/react-native /img /favicon.png ')} /> <Image source ={require( '/react-native /img /favicon.png ')} /> <Image source ={require( '/react-native /img /favicon.png ')} /> <Text style ={{fontSize:96}} > If you like</Text > <Image source ={require( '/react-native /img /favicon.png ')} /> <Image source ={require( '/react-native /img /favicon.png ')} /> <Image source ={require( '/react-native /img /favicon.png ')} /> <Image source ={require( '/react-native /img /favicon.png ')} /> <Image source ={require( '/react-native /img /favicon.png ')} /> <Text style ={{fontSize:96}} > Scrolling down</Text > <Image source ={require( '/react-native /img /favicon.png ')} /> <Image source ={require( '/react-native /img /favicon.png ')} /> <Image source ={require( '/react-native /img /favicon.png ')} /> <Image source ={require( '/react-native /img /favicon.png ')} /> <Image source ={require( '/react-native /img /favicon.png ')} /> </ScrollView > ); } } AppRegistry.registerComponent( 'AwesomeProject' , () => IScrolledDownAndWhatHappenedNextShockedMe);
ScrollViews
通过配置pagingEnabled
属性支持滑动切换页面。
FlatList
高性能的列表组件,支持下面这些常用的功能:
完全跨平台
支持水平布局模式
行组件显示或隐藏时可配置回掉事件
支持单独的头部组件
支持单独的尾部组件
支持自定义行间分割线
支持上拉加载
支持跳转到指定行
FlatList
组件有两必定义属性data
和renderItem
。data
是列表的源数据。renderItem
从源数据取一项用于定义好格式的组件渲染。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 import React, { Component } from 'react' ;import { AppRegistry, FlatList, StyleSheet, Text, View } from 'react-native' ;export default class FlatListBasics extends Component { render ( ) { return ( <View style ={styles.container} > <FlatList data ={[ {key: 'Devin '}, {key: 'Jackson '}, {key: 'James '}, {key: 'Joel '}, {key: 'John '}, {key: 'Jillian '}, {key: 'Jimmy '}, {key: 'Julie '}, ]} renderItem ={({item}) => <Text style ={styles.item} > {item.key}</Text > } /> </View > ); } } const styles = StyleSheet.create({ container : { flex : 1 , paddingTop : 22 }, item : { padding : 10 , fontSize : 18 , height : 44 , }, }) AppRegistry.registerComponent('AwesomeProject' , () => FlatListBasics);
高性能的分组(section)列表组件,支持下面这些常用的功能:
完全跨平台
支持水平布局模式
行组件显示或隐藏时可配置回调事件
支持单独头部组件
支持单独尾部组件
支持自定义行间分隔线
支持下拉刷新
支持上拉刷新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import React, { Component } from 'react' ;import { AppRegistry, SectionList, StyleSheet, Text, View } from 'react-native' ;export default class SectionListBasics extends Component { render ( ) { return ( <View style ={styles.container} > <SectionList sections ={[ {title: 'D ', data: ['Devin ']}, {title: 'J ', data: ['Jackson ', 'James ', 'Jillian ', 'Jimmy ', 'Joel ', 'John ', 'Julie ']}, ]} renderItem ={({item}) => <Text style ={styles.item} > {item}</Text > } renderSectionHeader={({section}) => <Text style ={styles.sectionHeader} > {section.title}</Text > } keyExtractor={(item, index) => index} /> </View > ); } } const styles = StyleSheet.create({ container : { flex : 1 , paddingTop : 22 }, sectionHeader : { paddingTop : 2 , paddingLeft : 10 , paddingRight : 10 , paddingBottom : 2 , fontSize : 14 , fontWeight : 'bold' , backgroundColor : 'rgba(247,247,247,1.0)' , }, item : { padding : 10 , fontSize : 18 , height : 44 , }, }) AppRegistry.registerComponent('AwesomeProject' , () => SectionListBasics);
SectionList
用于需要分组展示的数据。
View
是React Native中最基础的组件。它通常用于界面的布局(flexbox
,style
),和绑定touch
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class ViewColoredBoxesWithText extends Component { render ( ) { return ( <View style ={{ flexDirection: 'row ', height: 100 , padding: 20 , }}> <View style ={{backgroundColor: 'blue ', flex: 0.3 }} /> <View style ={{backgroundColor: 'red ', flex: 0.5 }} /> <Text > Hello World!</Text > </View > ); } }
StyleSheet
是对CSS的StyleSheets 的抽象。它用于创建样式规则赋予一个变量分配给节点上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const styles = StyleSheet.create({ container : { borderRadius : 4 , borderWidth : 0.5 , borderColor : '#d6d7da' , }, title : { fontSize : 19 , fontWeight : 'bold' , }, activeTitle : { color : 'red' , }, }); <View style ={styles.container} > <Text style ={[styles.title, this.props.isActive && styles.activeTitle ]} /> </View >
Button
按钮的基础组件能够很好的在各个平台上展示,支持有限的自定义。
1 2 3 4 5 6 7 8 9 import { Button } from 'react-native' ;... <Button onPress={onPressLearnMore} title="Learn More" color="#841584" accessibilityLabel="Learn more about this purple button" />
onPress 当用户触摸时触发方法。
title 按钮中展示的文字。
accessibilityLabel 无障碍显示的文字。
color 设置iOS文本颜色,设置Android背景颜色。
disabled 如果为true,则组件无法点击。
testID 用于端对端测试
Picker
选择器。
1 2 3 4 5 6 <Picker selectedValue={this .state.language} onValueChange={(itemValue, itemIndex ) => this .setState({language : itemValue})}> <Picker.Item label ="Java" value ="java" /> <Picker.Item label ="JavaScript" value ="js" /> </Picker>
onValueChange 当数据变化时触发的方法。这个方法有两个参数
itemValue 选中的item的值。
itemPosition 被选中item的序号
selectedValue 默认选中的item。
mode 选择器的模式。有两种:dialog 和 dropdown 默认是 dialog 。(Android)
WebView
渲染web页面
1 2 3 4 5 6 7 8 9 10 11 12 13 import React, { Component } from 'react' ;import { WebView } from 'react-native' ;class MyWeb extends Component { render ( ) { return ( <WebView source ={{uri: 'https: //github.com /facebook /react-native '}} style ={{marginTop: 20 }} /> ); } }
source 加载静态的 html 或 uri在WebView中。
style 设置组件样式。
iOS组件和API AlertIOS
创建iOS消息提示框。
1 2 3 4 5 6 7 8 9 10 AlertIOS.alert( 'Sync Complete' , 'All your data are belong to us.' ); AlertIOS.prompt( 'Enter a value' , null , text => console .log("You entered " +text) );
DatePickerIOS
iOS平台上选中日期和时间组件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import React, { Component } from 'react' import { DatePickerIOS, View, StyleSheet, } from 'react-native' export default class App extends Component { constructor (props ) { super (props); this .state = { chosenDate : new Date () }; this .setDate = this .setDate.bind(this ); } setDate (newDate ) { this .setState({chosenDate : newDate}) } render ( ) { return ( <View style ={styles.container} > <DatePickerIOS date ={this.state.chosenDate} onDateChange ={this.setDate} /> </View > ) } } const styles = StyleSheet.create({ container : { flex : 1 , justifyContent : 'center' }, })
这个组件上你必须定义onDateChang
回调方法和date
初始化数据。
Android组件 DatePickerAndroid
使用标准的Android日期选择器。
1 2 3 4 5 6 7 8 9 10 11 12 try { const {action, year, month, day} = await DatePickerAndroid.open({ date : new Date (2020 , 4 , 25 ) }); if (action !== DatePickerAndroid.dismissedAction) { } } catch ({code, message}) { console .warn('Cannot open date picker' , message); }
TimePickerAndroid
使用标准的Android时间选中器。
1 2 3 4 5 6 7 8 9 10 11 12 try { const {action, hour, minute} = await TimePickerAndroid.open({ hour : 14 , minute : 0 , is24Hour : false , }); if (action !== TimePickerAndroid.dismissedAction) { } } catch ({code, message}) { console .warn('Cannot open time picker' , message); }
ViewPagerAndroid
容器运行左右翻动子视图。每个子视图是独立且会沾满ViewPagerAndroid
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 render: function ( ) { return ( <ViewPagerAndroid style ={styles.viewPager} initialPage ={0} > <View style ={styles.pageStyle} key ="1" > <Text > First page</Text > </View > <View style ={styles.pageStyle} key ="2" > <Text > Second page</Text > </View > </ViewPagerAndroid > ); } ... var styles = { ... viewPager : { flex : 1 }, pageStyle : { alignItems : 'center' , padding : 20 , } }
参考 https://facebook.github.io/react-native/docs/getting-started.html