##react-native 自定义封装刷新组件
###几个月没写博客了,最近一直在写react 和react-native,前几天刚发了一版基于react-native混合开发的App,这几天赶快总结下。
#目录
##1.FlatList常用的属性方法
##2.封装一个上拉加载,下拉刷新的组件
###注:当然还有其他的属性方法,请自行查阅文档FlatList
##2.封装一个上拉加载,下拉刷新的组件
static propTypes = {
renderItem: PropTypes.func.isRequired, /* 渲染行的方法 */
ItemSeparatorComponent: PropTypes.func, /* 渲染行间隔的方法 */
keyExtractor: PropTypes.func, /* 返回每行key的方法 */
ListFooterComponent: PropTypes.func, /* 渲染列表底部的方法 */
ListHeaderComponent: PropTypes.func, /* 渲染列表头部的方法 */
listUrl: PropTypes.string.isRequired, /* 获取列表的url */
fetchMethod: PropTypes.string, /* 获取列表的请求方式(默认为get) */
fetchParams: PropTypes.object, /* 获取列表的请求参数 */
pageSize: PropTypes.number, /* 每页行数(默认20条) */
formatData: PropTypes.func, /* 返回列表数组的方法 */
_ref: PropTypes.func, /* 获取组件实例属性 */
auto: PropTypes.bool, /* 是否在加载时自动查询(默认自动) */
showFooterBoo: PropTypes.bool, /* 是否显示脚 */
ref: PropTypes.func, /* 获取组件实例 */
};
2.初始化当前状态state
constructor(props) {
super(props);
this._fetchUrl = props.listUrl;
this._fetchParams = props.fetchParams;
this.state = {
list: [], /* 列表数据 */
pageNum: 1, /* 当前页数 */
count: 0, /* 总条数 */
refreshing: false, /* 是否正在加载 */
isEnd: false, /* 是否加载完 */
isNotList: false, /* 是否未查询到数据 */
isError: false, /* 是否查询失败 */
}
}
3.FlatList组件属性封装
const { list, refreshing } = this.state;
const {
renderItem,
ItemSeparatorComponent,
keyExtractor = (...arg) => arg[1],
ListHeaderComponent,
extraData = {},
showFooterBoo,
} = this.props;
this._listRef = ref}
extraData={extraData}
/>
4.data={list} 中list数据来源于引用组件处的属性
5.renderItem={renderItem} 中renderItem来源于引用组件的Item布局属性
6.onRefresh={this.onRefresh} 下拉刷新布局如下:
/**
* 下拉刷新
* @return {void}
*/
onRefresh = () => {
this.setState({
isEnd: false,
}, () => {
this.getList();
});
}
/**
* 获取列表
* @return {void}
*/
getList = (isRefresh = true) => {
const {
$fetch,
fetchMethod = 'get',
pageSize = 20,
formatData = ({data}) => ({
list: data.records,
count: data.total,
}),
fetchCatch = () => {},
} = this.props;
const { list, pageNum, refreshing, isEnd } = this.state;
if((refreshing || isEnd) && !isRefresh) return;
const fetchPageNum = isRefresh ? 1 : pageNum;
let fetchPromise;
if(fetchMethod.toLowerCase() === 'get') {
fetchPromise = $fetch.get(this._fetchUrl, {
size: pageSize,
current: fetchPageNum,
...this._fetchParams,
});
} else if(fetchMethod.toLowerCase() === 'post') {
fetchPromise = $fetch.post(`${this._fetchUrl}`, {
...this._fetchParams,
});
} else {
throw new Error('method type error! only "get" or "post"');
}
this.setState({refreshing: true});
fetchPromise.then(data => {
console.log(data);
if(!data.success) {
this.setState({ isError: true });
return;
}
const listData = formatData(data);
const currentList = isRefresh ? listData.list : list.concat(listData.list);
/* 判断是否查询到数据 */
if(fetchPageNum === 1 && listData.list.length === 0){
this.setState({
isNotList: true
});
} else {
this.setState({
isNotList: false
});
}
/* 如果有数据则添加到列表中 */
if(listData.list.length) {
this.setState({
list: currentList,
pageNum: fetchPageNum + 1,
});
}
if(currentList.length >= listData.count) {
this.setState({
isEnd: true
});
}
this.setState({
count: listData.count,
});
}).catch(err => {
console.log(err.response);
if(!data.success) {
this.setState({ isError: true });
}
fetchCatch(err);
}).finally(() => {
this.setState({refreshing: false});
});
}
###注:get与post可以根据自己的具体需求进行优化,其中网络请求使用的fetch。
7.refreshing={refreshing} 中refreshing布尔值,是用来判断当前是否是出于刷新状态的,当处于请求数据的刷新状态时置为true。
8.onEndReachedThreshold={0.2} 当滑动比例为0.2时触发onEndReached方法;onEndReached={this.onEndReached}上拉加载实现,如下:
/**
* 上拉加载
* @return {void}
*/
onEndReached = () => {
this.getList(false);
}
###注:this.getList(false);方法同下拉刷新,参数false代表上拉加载。
9.ItemSeparatorComponent={ItemSeparatorComponent} 自定义一个分割线,如下:
export const ItemSeparator = props => {
const {
paddingLeft = px(40),
backgroundColor = '#fff',
borderColor = '#eee',
} = props;
return (
);
};
10.keyExtractor={keyExtractor} 使用当前数据的id即可,如下:
keyExtractor={item => item.id}
11.ListHeaderComponent={this.renderListHeader} 头部的渲染,代码如下:
/**
* 渲染列表头部
*/
renderListHeader = () => {
const { count } = this.state;
const { ListHeaderComponent = () => } = this.props;
return ListHeaderComponent(this.state);
}
###注:布局根据自己的需求进行定义即可。
12.ListFooterComponent={showFooterBoo ? this.renderListFooter : null} 属性showFooterBoo布尔值用来控制是否显示脚,脚的布局定义如下:
/**
* 渲染列表底部
* @return {ReactComponent}
*/
renderListFooter = () => {
const { ListFooterComponent = this.defaultListFooter } = this.props;
const { isEnd, refreshing } = this.state;
return this.defaultListFooter(isEnd, refreshing);
}
/**
* 列表默认底部组件
* @return {Node}
*/
defaultListFooter = () => {
return (
{this.defaultListFooterContent()}
);
}
/**
* 列表底部显示内容
* @return {Node}
*/
defaultListFooterContent = () => {
const { isEnd, refreshing, isNotList, isError } = this.state;
if(isNotList) {
return (
<_Text>未查询到相关数据!
);
}
if(isEnd) {
return [
,
<_Text key={2}>没有更多数据,
,
];
}
if(refreshing) {
return (
<_Text>正在加载...
);
}
if(isError) {
return (
<_Text>查询失败,下拉重新加载!
);
}
return (
<_Text>上拉加载更多
);
}
###注:脚的布局可以根据自己的项目需求进行更改。
13.ListEmptyComponent={this.renderListEmpty} 空布局,没有数据,请求出错显示,代码如下:
/**
* 列表为空时显示的组件
* @return {ReactComponent}
*/
renderListEmpty = () => {
return (
没有数据哦!
);
}
14.ref={ref => this._listRef = ref} 当前实例