RN学习笔记

来源:互联网 发布:淘宝助手ipad版 编辑:程序博客网 时间:2024/06/06 02:58
react-native 学习
环境安装:http://reactnative.cn/docs/0.48/getting-started.html#content
更新npm:
建议使用淘宝镜像:$ npm i -g npm --registry=https://registry.npm.taobao.org
创建并运行项目:

react-native init AwesomeProject
cd AwesomeProjectreact-native run-ios
ps:可以使用--version参数(注意是个杠)创建指定版本的项目。例如react-native init MyApp --version 0.44.3。
0.45及以上版本需要下载boost库编译 —》查看http://bbs.reactnative.cn/topic/4301/ios-rn-0-45%E4%BB%A5%E4%B8%8A%E7%89%88%E6%9C%AC%E6%89%80%E9%9C%80%E7%9A%84%E7%AC%AC%E4%B8%89%E6%96%B9%E7%BC%96%E8%AF%91%E5%BA%93-boost%E7%AD%89
在模拟器中,commond+R是重新加载
属性(props)的使用
//自定义的控件
class Greeting extends Component {  render() {    return (      <Text>Hello {this.props.name}!</Text>    );  }}
//调用自定义控件class LotsOfGreetings extends Component {  render() {    return (      <View style={{alignItems: 'center'}}>        <Greeting name='Rexxar' />        <Greeting name='Jaina' />        <Greeting name='Valeera' />      </View>    );  }}
props是在父组件中指定,而且一经指定,在被指定的组件的生命周期中则不再改变
对于需要改变的数据,我们需要使用state
一般在 constructor中初始化 state,在需要修改时调用setState方法
组件的生命周期。

组件的生命周期分成三个状态:

Mounting:已插入真实 DOM

Updating:正在被重新渲染

Unmounting:已移出真实 DOM

React 为每个状态都提供了两种处理函数,will函数在进入状态之前调用,did函数在进入状态之后调用,三种状态共计五种处理函数。

componentWillMount():只会在装载之前调用一次,在 render之前调用,你可以在这个方法里面调用setState改变状态,并且不会导致额外调用一次 render

componentDidMount():只会在装载完成之后调用一次,在 render之后调用,从这里开始可以通过ReactDOM.findDOMNode(this)获取到组件的 DOM 节点。

componentWillUpdate(object nextProps, object nextState)

componentDidUpdate(object prevProps, object prevState)

componentWillUnmount():卸载组件触发

此外,React还提供两种特殊状态的处理函数。

componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用

shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用

特别注意:以下这些方法不会在首次 render组件的周期调用

componentWillReceiveProps

shouldComponentUpdate

componentWillUpdate

componentDidUpdate

创建组件实例并插入DOM时,会调用:
  • constructor() //初始化 state 的位置,如果不需要初始化 state 并且不绑定方法的话,则不用实现该构造函数,注意state不会随着任何props更新而更新,所以不要这样写:
  • constructor(props) {
  • super(props); this.state = { color: props.initialColor };}
  • componentWillMount()
//在插入 DOM 前调用,官方建议用 constructor 代替
  • render() //在调用时,应该检查this.propsthis.state,并返回一个作出反应的元素。此元素可以是本机DOM组件的表示形式,也可以是<div />您自己定义的另一个复合组件。

    您也可以返回nullfalse指示您不想要任何呈现。当返回null或者falseReactDOM.findDOMNode(this)将返回null

    如果shouldComponentUpdate()返回false,则render()不会被调用

  • componentDidMount()
//在插入 DOM 后调用,在此方法中设置/更新 state都会重新渲染组件,如果需要从远程端点加载数据,这是实例化网络请求的好地方
更新 state 或者 props,当重新渲染组件的时候,会调用:
  • componentWillReceiveProps()
//接收新的 props 前会调用,要注意的是,就算 props 没有发生改变,这个方法也可能会触发,所以请确保比较当前值和下一个值,然后在执行后面的处理。
//在 props初始化的时候不会调用这个方法,只有在更新state 的时候才會调用,调用this.setState一般不会触发该方法
  • shouldComponentUpdate()
//默认返回 true,此方法在接收新的 state 或者 props 前被调用。当 render()或者forceUpdate被调用的时候并不会调用此方法。
//返回 false 并不会阻止组件在state 改变时候的重新渲染,但是componentWillUpdate()render()componentDidUpdate()将不会被调用,所以可以通过比较this.propsnextPropsthis.state与nextState来告诉组件跳过更新。
//返回 false可能导致组件的重新渲染。
  • componentWillUpdate()
这个方法会在接收到新的 state 或者 props 前调用,初始化渲染的时候不会调用该方法。
不能在这个方法里面调用 this.setState(),如果需要更新 state 来响应 props 的改变,用componentWillReceiveProps代替。
shouldComponentUpdate()返回 false 的时候,这个方法不会被调用。
  • render()
  • componentDidUpdate()
该方法在更新后会被立即调用,同样不会在初始化渲染的时候调用。
这个方法也是操作 DOM 组件的好地方,比如可以比较 前后的props来判断是否需要进行网络请求。
从 DOM 删除组件的时候,会调用:
  • componentWillUnmount()
在组件销魂和删除前会调用该方法,
在此方法中执行任何必要的清理,例如使定时器无效,取消网络请求或清除在componentDidMount创建的对象

每个组件还提供了一些其他API:

  • setState()
setState(updater, [callback])
第一个参数是(prevState, props) => stateChange

prevState是对以前状态的引用。不应该直接改变它,而是应该根据prevState和props构建一个新对象来表示更改。例如,

假设我们想增加一个状态值props.state

this.setState((prevState, props) => {  return {counter: prevState.counter + props.step};});
第二个参数是一个可选的回调函数,官方建议用componentDidUpdate代替它的使用。
如果下一个 state 仅依赖上一个 state,官方建议如下形式使用:
this.setState((prevState) => {
return {counter: prevState.quantity + 1};});

  • forceUpdate()
在大多数情况下,应该尽量避免使用这个方法,并且 this.state 和 this.props的读操作应该只在render()中发生。

类属性

  • defaultProps
用设置默认 的props,但如果设置好的 props 为 null,则默认设置不会生效。
e.g.:
class CustomButton extends React.Component { // ...}CustomButton.defaultProps = { color: 'blue'};

如果props.color没有提供,它将默认设置为'blue'

  render() {    return <CustomButton /> ; // props.color will be set to blue  }

如果props.color设置为null,它将保持为空:

  render() {    return <CustomButton color={null} /> ; // props.color will remain null  }

  • displayName

实例属性

  • props

  • state
用户定义、JavaScript对象,用于包含特定的组件数据,这些数据会发生变化。
如果要改变它,不要直接 this.state 的方式,而是用 setState()

弹性(Flex)宽高

在组件样式中使用flex可以使其在可利用的空间中动态地扩张或收缩。一般而言我们会使用flex:1来指定某个组件扩张以撑满所有剩余的空间。如果有多个并列的子组件使用了flex:1,则这些子组件会平分父容器中剩余的空间。如果这些并列的子组件的flex值不一样,则谁的值更大,谁占据剩余空间的比例就更大(即占据剩余空间的比等于并列组件间flex值的比)。
ps: flexDirection标签控制 flex 拉伸方向(控制主轴方向),默认是column竖直轴(默认拉伸高度),可以设置成水平轴(row)
justifyContent标签可以控制子组件的排列顺序,分别是:
flex-start:主轴首部
center:主轴中部
flex-end:主轴尾部
space-around:组件在主轴方向按固定间距排列(比如每个组件都是左右间距50或者每个组件上下间距都是50)
space-between:主轴方向等间距排列。

Align Items

在组件的style中指定alignItems可以决定其子元素沿着次轴
对应的这些可选项有:flex-startcenterflex-end以及stretch
注意:要使stretch选项生效的话,子元素在次轴方向上不能有固定的尺寸
style 賦值
e.g.:
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',  },});
后声明的属性会覆盖先声明的同名属性(上面的例子是覆蓋了 color 這個屬性)
所以文本的風格是(:
藍、大
紅、大
藍、大

Textinput
从TextInput里取值这就是目前唯一的做法:订阅它的onChangeText事件来读取用户的输入,即使用onChangeText写入state,然后从this.state中取出值

TextInput在安卓上默认有一个底边框,同时会有一些padding。如果要想使其看起来和iOS上尽量一致,则需要设置padding: 0,同时设置underlineColorAndroid="transparent"来去掉底边框。

又,在安卓上如果设置multiline = {true},文本默认会垂直居中,可设置textAlignVertical: 'top'样式来使其居顶显示。

又又,在安卓上长按选择文本会导致windowSoftInputMode设置变为adjustResize,这样可能导致绝对定位的元素被键盘给顶起来。要解决这一问题你需要在AndroidManifest.xml中明确指定合适的windowSoftInputMode( https://developer.android.com/guide/topics/manifest/activity-element.html )值,或是自己监听事件来处理布局变化

长列表(listview):FlatList或是SectionList。

FlatList:没有组视图

const myListData = [ {key: 'Devin'}, {key: 'Jackson'}, {key: 'James'}, {key: 'Joel'}, {key: 'John'}, {key: 'Jillian'}, {key: 'Jimmy'}, {key: 'Julie'}, ];export default class MyListViewDemo extends Component<{}> { render() { return ( <View style = {styles.container}> <FlatList data = {myListData} renderItem = { ({item}) => <View style = {styles.flesone}> <Image source = {require('./image/test.png')} style = {{alignItems: 'center'}}/> <Text style = {styles.item} >{item.key}</Text> </View> } /> </View> ); }}

SectionList:有组视图
const sectionListData = [{title: {name: 'Jo', age: 20}, data: [ {key: 'Devin'}, {key: 'Jackson'}, {key: 'James'}, {key: 'Joel'}, {key: 'John'}, {key: 'Jillian'}, {key: 'Jimmy'}, {key: 'Julie'}, ]},{title: {name: 'XYF', age: 30}, data: [ {key: 'XYF_SSS'}, {key: 'XYF_Jackson'}, {key: 'XYF_James'}, {key: 'XYF_Joel'}, ]},];export default class MySectionListDemo extends Component<{}> { render() { return ( <View style = {styles.flexone}> <SectionList sections = {sectionListData} renderItem = {({item}) => <Text style = {{color: 'red', fontSize: 20}}> {item.key} </Text> } renderSectionHeader = {({section}) => <Text style = {{fontSize: 30, marginLeft: 100}}> {section.title.name} </Text>} /> </View> ); }}

导航栏:目前主推react-navigation

只针对iOS平台开发,并且想和系统原生外观一致,那么可以选择NavigatorIOS

e.g.:

//只有声明了{ navigation }的才能继续跳转。

const HomeScreen = ({ navigation }) => ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> <Button onPress={() => navigation.navigate('Details’) //跳转到” Details"界面}

title="Go to details" /> </View>);const DetailsScreen = () => ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Details Screen</Text> </View>);//初始化StackNavigator,注册导航栏所在的窗口视图

const RootNavigator = StackNavigator({ Home: { screen: HomeScreen, navigationOptions: {

//导航栏标题 headerTitle: 'Home', }, }, Details: { screen: DetailsScreen, navigationOptions: {

//导航栏标题 headerTitle: 'Details', }, },});export default class MainScreen extends Component<{}> { render() { return ( <RootNavigator /> ); }}

工具栏:

class App extends Component<{}> { render() { return ( <View style={styles.container}> <Text style={styles.welcome}> Welcome to React Native! </Text> <Text style={styles.instructions}> To get started, edit App.js </Text> <Text style={styles.instructions}> {instructions} </Text> </View> ); }}/*标签栏 tabbar 的简单使用*/class MyTabBarItem extends Component<{}> { render(){ var icon = this.props.active ? this.props.selectImage : this.props.normalImage; return ( <Image source={icon} style={{tintColor: this.props.tintColor, width: 25, height: 25}}/> ); }}const SimpleApp = TabNavigator({ Home: { screen: App, navigationOptions: ({navigation}) => ({ tabBarVisible: true, tabBarLabel: '首页', tabBarIcon: ({focused, tintColor})=>( <MyTabBarItem tintColor={tintColor} focused={focused} selectImage= {require('./image/test.png')} normalImage={require('./image/test.png')} /> ), }) }, Detail: { screen: App, navigationOptions: ({navigation}) => ({ tabBarLabel: '消息', tabBarIcon: ({focused, tintColor})=>( <MyTabBarItem tintColor={tintColor} selectImage= {require('./image/test.png')} normalImage={require('./image/test.png')} /> ), }) }, Three: { screen: App, navigationOptions: ({navigation}) => ({ tabBarLabel: '我的', tabBarIcon: ({focused, tintColor})=>( <MyTabBarItem tintColor={tintColor} focused={focused} selectImage= {require('./image/test.png')} normalImage={require('./image/test.png')} /> ), }) }},{ tabBarPosition:'bottom', swipeEnabled:false, animationEnabled:false, lazy:true, tabBarOptions:{ activeTintColor:'red', inactiveTintColor:'black', style:{backgroundColor:'#fff',}, labelStyle: { fontSize: 16, // 文字大小 }, }})export default class MyTabbar extends Component<{}> { render () { return ( <SimpleApp/> ); }}

常用属性:

screen:和导航的功能是一样的,对应界面名称,可以在其他页面通过这个screen传值和跳转。 navigationOptions:配置TabNavigator的一些属性 { title:标题,会同时设置导航条和标签栏的title tabBarVisible:是否隐藏标签栏。默认不隐藏(true) tabBarIcon:设置标签栏的图标。需要给每个都设置 tabBarLabel:设置标签栏的title。推荐 }tabBarPosition:设置tabbar的位置,iOS默认在底部,安卓默认在顶部。(属性值:'top','bottom') swipeEnabled:是否允许在标签之间进行滑动 animationEnabled:是否在更改标签时显示动画 lazy:是否根据需要懒惰呈现标签,而不是提前,意思是在app打开的时候将底部标签栏全部加载,默认false,推荐为true trueinitialRouteName: 设置默认的页面组件 backBehavior:按 back 键是否跳转到第一个Tab(首页), none 为不跳转 tabBarOptions:配置标签栏的一些属性iOS属性 activeTintColor:label和icon的前景色 活跃状态下 activeBackgroundColor:label和icon的背景色 活跃状态下 inactiveTintColor:label和icon的前景色 不活跃状态下 inactiveBackgroundColor:label和icon的背景色 不活跃状态下 showLabel:是否显示label,默认开启 style:tabbar的样式 labelStyle:label的样式安卓属性 activeTintColor:label和icon的前景色 活跃状态下 inactiveTintColor:label和icon的前景色 不活跃状态下 showIcon:是否显示图标,默认关闭 showLabel:是否显示label,默认开启 style:tabbar的样式 labelStyle:label的样式 upperCaseLabel:是否使标签大写,默认为true pressColor:material涟漪效果的颜色(安卓版本需要大于5.0) pressOpacity:按压标签的透明度变化(安卓版本需要小于5.0) scrollEnabled:是否启用可滚动选项卡 tabStyle:tab的样式 indicatorStyle:标签指示器的样式对象(选项卡底部的行)。安卓底部会多出一条线,可以将height设置为0来暂时解决这个问题 labelStyle:label的样式 iconStyle:图标样式

还有DrawerNavigator(抽屉视图/侧栏视图),参考下面详情

详细参考:https://reactnavigation.org/docs/intro/quick-start

属性(个别需要特别注意的)

keyboardType enum("default", 'numeric', 'email-address', "ascii-capable", 'numbers-and-punctuation', 'url', 'number-pad', 'phone-pad', 'name-phone-pad', 'decimal-pad', 'twitter', 'web-search') 

决定弹出的何种软键盘的,譬如numeric(纯数字键盘)。

这些值在所有平台都可用:

  • default
  • numeric
  • email-address
  • phone-pad

returnKeyType enum('done', 'go', 'next', 'search', 'send', 'none', 'previous', 'default', 'emergency-call', 'google', 'join', 'route', 'yahoo') 

决定“确定”按钮显示的内容。在Android上你还可以使用returnKeyLabel来自定义文本。

跨平台

下列这些选项是跨平台可用的:

  • done
  • go
  • next
  • search
  • send

限Android

下列这些选项仅限Android使用:

  • none
  • previous

限iOS

下列这些选项仅限iOS使用:

  • default
  • emergency-call
  • google
  • join
  • route
  • yahoo
加载图片
http://reactnative.cn/docs/0.49/images.html
ps: 在iOS上,每次调整Image组件的宽度或者高度,都需要重新裁剪和缩放原始图片。这个操作开销会非常大,尤其是大的图片。比起直接修改尺寸,更好的方案是使用transform: [{scale}]的样式属性来改变尺寸。比如当你点击一个图片,要将它放大到全屏的时候,就可以使用这个属性

resizeMode的属性:cover(默认),contain(全部展示图片,自动缩放)、stretch(拉伸图片,让宽或者高占满控件)

设置背景色为透明色: backgroundColor: ‘transparent’

各种颜色参数:http://reactnative.cn/docs/0.49/colors.html#content
可点击/长按的组件(点击效果按钮)
  • 一般来说,你可以使用TouchableHighlight来制作按钮或者链接。注意此组件的背景会在用户手指按下时变暗。

  • 在Android上还可以使用TouchableNativeFeedback,它会在用户手指按下时形成类似墨水涟漪的视觉效果。

  • TouchableOpacity会在用户手指按下时降低按钮的透明度,而不会改变背景的颜色。

  • 如果你想在处理点击事件的同时不显示任何视觉反馈,则需要使用TouchableWithoutFeedback。

    e.g.:

    <TouchableHighlight onPress = {() => Alert.alert("测试单击”)}

    onLongPress = {() => Alert.alert("这是长按效果")}>

    <Text>My Test </Text> </TouchableHighlight>

定时器使用
需要注意的是铭记在unmount组件时清除(clearTimeout/clearInterval)所有用到的定时器
直接操作组件setNativeProps的简单使用:http://reactnative.cn/docs/0.49/direct-manipulation.html#content

各种性能影响比如:ListView初始化渲染太慢以及列表过长时滚动性能太差,滑动画面卡顿等的解决方法:http://reactnative.cn/docs/0.49/performance.html#content

升级教程:http://reactnative.cn/docs/0.49/upgrading.html#content
特定平台代码的区分:http://reactnative.cn/docs/0.49/platform-specific-code.html#content

React Native会检测某个文件是否具有.ios.或是.android.的扩展名,然后根据当前运行的平台加载正确对应的文件。

假设你的项目中有如下两个文件:

BigButton.ios.jsBigButton.android.js

这样命名组件后你就可以在其他组件中直接引用,而无需关心当前运行的平台是哪个。

import BigButton from './components/BigButton';

React Native会根据运行平台的不同引入正确对应的组件。

实用的方法是Platform.select()

e.g.:

import { Platform, StyleSheet } from 'react-native';var styles = StyleSheet.create({  container: {    flex: 1,    ...Platform.select({      ios: {        backgroundColor: 'red',      },      android: {        backgroundColor: 'blue',      },    }),  },});

上面的代码会根据平台的不同返回不同的container样式——iOS上背景色为红色,而android为蓝色。

这一方法可以接受任何合法类型的参数,因此你也可以直接用它针对不同平台返回不同的组件,像下面这样:

var Component = Platform.select({  ios: () => require('ComponentIOS'),  android: () => require('ComponentAndroid'),})();<Component />;
对于其他文件组件的引用:
//App.js 文件
import CustTabBarItem from "./TabBarItem” //App 文件和 TabBarItem.js在同一目录下
…..
//使用
<CustTabBarItem                    tintColor={tintColor}                    focused={focused}                    selectImage={{uri: 'tabbar_home_select'}}                    normalImage={{uri: 'tabbar_home'}}                />
…..
//TabBarItem.js 文件
export default class TabBarItem extends Component {    render(){        return (            <Image source={this.props.focused ? this.props.selectImage : this.props.normalImage}            style={{tintColor: this.props.tintColor, width: 25, height: 25}}/>        );    }}