React Native学习笔记之一

概述:

React Native 是现在比较火的Android APP开发技术,由FaceBook推出的基于JSX开发的一个可以跨平台开发的框架。 Facebook在这个框架中提出了一个理念: Learn once, write anywhere 也是这个框架的优势所在。目前基于RN开发的APP有:
天猫iPad客户端,支付宝,携程网,Facebook Group,Chinese Flashcards等等(部分业务、模块采用RN开发)。

下图是RN实践的demo:
第一个RN程序

Step 1: 环境的搭建(mac)

  1. 安装Homebrew;
  2. 安装nvm;
  3. 安装node,通过命令:nvm install node && nvm alias default node
  4. 安装watchmam,通过命令:brew install watchman
  5. 安装flow,通过命令:brew install flow
  6. 安装React Native,通过命令:npm install -g react-native-cli;
  7. 创建React Native应用程序,通过命令react-native init HelloWorld;
  8. 进入HelloWorld目录,并创建5.0系统以上的安卓模拟器;
  9. 配置React Native环境,通过命令npm install
  10. 运行React Native程序,通过命令react-native run-android

Step 2: React Native项目的基本认识

进入HelloWorld目录后,我们至少看到以下几个文件或者文件夹:

文件夹

android
ios
node_modules

文件

index.androi.js
index.ios.js
package.json

android、ios文件夹分别对应ios工程和android工程,两个js文件分别对应android、ios默认的js文件,package.json和package.json是React Native的环境配置相关文件。

Android工程依赖于指定的js展示界面,全工程甚至可以只需要通过一个Activity和多个js文件来表现不同的页面。在js文件中,Facebook提供了UI组件,网络请求等其他APIS,类似于于Activity+XML的结合体。

在这里不得不提的是,Facebook在最早的时候提出基础理念叫做React,基于此出现了ReactJS来开发网页,直到现在出现React Native来开发移动应用。在React Native官网中提到这么一句话:

React Native enables you to build world-class application experiences on native platforms using a consistent developer experience based on JavaScript and React.

也就是说React Native是基于JavaScript和React的开发框架,因此支持JS语法。

Step 3: JS文件语法的初步学习

打开index.androoid.js,观察里面的代码。从上往下解读:

代码的开始以:

import ... from ...

的方式引入该界面所需要的组件元素。

中间创建了一个HelloWorld组件,在最早的RN版本中,使用React.CreateClass的形式创建组件,在最新的RN版本中使用了:

extends Component

的方式代替React.CreateClass,因此在很多教程中出现不一样的代码。

接下来是

const styles = StyleSheet.create({})

这里才用CSS Style来对UI进行管理。

最后

AppRegistry.registerComponent('HelloWorld', () => HelloWorld);

注册组件,单引号内的HelloWorld对应MainActivity中的getMainComponentName()方法返回的指定的组件名称,后面的HelloWorld是我们在上面通过extends Component的方式创建的component。

重点观察class HelloWorld中的内容:

render() {
    return {};
};

在render方法中返回了类似于“div”标签形式组合的ui组件,通过修改对应的文本,并双击R(Genymotion)ReLoad JS,可以查看修改后的内容。

通过访问React Native官网,在左侧的导航列表的COMPONENTS列表中可以看到通用的UI控件,如ListViewImage等等。参考官网提供的学习步骤,我们可以新建一个js文件,建立自己的Movie List程序,效果图如上图所示。

Step 4: JS文件的编写

新建movielist.js,并保存在目录HelloWorld工程的根目录下(与index.android.js目录平级),修改MainActivity中的getJSMainModuleName()方法返回的String字符串"index.android""movielist",引入相应控件,ImageText等:

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Image,
} from 'react-native';

创建HelloWorld组件,完成render()方法,返回movie list程序的第一个item:

class HelloWorld extends Component{

    render() {
        return {
            <View style={styles.item}>
                <ImageView style={style.img} source={{require('./img/icon.png'})} />
                <Text style"styles.text">movie item</Text>
            </View>
        }
    }

}

const styles = StyleSheet.create({
    item: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        flexDirection: 'row',
        padding: 10,
    },
    img: {
        width: 100,
        height: 100,
        justifyContent: 'center',
    },
    text: {
        width: 200,
        fontSize: 10,
        textAlign: 'left',
    }
});

其中style属性同CSS的应用方法大同小异,可以查阅官网左侧导航栏底部的POLYFILLS导航进行查阅。
Image组件设置图片的方式两种,

本地:`source={require('./img/icon.png')}`;
网络:`source={{uri: item.url}}`

如果想获取到屏幕的宽度或者高度来控制控件的宽高,可通过Dimensions:

import {
  Dimensions
} from 'react-native';

const styles = StyleSheet.create({
    text: {
        width: Dimensions.get('window').width - 150,
        fontSize: 10,
        textAlign: 'left',
    }
});

item编写完成后,导入ListView组件,完成ListView的编写:
ListView是需要数据源和item view的,因此修改刚才编写好的代码,将render()方法中返回的UI组件抽取为rendItem()方法,并重写render()方法

import { ListView } from 'react-native';

class HelloWorld extends Component{

    render() {
        return {
            <ListView
                dataSouce={}
                renderRow={this.renderItem}
            ></ListView>
        }
    }

    renderItem(){
        return {
            <View style={styles.item}>
                <ImageView style={style.img} source={{require('./img/icon.png'})} />
                <Text style"styles.text">movie item</Text>
            </View>
        }
    }

}

继续为ListView补充数据,采用从网络获取的方式,Facebook提供了fetch()函数进行异步网络请求:

var REQUEST_URL = "https://raw.githubusercontent.com/facebook/react-native/master/docs/MoviesExample.json"

class HelloWorld extends Component{

    constructor() {
            super();
            this.state = {
              dataSource: new ListView.DataSource({rowHasChanged: (row1, row2) => row1 !== row2 })
            };
      }

    componentDidMount() {
        fetch(REQUEST_URL)
          .then((response) => response.json())
          .then((responseData) => {
            this.setState({
              dataSource: this.state.dataSource.cloneWithRows(responseData.movies),
            });
          })
        .done()
    }

}

在这里,constructor()componentDidMount()render()方法一样,为RN组件的生命周期,在通过
constructor()声明数据,componentDidMount()方法进行数据设置,调用this.setState()方式强制重新调起render()方法刷新视图。在React.createClass的语法中,constructor()方法等同getInitialState()
方法,都是用来初始化状态值,可用来改变组件状态。
componentDidMount()方法中通过fetch(REQUEST_URL)得到相应值response并进行转化为相应的数据格式,取对应的值赋值dataSource
注意这里的dataSource必须通过:

dataSource: new ListView.DataSource({rowHasChanged: (row1, row2) => row1 !== row2 })

的方式进行初始化,rowHasChanged是ListView的dataSource的必须属性,用来进行渲染的优化,类似于ViewHolder。

补全代码,并修改item的数据:

render() {
    return (
        <ListView
            dataSource={this.state.dataSource}
            renderRow={this.renderItem}>
        </ListView>
    )

    renderItem(movie){
        return {
            <View style={styles.item}>
                <ImageView style={style.img} source={{uri: movie.posters.thumbnail}} />
                <Text style"styles.text">{movie.title}</Text>
            </View>
        }
    }
}

至此,movie list程序已经基本完成,接下来添加点击item的点击事件。这里我们采用组件:TouchableHighlight。修改renderItem(movie)方法:

renderItem(movie){
    return {
        <TouchableHighlight onPress={this.alertImage}>
            <View style={styles.item}>
                <ImageView style={style.img} source={{uri: movie.posters.thumbnail}} />
                <Text style"styles.text">{movie.title}</Text>
            </View>
        </TouchableHighlight>
    }
}

alertImage(){
    alert("点击了一条item");
}

Facebook一共提供了四个Android的点击组件,基本点击组件为TouchableWithoutFeedback,其余的点击组件可以视为由TouchableWithoutFeedback发展过来的,TouchableWithoutFeedback是无点击出发效果的控件,而诸如TouchableHighlight则是可以通过style配置点击的动画背景效果的,可以通过TouchableWithoutFeedback等查询相应的属性。
同时,点击事件提供了按下时、松开后、长按、短按四个动作事件,同样在API上查询到,并且要注意的是:onPress的执行者是一个Object,而不是调用this.alertImage(),这是不被允许的语法。
上面我们写了最简单的点击事件,但是并没有出现对应的效果,经过查询原因,发现this.alertImage()的作用域并不正确。这里的this并不是指代的事我们认为的组件this,而是在执行renderRow={this.renderItem()}的时候改变了this的指向,因此我们可以通过bind()方法来修正这一个错误:

render() {
    return {
        <ListView
            dataSouce={}
            renderRow={this.renderItem.bind(this)}
        ></ListView>
    }
}

重新运行,发现点击之后会弹出一个弹出框。但是如果想传递点击条目对应的数据,这个时候我们发现因为只能通过Object指定点击事件,所以我们不能像调用方法那样补写参数。这个时候,我们同样可以用bind()方法实现目的:

renderItem(movie){
    return {
        <TouchableHighlight onPress={this.alertImage.bind(this,movie)}>
            <View style={styles.item}>
                <ImageView style={style.img} source={{uri: movie.posters.thumbnail}} />
                <Text style"styles.text">{movie.title}</Text>
            </View>
        </TouchableHighlight>
    }
}

alerImage(movie) {
    alert(movie.id);
}

Step 5: 总结

通过简单的初步的学习,我们了解了大致的RN应用程序交互是如何实现的。简单来说是Facebook提供了一套js解析库,开发者通过创建RN工程编写JS文件由JS库解析得到相应的事件动作。因此学习的方向包括组件的应用及封装,API和RN生命周期的学习。
在这里推荐可以学习研究的Demo:
Demo: Reading
干货集中营
OSChina的Git@OSC客户端

发布了23 篇原创文章 · 获赞 10 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/byxyrq/article/details/51833738