每一个用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 (<View style={[styles.container, {marginTop: 44}]}><FlatListstyle={styles.flatListStyle}data={this.state.data}keyExtractor={this._keyExtractor}// contentContainerStyle={{backgroundColor: 'blue', flex: 1}}// contentContainerStyle={{backgroundColor: 'blue', height: 200}} height > 2 * 40onEndReachedThreshold={0.01} // 决定当距离内容最底部还有多远时触发onEndReached回调scrollEventThrottle={16}showsVerticalScrollIndicator={false}onEndReached={this._onEndReached}onLayout={this._onLayout} // 当组件挂载或者布局变化的时候调用,参数为:: {nativeEvent: { layout: {x, y, width, height}}} 这个事件会在布局计算完成后立即调用一次,不过收到此事件时新的布局可能还没有在屏幕上呈现,尤其是一个布局动画正在进行中的时候。renderItem={({item}) =><View style={{width: width,height: 40,marginTop: 10,justifyContent: 'center',alignItems: 'center',backgroundColor: 'gray'}}><Text style={{fontSize: 20,}}>{item.key}</Text></View>}/></View>);}
}
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 (<CTouchableWithoutFeedback handle={() => this._goTransfer(item)}><View style={styles.itemsWrapper}><Textstyle={{fontSize: 16,color: HBStyle.color.wblack,marginBottom: 19.5}}>{"债权转让通知书"}</Text><View style={{ ...HBStyle.layout.rsbc }}><View style={{ ...HBStyle.layout.rsbc }}><Image style={{ width: 24, height: 24, marginRight: 7 }} source={require("../../res_img/borrower/image/news_img_notice.png")} /><Text style={{ fontSize: 13, color: HBStyle.color.wgray_main }}>{item.noticeName}</Text></View><View style={{ ...HBStyle.layout.rsbc }}><Text style={{ fontSize: 13, color: HBStyle.color.wgray_main }}>{Util.formatDate(item.transferDate, "yyyy-m-d HH:MM")}</Text></View></View></View></CTouchableWithoutFeedback>);};_keyExtractor = (item, index) => index + "" + item.id;/** 下拉刷新 */_onEndReached = () => {if (!this._isAllowToFetch) return;  // 初始化页面,不会进行数据的加载this._getNotice();};_footerCom = () => {return (<View style={[HBStyle.layout.ccc, { height: 40 }]}><Text style={{ fontSize: 13, color: HBStyle.color.wgray_main }}>{"没有更多啦~"}</Text></View>);};render() {const { isShowFooterCom } = this.state;return (<View style={styles.container}>{!this.state.hasMoreNoticeData ? (<ResultPageNoTitle imgurl={NOData_Icon} textView={() => <Text style={styles.describeFont}>{"还没收到过通知"}</Text>} />) : (<WithScrollViewref={ref => (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}/>)}</View>);}
}
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

欢迎各位看官的批评和指正,共同学习和成长

希望该文章对您有帮助,也希望得到您的鼓励和支持

FlatList 优化相关推荐

  1. React Native FlatList优化

    众所周知React Native刷新控件一般都是采用setState,对于FlatList来说就要想办法减少item的渲染,采用shouldComponentUpdate自己定义什么情况下执行刷新,有 ...

  2. React Native列表视图FlatList使用优化实践指南

    列表视图在app中是非常常见的,目前React Native比较严重的性能问题集中在FlatList大列表等地方,以下通过js层的优化,甚至原生层的优化封装,使性能媲美原生. FlatList Rea ...

  3. RN性能优化以及事件监听

    自从React Native出世,虽然官方一直尽可能的优化其性能,为了能让其媲美原生App的速度,但是现实感觉有点不尽人意.接下来介绍下实践中遇到的一些性能问题以及优化方案. 一.StackNavig ...

  4. React Native FlatList和SectionList列表组件

    FlatList 之前使用的组件是ListView,当时要添加一个下拉刷新,上拉加载的功能,所以对ListView做了一些封装,但是后来看官方文档,不建议再使用ListView,因为效率问题,做过An ...

  5. react native关于FlatList的随手记

    FlatList 注意: 1. 滑出渲染区域后,内部状态不保留,请确保组件以外保留了数据 2. 为了优化内存占用同时保持滑动顺畅,列表内容会在屏幕外绘制,如果滑动速度超过渲染速度,则会先看到空白内容3 ...

  6. React Native入门(七)之列表组件的使用(2)关于FlatList的一切

    前言 在上一篇博客中了解了列表组件的相关内容,主要是静态的展示了一个列表数据,了解了ScrollVIew,FlatList和SectionList的基本用法,本篇文章就深入的了解一个常用的一个列表组件 ...

  7. RN FlatList使用详解及源码解析

    FlatList使用详解及源码解析 前言 长列表或者无限下拉列表是最常见的应用场景之一.RN 提供的 ListView 组件,在长列表这种数据量大的场景下,性能堪忧.而在最新的 0.43 版本中,提供 ...

  8. FlatList组件的使用

    上一篇博客介绍了ScrollableTabView组件,其中封装了一个CategoryList组件,这篇博客介绍一下这个组件的封装,其实看下图很简单的,就是一个FlatList组件,但还是第一次使用还 ...

  9. RN FlatList组件

    长列表或者无限下拉列表是最常见的应用场景之一.RN 提供的 ListView 组件,在长列表这种数据量大的场景下,性能堪忧.而在最新的 0.43 版本中,提供了 FlatList 组件,或许就是你需要 ...

最新文章

  1. EMNLP 2021 | ST-ToD:小样本场景下的任务型对话预训练
  2. javq接口_Java为什么要使用接口_java接口怎么使用
  3. qdialog 只有点击才能获得焦点_4 个突破点,让你的 Banner 点击率提升10倍
  4. python训练营朋友圈留言_用Python发一个高逼格的朋友圈【附代码】
  5. Web前端笔记-修改element ui中表格样式(透明、去横纵线等含修改思路)
  6. LaTeX常用Debug方法汇总
  7. 准备在北京Tech·Ed上组织博客园聚会
  8. Nhibernate学习的第一天
  9. python爬虫简单示例
  10. kettle数据清洗
  11. 怎样用计算机做ppt,电脑怎么制作ppt步骤
  12. u盘虚拟启动cd linux,CDlinux系统用U盘搭建启动盘
  13. 华硕笔记本电脑重装系统后不能读取usb,不能上网
  14. ERROR command failed: npm install --loglevel error --legacy-peer-deps
  15. 频域串联滞后校正matlab,控制工程基础(基于Matlab的线性系统串联校正)
  16. html5页面3d滚动轮播,jQuery实现的3D版图片轮播示例【滑动轮播】
  17. 使用Golang开发手游服务器的感想
  18. 两名老人接力营救轻生女子一人溺亡
  19. 统考英语计算机报名入口奥鹏,考试服务
  20. KITTI数据真值处理

热门文章

  1. R 创建文件夹和子文件夹
  2. 魔术中的数学艺术系列讲座(一)——开篇简介
  3. 关于用DELPHI开发服务器软件中的一些经验
  4. flash与游戏笔记:滚动数字
  5. 苹果wifi网速慢怎么办_苹果手机WiFi网速慢?这四招让网速无比流畅,只有19.27%的人知道...
  6. java 鱼刺图_使用java实现鱼刺图
  7. 从数字孪生到数字永生,元宇宙发展的“三阶段论”
  8. JW Player 5.7 去水印版
  9. 针对软件研发流程,我总结出的流水线生产方法论
  10. 20个 Linux 服务器性能调优技巧