常用组件
文本输入 TextInput
导航 Navigator
View
Text
ScrollView
Image
ListView
TouchableHighlight
TouchableNativeFeedback
TouchableOpacity
TouchableWithoutFeedback
ViewPagerAndroid
常用引入包
Redux来统一管理数据流
网络库 frisbee、axios
防止定时器clear时出bug react-timer-mixin (ES5)
持久数据 Immutable
reselect
安装
python2
npm 包管理
node 环境
react-native-cli 脚手架
Nuclide FaceBook的IDE
1 2 3 4 5 6 7 8 9 10 11 12 13
| npm 替换淘宝镜像源 1.通过config命令 npm config set registry https://registry.npm.taobao.org npm info underscore (如果上面配置正确这个命令会有字符串response) 2.命令行指定 npm --registry https://registry.npm.taobao.org info underscore 3.编辑 ~/.npmrc 加入下面内容 registry = https://registry.npm.taobao.org
|
自定义组件
Component
1 2 3 4 5 6 7 8 9 10 11 12 13
| 函数 render()、construtor(props) class Greeting extends Component { render() { return ( <Text>Hello {this.props.name}!</Text> ); } } =========== <Greeting name='文字'/>
|
弹性Flex 宽高
flex可以使其在可利用的空间中动态地扩张或收缩
flex:1来指定某个组件扩张以撑满所有剩余的空间
使用Flexbox布局
flexDirection 指定主体方向、容器属性
1
| flexDirection: 'row' 水平 、默认竖直 column
|
justifyContent 指定子元素排列方式、容器属性
1
| flex-start、center、flex-end、space-around以及space-between
|
alignItems 子元素沿着次轴方向、容器属性
1
| flex-start、center、flex-end以及stretch
|
处理文本输入
基础组件 TextInput
属性 onChangeText 接受一个函数
1
| onChangeText={(text) => this.setState({text})}
|
属性 onSubmitEditing 会在文本被提交后(用户按下软键盘上的提交键)调用。
默认垂直。 水平horizontal
ListView
ListView组件必须的两个属性是dataSource和renderRow.
dataSource是列表的数据源
renderRow则逐个解析数据源中的数据
rowHasChanged函数也是ListView的必需属性、判断某行数据是否变化了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| constructor(props) { super(props); const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); this.state = { dataSource: ds.cloneWithRows([ 'John', 'Joel', 'James', 'Jimmy', 'Jackson', 'Jillian', 'Julie', 'Devin' ]) }; } ============ <View style={{flex: 1, paddingTop: 22}}> <ListView dataSource={this.state.dataSource} renderRow={(rowData) => <Text>{rowData}</Text>} /> </View>
|
网络
react-native 内置了XMLHttpRequest API
支持 WebSocket
使用Fetch
1 2 3 4 5 6 7 8 9 10 11 12 13
| 请求、 Fetch 方法会返回一个Promise fetch('https://mywebsite.com/endpoint/', { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify({ firstParam: 'yourValue', secondParam: 'yourOtherValue', }) })
|
处理服务器的响应数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| getMoviesFromApiAsync() { return fetch('http://facebook.github.io/react-native/movies.json') .then((response) => response.json()) .then((responseJson) => { return responseJson.movies; }) .catch((error) => { console.error(error); }); } =============ES7 // 注意这个方法前面有async关键字 async getMoviesFromApi() { try { // 注意这里的await语句,其所在的函数必须有async关键字声明 let response = await fetch('http://facebook.github.io/react-native/movies.json'); let responseJson = await response.json(); return responseJson.movies; } catch(error) { console.error(error); } }
|
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); };
|
Navigator
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
| import React, { Component } from 'react'; import { AppRegistry, Navigator, Text, View } from 'react-native'; import MyScene from './MyScene'; class SimpleNavigationApp extends Component { render() { return ( <Navigator initialRoute={{ title: 'My Initial Scene', index: 0 }} renderScene={(route, navigator) => <MyScene title={route.title} // Function to call when a new scene should be displayed onForward={ () => { const nextIndex = route.index + 1; navigator.push({ title: 'Scene ' + nextIndex, index: nextIndex, }); }} // Function to call to go back to the previous scene onBack={() => { if (route.index > 0) { navigator.pop(); } }} /> } /> ) } } AppRegistry.registerComponent('SimpleNavigationApp', () => SimpleNavigationApp); AppRegistry.registerComponent('SimpleNavigationApp', () => SimpleNavigationApp);
|
跳转
1 2 3 4 5 6
| navigator.push({ title: 'Next Scene', index: 1, }); navigator.pop();
|
颜色格式支持
1 2 3 4 5 6 7 8 9 10 11
| '#f0f' (#rgb) '#f0fc' (#rgba) '#ff00ff' (#rrggbb) '#ff00ff00' (#rrggbbaa) 'rgb(255, 255, 255)' 'rgba(255, 255, 255, 1.0)' 'hsl(360, 100%, 100%)' 'hsla(360, 100%, 100%, 1.0)' 'transparent' 'red' 0xff00ff00 (0xrrggbbaa)
|
图片
静态图片资源
1 2 3 4 5 6
| <Image source={require('./my-icon.png')} /> Packager就会去这个组件所在的文件夹下查找my-icon.png。并且,如果你有my-icon.ios.png和my-icon.android.png,Packager就会根据平台而选择不同的文件。 你还可以使用@2x,@3x这样的文件名后缀,来为不同的屏幕精度提供图片。
|
使用混合App的图片资源
1
| <Image source={{uri: 'app_icon'}} style={{width: 40, height: 40}} />
|
网络图片
1
| <Image source={{uri: 'https://facebook.github.io/react/img/logo_og.png'}} style={{width: 400, height: 400}} />
|
本地文件系统中的图片
1 2 3 4
| 详情见,Images.xcassets require('image!logo')
|
资源属性是一个对象Object
1 2 3 4 5
| <Image source={{uri: 'something.jpg'}} /> 裁剪 {uri: ..., crop: {left: 10, top: 50, width: 20, height: 40}}ß
|
实现背景
1 2 3 4 5
| return ( <Image source={...}> <Text>Inside</Text> </Image> );
|
圆角
1 2 3 4 5 6 7
| iOS暂不支持 borderTopLeftRadius borderTopRightRadius borderBottomLeftRadius borderBottomRightRadius
|
处理触摸事件
可点击控件,Touchable开头
- TouchableHighlight来制作按钮或者链接
- Android上还可以使用TouchableNativeFeedback,类似墨水涟漪的视觉效果
- TouchableOpacity会在用户手指按下时降低按钮的透明度,而不会改变背景的颜色。
- TouchableWithoutFeedback, 不显示任何视觉反馈。
1 2 3 4 5 6 7 8 9 10 11 12 13
| class MyButton extends Component { _onPressButton() { console.log("You tapped the button!"); } render() { return ( <TouchableHighlight onPress={this._onPressButton}> <Text>Button</Text> </TouchableHighlight> ); } }
|
长按
在列表中上下滑动和在视图上左右滑动
1
| ScrollView可以在垂直或水平方向滚动,还可以配置pagingEnabled属性来让用户整屏整屏的滑动。此外,水平方向的滑动还可以使用Android上的ViewPagerAndroid 组件。
|
双指缩放
1
| 在ScrollView中只放置一个组件,设置maximumZoomScale和minimumZoomScale
|
动画
Animated
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
| class Playground extends React.Component { constructor(props: any) { super(props); this.state = { bounceValue: new Animated.Value(0), }; } render(): ReactElement { return ( <Animated.Image // 可选的基本组件类型: Image, Text, View source={{uri: 'http://i.imgur.com/XMKOH81.jpg'}} style={{ flex: 1, transform: [ // `transform`是一个有序数组(动画按顺序执行) {scale: this.state.bounceValue}, // 将`bounceValue`赋值给 `scale` ] }} /> ); } componentDidMount() { this.state.bounceValue.setValue(1.5); // 设置一个较大的初始值 Animated.spring( // 可选的基本动画类型: spring, decay, timing this.state.bounceValue, // 将`bounceValue`值动画化 { toValue: 0.8, // 将其值以动画的形式改到一个较小值 friction: 1, // Bouncier spring } ).start(); // 开始执行动画 } } spring: 基础的单次弹跳物理模型,符合Origami设计标准 friction: 摩擦力,默认为7. tension: 张力,默认40。 decay: 以一个初始速度开始并且逐渐减慢停止。 velocity: 起始速度,必填参数。 deceleration: 速度衰减比例,默认为0.997。 timing: 从时间范围映射到渐变的值。 duration: 动画持续的时间(单位是毫秒),默认为500。 easing:一个用于定义曲线的渐变函数。阅读Easing模块可以找到许多预定义的函数。iOS默认为Easing.inOut(Easing.ease)。 delay: 在一段时间之后开始动画(单位是毫秒),默认为0。
|
组合动画
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| parallel(同时执行)、sequence(顺序执行)、stagger和delay来组合使用。 Animated.sequence([ // 首先执行decay动画,结束后同时执行spring和twirl动画 Animated.decay(position, { // 滑行一段距离后停止 velocity: {x: gestureState.vx, y: gestureState.vy}, // 根据用户的手势设置速度 deceleration: 0.997, }), Animated.parallel([ // 在decay之后并行执行: Animated.spring(position, { toValue: {x: 0, y: 0} // 返回到起始点开始 }), Animated.timing(twirl, { // 同时开始旋转 toValue: 360, }), ]), ]).start(); // 执行这一整套动画序列
|
插值 interpolate
1 2 3 4 5 6 7 8 9 10 11
| value.interpolate({ inputRange: [0, 1], outputRange: [0, 100], }); 支持多区间定义 value.interpolate({ inputRange: [-300, -100, 0, 100, 101], outputRange: [300, 0, 1, 0, 0], });
|
跟踪动态值
1 2 3 4 5 6 7
| Animated.spring(follower, {toValue: leader}).start(); Animated.timing(opacity, { toValue: pan.x.interpolate({ inputRange: [0, 300], outputRange: [1, 0], }), }).start();
|
LayoutAnimation 允许你在全局范围内创建和更新动画
1 2 3
| 如果要在Android上使用LayoutAnimation,那么目前还需要在UIManager中启用: UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true);
|
setNativeProps 方法可以使我们直接修改基于原生视图的组件的属性,而不需要使用setState来重新渲染整个组件树。
定时器
setTimeout, clearTimeout
setInterval, clearInterval
setImmediate, clearImmediate
requestAnimationFrame, cancelAnimationFrame
TimerMixin(ES5)
1 2 3 4 5 6 7 8 9 10 11 12 13
| 这个库并没有跟着React Native一起发布。你需要在项目文件夹下输入npm i react-timer-mixin --save来单独安装它。 var TimerMixin = require('react-timer-mixin'); var Component = React.createClass({ mixins: [TimerMixin], componentDidMount: function() { this.setTimeout( () => { console.log('这样我就不会导致内存泄露!'); }, 500 ); } });
|
ES6代替
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import React,{ Component } from 'react'; export default class Hello extends Component { componentDidMount() { this.timer = setTimeout( () => { console.log('把一个定时器的引用挂在this上'); }, 500 ); } componentWillUnmount() { // 如果存在this.timer,则使用clearTimeout清空。 // 如果你使用多个timer,那么用多个变量,或者用个数组来保存引用,然后逐个clear this.timer && clearTimeout(this.timer); } };
|