RN 上拉下拉刷新的组件封装篇
首先,先上一份实现了 List 上下拉刷新的代码:
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
ListView,
TouchableHighlight,
RefreshControl,
Image,
} from 'react-native';
import MZCKit from 'react-native-mzckit';
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
export default class PageContent extends Component<Props> {
static navigationOptions = ({navigation}) => ({
title: '最新动态',
headerStyle: { backgroundColor: '#ff6600', },
headerTintColor: '#FFFFFF',
headerTitleStyle: { color: 'white' },
});
constructor(props) {
super(props);
this.state = ({
refreshing: true,
loadMore: false,
name: this.props.name,
dataSource: [],
page:1,
})
}
componentDidMount() {
this._fetchData();
}
_fetchData() {
var that = this;
var params = {id:2,page:this.state.page,per_page:20};
var url = 'http://api.test.com' + '/v2/api.article.list';
MZCKit.post2(url,params, function (data) {
if (data.error_code === 0) {
console.log('aaaaaaaaaaaaaaaaaa=========', data);
let articles = data.articles;
that.setState({
refreshing: false,
loadMore: false,
dataSource:that.state.dataSource.concat(articles),
});
}
}, function (err) {
console.log('nnnnnnnnnnnnnnnnnn', err);
alert(err)
});
}
_onRefresh() {
this.setState({
refreshing: true,
page: 1,
dataSource: [],
}, () => this._fetchData());
}
_onEndReached() {
if (this.state.dataSource.length === 0) return;
this.setState({
loadMore: true,
page: this.state.page + 1,
}, () => this._fetchData());
}
_onPress(rowData) {
const {navigate} = this.props.navigation;
navigate('NewsDetail', {
title: rowData.title,
href: 'http://api.test.com/article/' + rowData.id
})
}
_renderRow(rowData) {
return <TouchableHighlight
underlayColor='#008b8b'
onPress={() => this._onPress(rowData)}>
<View style={styles.rowStyle}>
<Text style={{fontSize: 20, flex: 1}}>{rowData.title}</Text>
</View>
</TouchableHighlight>
}
render() {
const FooterView = this.state.loadMore ?
<View style={styles.footer}>
<Text style={{fontSize: 16, color: '#777'}}>加载更多...</Text>
</View> : null;
return <ListView
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this._onRefresh.bind(this)}
/>
}
style={[styles.listView]}
dataSource={ds.cloneWithRows(this.state.dataSource)}
enableEmptySections={true}
renderRow={this._renderRow.bind(this)}
onEndReachedThreshold={10}
onEndReached={this._onEndReached.bind(this)}
renderFooter={() => FooterView}
/>
}
}
const styles = StyleSheet.create({
listView: {
backgroundColor: '#eee',
},
rowStyle: {
padding: 10,
backgroundColor: '#fff',
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 1,
},
footer: {
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
height: 40,
},
});
可以看到这个实现有很多方法。
_fetchData 请求事件
_onRefresh 下拉刷新事件
_onEndReached 上拉刷新事件
_onPress 点击事件
_renderRow 实现 List 的 Row
封装
把通用的东西提取出来,比如
_fetchData 请求
_onPress 点击事件
_renderRow 实现 List 的 Row
其他的刷新事件就封装在组件里面。
最终实现 刷新组件
NewsListPageListRefresh.js
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
ListView,
RefreshControl,
} from 'react-native';
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
const styles = StyleSheet.create({
footer: {
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
height: 40,
},
});
export default class PageContent extends Component<Props> {
static defaultProps = {
initPage: 1,
backgroundColor: '#fff',
footerView : (
<View style={styles.footer}>
<Text style={{fontSize: 16, color: '#777'}}>加载更多...</Text>
</View>
),
footerViewEnd : (
<View style={styles.footer}>
<Text style={{fontSize: 16, color: '#777'}}>没有更多的数据。</Text>
</View>
)
}
constructor(props) {
super(props);
this.state = ({
refreshing: true,
loadMore: false,
dataSource: [],
page:this.props.initPage,
})
}
componentDidMount() {
if (this.props.fetchData) {
this.props.fetchData(this);
}
}
_onRefresh() {
this.setState({
refreshing: true,
page: this.props.initPage,
dataSource: [],
}, () => {
if (this.props.fetchData) {
this.props.fetchData(this);
}
});
}
_onEndReached() {
if (this.state.dataSource.length === 0) return;
this.setState({
loadMore: true,
page: this.state.page + 1,
}, () => {
if (this.props.fetchData) {
this.props.fetchData(this);
}
});
}
render() {
const FooterView = this.state.loadMore ?
this.props.footerView : this.props.footerViewEnd;
return (
<ListView
style={{backgroundColor:this.props.backgroundColor}}
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this._onRefresh.bind(this)}
/>
}
style={[styles.listView]}
dataSource={ds.cloneWithRows(this.state.dataSource)}
enableEmptySections={true}
renderRow={this.props.renderRow.bind(this)}
onEndReachedThreshold={10}
onEndReached={this._onEndReached.bind(this)}
renderFooter={() => FooterView}
/>
)
}
}
提供属性:
fetchData(this) 接入请求的方法,this 为组件。
renderRow(rowData) 接入List的Row的方法,rowData 就是当前Row 要使用的数据。
backgroundColor 背景颜色值,初始值为#fff。
initPage 默认页,初始值为1。
footerView "加载更多..."的组件。
footerViewEnd "没有更多的数据。"的组件。
loadMore 布尔值,判断是否有更多的加载。
refreshing 布尔值,判断是否加载中。
使用该组件
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
TouchableHighlight,
SafeAreaView,
} from 'react-native';
import MZCKit from 'react-native-mzckit';
import ListRefresh from './NewsListPageListRefresh';
export default class PageContent extends Component<Props> {
static navigationOptions = ({navigation}) => ({
title: '最新动态',
headerStyle: { backgroundColor: '#ff6600', },
headerTintColor: '#FFFFFF',
headerTitleStyle: { color: 'white' },
});
_fetchData(that) {
var params = {id:2,page:that.state.page,per_page:20};
var url = 'http://api.test.com' + '/v2/api.article.list';
MZCKit.post2(url,params, function (data) {
if (data.error_code === 0) {
console.log('aaaaaaaaaaaaaaaaaa=========', data);
let articles = data.articles;
that.setState({
refreshing: false,
loadMore: false,
dataSource:that.state.dataSource.concat(articles),
});
}
}, function (err) {
console.log('nnnnnnnnnnnnnnnnnn', err);
alert(err)
});
}
_onPress(rowData) {
const {navigate} = this.props.navigation;
navigate('NewsDetail', {
title: rowData.title,
href: 'http://api.test.com/article/' + rowData.id
})
}
_renderRow(rowData) {
return <TouchableHighlight
underlayColor='#008b8b'
onPress={() => this._onPress(rowData)}>
<View style={styles.rowStyle}>
<Text style={{fontSize: 20, flex: 1,color:'#cc9660'}}>{rowData.title}</Text>
</View>
</TouchableHighlight>
}
render() {
return <SafeAreaView>
<ListRefresh backgroundColor='#ccff00'
renderRow={this._renderRow.bind(this)}
fetchData={this._fetchData.bind(this)}
/>
</SafeAreaView>
}
}
const styles = StyleSheet.create({
rowStyle: {
padding: 10,
backgroundColor: '#fff',
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 1,
},
});