// 给listview设置数据源
// dataSource{}接口用于在数据显示的时候判断哪些数据显示哪些不显示
dataSource={this.state.dataSource}
// renderRow表示渲染一行
// 也就是这里会一条一条的从dataSource中取数据,然后按照
// renderMovie(movie)里面的规则去显示item,前提就是dataSource里面存放的是movie这种类型的数据
renderRow={this.renderMovie}
// 指定style为listview类型
style={styles.listView}
/>
下面我们就通过组件ListView来进一步理解和熟悉React Native
官网中提供的有这个示例,不过里面的示例注释不够,对于新手来说里面的内容在理解上还是不太够用,所以我就自己写了一下这个js,其中的注释也很详细,对于新手来说也能看的懂。
下面的内容,大家可以直接把这个内容粘贴下来创建一个新的index.android.js文件放在你的项目中去,然后Reload js查看效果。完整的代码如下:
/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
Image,
ListView,
View
} from 'react-native';
/**
* 为了避免骚扰,我们用了一个样例数据来替代Rotten Tomatoes的API
* 请求,这个样例数据放在React Native的Github库中。
* 当然,由于众所周知的原因,这个地址可能国内访问也比较困难。
*/
var REQUEST_URL = 'https://raw.githubusercontent.com/facebook/react-native/master/docs/MoviesExample.json';
/*
* 大家可以把这个类的名字换成你们的项目的名称,然后替换掉你自己的index.android.js文件
* 注意:这个类型必须和你的项目名称一致,并且文件最后一行通过AppRegistry注册的名称也必须和你的项目名称一致
*/
export default class SampleAppMovies extends Component {
/**
* 构造函数
*/
constructor(props){
super(props); // 这一句不能省略
this.state={
// 这里放我们自定义的state变量及初始值
movies:null,
dataSource:new ListView.DataSource({
rowHasChanged:(row1, row2) => row1 !== row2, // 控制显示和隐藏 !== 代表不等于符号
}),
loaded:false,
};
// 在ES6中,如果在自定义的函数中使用了this关键字,则需要对该函数进行绑定操作
// 否则this的指向不明确就会报错
// 像下面的代码一样,在constructor 函数中使用bind 也可以使用箭头函数
this.fetchData = this.fetchData.bind(this);
}
/**
* 渲染 视图显示 方法
*/
render() {
// 判断如果movies为null或者loaded为false的话就显示‘正在加载中...’
if(!this.state.movies || !this.state.loaded){
return this.renderLoadingView();
}
// 显示一个电影条目的时候使用下面的方法
// var movie = this.state.movies[0];
// return this.renderMovie(movie);
return this.renderMovies();
}
/**
* 加载中显示的view
*/
renderLoadingView(){
return (
正在加载电影数据...
);
}
/*
* 加载成功显示一条结果,这里相当于显示一条item的布局格式
*/
renderMovie(movie){
return (
{movie.title}
{movie.year}
);
}
/**
* 加载成功显示所有结果
*/
renderMovies(){
return(
this.state.dataSource} // 给listview设置数据源,dataSource{}接口用于在数据显示的时候判断哪些数据显示哪些不显示
renderRow={this.renderMovie} // 这里是显示一条item的方法,也就是这里会一条一条的从dataSource中取数据,然后按照renderMovie(movie)里面的规则去显示item
style={styles.listView} // 指定style为listview类型
/>
);
}
/**
* 这个方法在所有组件加载完成的时候会被调用,只调用一次,一般请求网络的操作会在这个方法中调用
*/
componentDidMount(){
this.fetchData();
}
/**
* 自定义 网络请求方法
*/
fetchData(){
fetch(REQUEST_URL) // 请求接口
.then((response) => response.json()) // 将返回结果通过json转为实例对象
.then((responseData) => { // 得到想要的数据并重新渲染界面
// this.setState();方法调用的时候会出发一次重新渲染的操作,也就是会重新执行一次render()方法刷新界面
this.setState({
// 将结果放在数组中
movies:responseData.movies,
// 将结果放在 dataSource中
dataSource:this.state.dataSource.cloneWithRows(responseData.movies),
loaded:true,
});
});
}
}
const styles = StyleSheet.create({
container: {
flex: 1, // 占一份,可能是横向(代表width)也可能是纵向(代表height)
flexDirection:'row', // 指定让容器内的成员从左到右横向布局,默认从上到下纵向布局
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
paddingLeft:12
},
thumbnail:{
width:53,
height:81
},
rightContainer:{
flex:1 // 占一份
},
title:{
fontSize:20,
marginBottom:8,
textAlign:'center'
},
year:{
textAlign:'center'
},
listView: {
paddingTop: 20,
backgroundColor: '#F5FCFF',
}
});
// 注册使用
AppRegistry.registerComponent('SampleAppMovies', () => SampleAppMovies);
上面的代码示例中,需要我们注意的有以下几点:
import {
...,
ListView,
View
} from 'react-native';
constructor(props){
super(props); // 这一句不能省略
this.state={
movies:null,
dataSource:new ListView.DataSource({
rowHasChanged:(row1, row2) => row1 !== row2,
}),
loaded:false,
};
this.fetchData = this.fetchData.bind(this);
}
在构造中我的写法没有完全模仿官网中的写法,我保留了在state 中的movies,我是想着为之后的操作预留的,大家如果用不着可以删除掉(注意代码中的引用也要删掉)。Component 的constructor(props) 方法中建议写一些初始化的东西,至于其中的state 和 props 这两个东西我们在下一篇blog中会详细介绍。
/**
* 这个方法在所有组件加载完成的时候会被调用,只调用一次,一般请求网络的操作会在这个方法中调用
*/
componentDidMount(){
this.fetchData(); // 请求接口,处理网络请求 这个是我们自定义的方法
}
关于Component 组件的生命周期推荐大家看两篇文章React.Component 和 阮一峰的一篇文章 ,组件的生命周期有三种状态:
Mounting:已插入真实 DOM
Updating:正在被重新渲染
Unmounting:已移出真实 DOM
每种状态对应五个生命周期方法,did和will分别在进入某种状态之后和之前调用:
componentWillMount() // 增加节点之前
componentDidMount() // 增加节点之后
componentWillUpdate(object nextProps, object nextState) // 重新渲染界面之前
componentDidUpdate(object prevProps, object prevState) // 重新渲染界面之后
componentWillUnmount() // 移除节点之前
另外,React还提供了两种特殊状态的处理函数,方便用户手动去更新界面:
componentWillReceiveProps(object nextProps) // 已经加载的组件的参数变化的时候可以调用
shouldComponentUpdate(object nextProps, object nextState) // 判断组件是否重新渲染时候调用
fetchData(){
fetch(REQUEST_URL) // 请求接口
.then((response) => response.json())
.then((responseData) => {
this.setState({
movies:responseData.movies,
dataSource:this.state.dataSource.cloneWithRows(responseData.movies),
loaded:true,
});
});
}
这里面需要注意的就是接口的返回类型需要是json格式的,解析成功之后通过对象responseData 去得到我们想要的结果就行了。
我们要为ListView指定数据源,处理item的加载,也就是上面的renderMovie(movie)方法,这个方法在Android中就类似于Adapter中的ViewHolder,用于item的显示。
电影列表示例资料地址:
http://reactnative.cn/docs/0.38/sample-application-movies.html
组件生命周期:
http://www.ruanyifeng.com/blog/2015/03/react.html
https://facebook.github.io/react/docs/react-component.html