React-Native入门教程
Table of Contents
props(属性)
大部分组件在创建的时候, 就可以使用各种参数来进行定制. 这些参数就称为 props
.
例如, 在创建图片时:
import React, { Component } from 'react'; import { Image } from 'react-native'; export default class Bananas extends Component { render() { let pic = { uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg' }; return ( <Image source={pic} style={{width: 193, height: 110}} /> ); } }
这边, 使用名为 source
的props来指定图片的地址, 使用名为 style
的props来控制尺寸.
state(状态)
props
一旦被指定, 在该组件的生命周期中就不再改变. 如果有组件继续了该组件, 则可以在子组件中使用 state
来改变.
一般做法: 子组件在 constructor()
中初始化 state
, 在需要修改时使用 setState()
.
如: 要制作一段闪烁的文字. 文字内容在组件创建时被指定, 所以文字内容应该是一个 prop
, 而文字的显示或隐藏状态(快速显隐切换可产生闪烁效果)是随时间变化的, 因此这个状态应该写到 state
中.
import React, { Component } from 'react'; import { Text, View } from 'react-native'; class Blink extends Component { constructor(props) { super(props); this.state = { showText: true }; // 每1s对showText状态取反 setInterval(() => { this.setState(previousState => { return { showText: !previousState.showText }; }); }, 1000); } render () { // 根据showText的值来决定是否显示text内容 let display = this.state.showText ? this.props.text : ' '; return ( <Text>{display}</Text> ); } } export default class BlinkApp extends Component { render() { return ( <View> <Blink text='I love to blink' /> <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> ); } }
这只是示例. state
使用的典型场景是在接收到服务器返回的新数据, 或在用户输入数据之后.
style(样式)
所有核心组件都接受名为 style
的属性.
在实际开发的时候, 样式会很复杂. 建议使用 StyleSheet.create
来集中定义组件的样式. 如:
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);
高度与宽度
指定宽高
组件的高度与宽度决定了它在屏幕上显示的尺寸. 给组件设定尺寸的方式是在样式中指定 width
和 height
. React Native中尺寸没有单位, 表示的是与设备像素密度无关的逻辑像素点.
import React, { Component } from 'react'; import { AppRegistry, View } from 'react-native'; class FixedDimensionsBasics extends Component { render() { return ( <View> <View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} /> <View style={{width: 100, height: 100, backgroundColor: 'skyblue'}} /> <View style={{width: 150, height: 150, backgroundColor: 'steelblue'}} /> </View> ); } }; // 注册应用(registerComponent)后才能正确渲染 // 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册 AppRegistry.registerComponent('AwesomeProject', () => FixedDimensionsBasics);
弹性宽高(flex)
flex
表示在可利用的空间中动态扩张或收缩. 一般会使用 flex:1
来指定某个组件扩张以撑满所有剩余的空间.
如果有多个并列的子组件使用了 flex:1
, 则这些子组件会平分父容器中的剩余空间.
组件能撑满剩余空间的前提是其父容器的尺寸不为0. 如果父容器既没有固定的 width
和 height
, 也没有设定 flex
, 则父容器的尺寸为0. 这样的话, 即使子组件使用了 flex
也不会起效果.
import React, { Component } from 'react'; import { AppRegistry, View } from 'react-native'; class FlexDimensionsBasics extends Component { render() { return ( // 试试去掉父View中的`flex: 1`。 // 则父View不再具有尺寸,因此子组件也无法再撑开。 // 然后再用`height: 300`来代替父View的`flex: 1`试试看? <View style={{flex: 1}}> <View style={{flex: 1, backgroundColor: 'powderblue'}} /> <View style={{flex: 2, backgroundColor: 'skyblue'}} /> <View style={{flex: 3, backgroundColor: 'steelblue'}} /> </View> ); } }; AppRegistry.registerComponent('AwesomeProject', () => FlexDimensionsBasics);
使用Flexbox布局
在React Native中, 使用flexbox规则来指定某个组件的子元素的布局. flexbox可以在不同屏幕尺寸上提供一致的布局结构.
flexDirection
在组件的 style
中指定 flexDirection
可以决定布局的主轴. 子元素可以沿着水平排列(row), 也可以垂直排列(column), 默认为column.
import React, { Component } from 'react'; import { AppRegistry, View } from 'react-native'; class FlexDirectionBasics extends Component { render() { return ( // 尝试把`flexDirection`改为`column`看看 <View style={{flex: 1, flexDirection: 'row'}}> <View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} /> <View style={{width: 50, height: 50, backgroundColor: 'skyblue'}} /> <View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} /> </View> ); } }; AppRegistry.registerComponent('AwesomeProject', () => FlexDirectionBasics);
justifyContent
在组件中的 style
中指定 justifyContent
可以决定子元素沿着主轴的排列方式. 如, 左对齐, 右对齐, 还是居中, 等等, 都是由它来指定.
import React, { Component } from 'react'; import { AppRegistry, View } from 'react-native'; class JustifyContentBasics extends Component { render() { return ( // 尝试把`justifyContent`改为`center`看看 // 尝试把`flexDirection`改为`row`看看 <View style={{ flex: 1, flexDirection: 'column', justifyContent: 'space-between', }}> <View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} /> <View style={{width: 50, height: 50, backgroundColor: 'skyblue'}} /> <View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} /> </View> ); } }; AppRegistry.registerComponent('AwesomeProject', () => JustifyContentBasics);
alignItems
在组件的 style
中指定 alignItems
可以决定其子元素沿着次轴的排列方式.
import React, { Component } from 'react'; import { AppRegistry, View } from 'react-native'; class AlignItemsBasics extends Component { render() { return ( // 尝试把`alignItems`改为`flex-start`看看 // 尝试把`justifyContent`改为`flex-end`看看 // 尝试把`flexDirection`改为`row`看看 <View style={{ flex: 1, flexDirection: 'column', justifyContent: 'center', alignItems: 'center', }}> <View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} /> <View style={{width: 50, height: 50, backgroundColor: 'skyblue'}} /> <View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} /> </View> ); } }; AppRegistry.registerComponent('AwesomeProject', () => AlignItemsBasics);
处理文本输入
TextInput
是一个允许用户输入文本的基础组件. 它有一个名为 onChangeText
属性, 此属性接受一个函数, 而此函数会在文本变化时被调用; 有一个名为 onSubmitEditing
的属性, 在文件被提交后被调用.
把输入的单词转换成🍕:
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> ); } }
(ScrollView)滚动视图
ScrollView
是一个通用的可滚动的容器, 可以在其中放入多个组件和视图, 而且这些组件并不需要是同类型的. ScrollView
可以水平或者垂直滚动.
import React, { Component } from 'react'; import{ ScrollView, Image, Text, View } from 'react-native' export default class IScrolledDownAndWhatHappenedNextShockedMe extends Component { render() { return( <ScrollView> <Text style={{fontSize:96}}>Scroll me plz</Text> <Image source={require('./img/favicon.png')} /> <Image source={require('./img/favicon.png')} /> <Image source={require('./img/favicon.png')} /> <Image source={require('./img/favicon.png')} /> <Image source={require('./img/favicon.png')} /> <Text style={{fontSize:96}}>If you like</Text> <Image source={require('./img/favicon.png')} /> <Image source={require('./img/favicon.png')} /> <Image source={require('./img/favicon.png')} /> <Image source={require('./img/favicon.png')} /> <Image source={require('./img/favicon.png')} /> <Text style={{fontSize:96}}>Scrolling down</Text> <Image source={require('./img/favicon.png')} /> <Image source={require('./img/favicon.png')} /> <Image source={require('./img/favicon.png')} /> <Image source={require('./img/favicon.png')} /> <Image source={require('./img/favicon.png')} /> <Text style={{fontSize:96}}>What's the best</Text> <Image source={require('./img/favicon.png')} /> <Image source={require('./img/favicon.png')} /> <Image source={require('./img/favicon.png')} /> <Image source={require('./img/favicon.png')} /> <Image source={require('./img/favicon.png')} /> <Text style={{fontSize:96}}>Framework around?</Text> <Image source={require('./img/favicon.png')} /> <Image source={require('./img/favicon.png')} /> <Image source={require('./img/favicon.png')} /> <Image source={require('./img/favicon.png')} /> <Image source={require('./img/favicon.png')} /> <Text style={{fontSize:80}}>React Native</Text> </ScrollView> ); } }
ScrollView
会将内部所有组件都渲染. 如果如果要显示较长的滚动列表, 应该使用功能差不多, 但性能更好的长列表.
长列表
React Native中有几个长列表, 一般使用 FlatList
或 SectionList
.
FlatList
用于显示一个垂直的滚动列表, 内部元素格式相同, 元素个数可增删. 它优先渲染屏幕上可见的元素.
FlatList
有两个必须的属性: data
和 renderItem
. data
是列表的数据源, renderItem
则从数据源中逐个解析数据, 然后返回一个设定好格式的组件来渲染.
import React, { Component } from 'react'; import { 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, }, })
SectionList
适用于渲染一组需要分组的数据, 也许还带有分组标签.
import React, { Component } from 'react'; import { 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>} /> </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, }, })
网络
一般移动应用都要从Server中获取数据. 我们可能要给某个REST API发起POST请求, 以提交用户数据; 也可能从Server上获取一些数据.
fetch
如果学过 XMLHttpRequest(ajax)
, 则 fetch
用起来比较容易上手.
发起网络请求
从指定地址获取内容:
fetch('https://mywebsite.com/mydata.json')
fetch()
还有可选的第二个参数, 用来定制HTTP请求一些参数. 如:
fetch('https://mywebsite.com/endpoint/', { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify({ firstParam: 'yourValue', secondParam: 'yourOtherValue', }) })
提交数据的格式取决于 headers
中的 Content-Type
. Content-Type
有多种, 对应的 body
的格式也有多种. 使用哪种, 协商清楚就好. 比如用网页表示的形式传递:
fetch('https://mywebsite.com/endpoint/', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: 'key1=value1&key2=value2' })
处理服务器的响应数据
getMoviesFromApiAsync() { return fetch('https://facebook.github.io/react-native/movies.json') .then((response) => response.json()) .then((responseJson) => { return responseJson.movies; }) .catch((error) => { console.error(error); }); }
还可以使用ES7标准中的 async/await
语法:
// 注意这个方法前面有async关键字 async getMoviesFromApi() { try { // 注意这里的await语句,其所在的函数必须有async关键字声明 let response = await fetch('https://facebook.github.io/react-native/movies.json'); let responseJson = await response.json(); return responseJson.movies; } catch(error) { console.error(error); } }
默认情况下, iOS会阻止所有非https请求. 如果非要使用http协议, 参考文档https://segmentfault.com/a/1190000002933776.
AJAX
此处不介绍.
WebSocket
React Native还支持 WebSocket
.
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); };
Navigation
React Native中有多种导航组件, 社区主推 react-navigation
.
安装
yarn add react-navigation
创建两个页面
创建有两个页面(Main和Profile)的应用:
import { StackNavigator, } from 'react-navigation'; const App = StackNavigator({ Main: {screen: MainScreen}, Profile: {screen: ProfileScreen}, });
其中, 每个 screen
组件都可以单独设置导航选项, 如导航头的标题, 页面的跳转等:
class MainScreen extends React.Component { static navigationOptions = { title: 'Welcome', }; render() { const { navigate } = this.props.navigation; return ( <Button title="Go to Jane's profile" onPress={() => navigate('Profile', { name: 'Jane' }); } /> ); } }
集成到现有原生应用
在原生应用程序的基础上, 加上React Native写的内容. 值得学习.
Generated by Emacs 25.x(Org mode 8.x)
Copyright © 2014 - Pinvon - Powered by EGO