每一个用react-native来开发项目的人,免不了会采一些坑,今天我们拿 列表来说事儿,正如标题所说,既然是优化,那么我们得从坑说起。
先看一段代码(最有说服力,和最直观的效果就是运行代码看结果):
import React, {Component} from "react";
import {
StyleSheet, Text, View, FlatList, Dimensions,
} from "react-native";
const {width, height} = Dimensions.get('window');//屏幕宽度
const DATA_LIST = [{key: 'a'}, {key: 'b'},]
export default class FlatListPage extends Component {
constructor(props) {
super(props);
this.state = {
data: []
};
}
componentDidMount() {
this.setState({data: this.state.data.concat(DATA_LIST)})
}
_keyExtractor = (item, index) => index + "";
_pullUpLoading = () => {
this.setState({data: this.state.data.concat(DATA_LIST)})
}
_onEndReached = () => {
console.log(1111111, '--------_onEndReached---------')
this._pullUpLoading();
}
_onLayout = (env) => {
// let {layout} = env.nativeEvent
// console.log(11111222222, layout.width, layout.height)
}
render() {
return (
2 * 40
onEndReachedThreshold={0.01} // 决定当距离内容最底部还有多远时触发onEndReached回调
scrollEventThrottle={16}
showsVerticalScrollIndicator={false}
onEndReached={this._onEndReached}
onLayout={this._onLayout} // 当组件挂载或者布局变化的时候调用,参数为:: {nativeEvent: { layout: {x, y, width, height}}} 这个事件会在布局计算完成后立即调用一次,不过收到此事件时新的布局可能还没有在屏幕上呈现,尤其是一个布局动画正在进行中的时候。
renderItem={({item}) =>
{item.key}
}
/>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
flatListStyle: {
width: width,
flex: 1,
backgroundColor: 'red',
}
});
如上代码运行,你会发现如图效果 : 此时的 contentContainerStyle 没有属性
满满一屏幕的元素,控制台打印出 onEndReached 方法执行了多次,有时候你也会看到 如下图所示的效果
onEndReached 并未执行,页面也如你所愿只渲染了一次数据
当 contentContainerStyle = {flex: 1} 或者 contentContainerStyle = {height: 200 } 这里手动设置高度必须要大于 item 渲染个数的高度 再次渲染数据,结果如下图:(最多只会 执行一次 onEndReachEnd 事件,当然有时也会达到如你所愿的效果)
原因分析:
在分析原因之前先引入两个 属性
onEndReachedThreshold 官方解释:决定当距离内容最底部还有多远时触发onEndReached回调,这里其实是针对 contentContainerStyle 属性的底部
onLayout 官方解释:当组件挂载或者布局变化的时候调用,参数为:: {nativeEvent: { layout: {x, y, width, height}}} 这个事件会在布局计算完成后立即调用一次,不过收到此事件时新的布局可能还没有在屏幕上呈现,尤其是一个布局动画正在进行中的时候。
当页面进行绘制的时候,新的布局还没有绘制完成的时候,onEndReachedThreshold = {0.01} 的属性一直是成立的,所以会触发 onEndReached, 导致页面的渲染不尽人意,当你没有 contentContainerStyle 属性时(实际开发中,我相信大多数应用场景都可以不用),也就导致了 页面一边绘制一边具有高度,结果就导致了 onEndReachedThreshold 始终满足条件,onEndReached 就不停的执行,直到页面被填满
实际项目中的优化代码如下(一下是实际生产项目的部分代码,只提供 FlatList 优化部分的注释和解答,关键在于 _isAllowToFetch 变量来控制
):
/** react 组建的引用 */
import React, { Component } from "react";
import { StyleSheet, Text, View, FlatList, Image } from "react-native";
/** 全局样式的引用 */
import HBStyle from "../../styles/standard";
import CommonSize from "../../utility/size";
/** 第三方依赖库的引用 */
/** 自定义组建的引用 */
import withTemplate from "../../components/HOC/withTemplate";
import withOnScroll from "../../components/HOC/withOnScrollToNav";
import CTouchableWithoutFeedback from "../../components/CTouchableWithoutFeedback";
/** 模板页面的引用 */
import ResultPageNoTitle from "../../components/ResultPageNoTitle";
/** 工具类的引用 */
import WebAPI from "../../utility/webAPI";
import Util from "../../utility/util";
import BorrowerToken from "../mobx";
import NativeModule from "../../utility/nativeModule";
import { observer } from "mobx-react";
/** 常量声明 */
const WithScrollView = withOnScroll(FlatList); // 高阶组件返回的 FlatList
const NOData_Icon = require("../../res_img/common/common_img_blank.png");
@observer
@withTemplate
export default class Notice extends Component {
_isAllowToFetch = false; // 是否允许上拉加载控制变量
constructor(props) {
super(props);
this.state = {
hasMoreNoticeData: true, // 是否收到过通知
page: 1, // 页数
rows: 10, // 每页条数
data: [],
isShowFooterCom: false // 默认不展示
};
this.navConfig = {
title: "通知"
};
}
componentDidMount() {
this._getNotice(true);
}
componentWillMount() {}
componentWillUnmount() {}
componentWillReceiveProps(nextProps, nextState) {}
shouldComponentUpdate(nextProps) {
return true;
}
/** 获取通知列表 */
_getNotice = isInitFetch => {
const { page, rows } = this.state;
WebAPI.Borrower.GetClaimsTransferNoticeList(BorrowerToken.token, page, rows).success(res => {
if (res.success) {
if (Util.isArray(res.data) && res.data.length > 0) {
this.setState({ data: this.state.data.concat(res.data), hasMoreNoticeData: true });
if (res.data.length >= 10) {
this._isAllowToFetch = true; // 当后台接口返回的数据不止一页的时候,允许上拉加载,可以执行该事件
} else {
this._isAllowToFetch = false; // 否则就不允许上拉加载
this.setState({ isShowFooterCom: true });
}
this.state.page += 1;
} else {
this._isAllowToFetch = false; // 接口请求失败更是不可能上拉加载
isInitFetch && this.setState({ hasMoreNoticeData: false });
}
} else if (!res.success && res.errorCode === "100001") {
Util.alert.show({
content: "你的荷包已在其他设备上登录,如非本人操作,则密码可能已泄露,请重新登录后立即修改登录密码。",
buttons: [{ title: "我知道了" }]
});
}
});
};
/** 跳转到转让协议 */
_goTransfer = item => {
NativeModule.RNBridge.jsBridgeOpen(item.noticeUrl);
};
_renderItem = ({ item }) => {
return (
this._goTransfer(item)}>
{"债权转让通知书"}
{item.noticeName}
{Util.formatDate(item.transferDate, "yyyy-m-d HH:MM")}
);
};
_keyExtractor = (item, index) => index + "" + item.id;
/** 下拉刷新 */
_onEndReached = () => {
if (!this._isAllowToFetch) return; // 初始化页面,不会进行数据的加载
this._getNotice();
};
_footerCom = () => {
return (
{"没有更多啦~"}
);
};
render() {
const { isShowFooterCom } = this.state;
return (
{!this.state.hasMoreNoticeData ? (
{"还没收到过通知"} } />
) : (
(this._pullInstance = ref)}
contentContainerStyle={{ paddingHorizontal: 12 }}
style={styles.flatListStyle}
keyExtractor={this._keyExtractor}
data={this.state.data}
renderItem={this._renderItem}
onEndReached={this._onEndReached}
ListFooterComponent={isShowFooterCom ? this._footerCom : null}
onEndReachedThreshold={0.01}
scrollEventThrottle={16}
showsVerticalScrollIndicator={false}
/>
)}
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
width: CommonSize.screen.width,
backgroundColor: HBStyle.color.gray_bg,
paddingBottom: Util.isIPhoneX() ? 34 : 0
},
flatListStyle: {
flex: 1
},
itemsWrapper: {
paddingHorizontal: 12,
backgroundColor: HBStyle.color.white_bg,
borderRadius: 5,
paddingTop: 15,
paddingBottom: 13.5,
marginTop: 12,
height: 94,
flex: 1
},
describeFont: {
fontSize: HBStyle.font.Body2,
color: "#bebebe",
textAlign: "center"
}
});
更多的干货请点击 https://blog.csdn.net/woleigequshawanyier
react-native 实战项目demo https://github.com/15826954460/BXStage
欢迎各位看官的批评和指正,共同学习和成长
希望该文章对您有帮助,也希望得到您的鼓励和支持