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

前言

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

属性

添加头部组件

ListHeaderComponent属性用来给FlatList添加头部组件
简单使用:

//ES6之前写法
_header = function () {
  return (
    <Text style={{fontWeight: 'bold',fontSize: 20}}>热门电影</Text>
  );
}


<FlatList
ListHeaderComponent={this._header}//header头部组件
/>

添加尾部组件

ListFooterComponent属性为FlatList添加尾部组件,接收的参数跟ListHeaderComponent相同。

//ES6的写法 _footer = () => ( <Text style={{fontSize: 14,alignSelf: 'center'}}>到底啦,没有啦!</Text> ) <FlatList  ListFooterComponent={this._footer} //添加尾部组件 />

添加头部和尾部组件比较简单,需要注意的就是上边两者ES5和6写法的区别!

添加分割线

ItemSeparatorComponent属性可以为FlatList列表之间添加分割线。
举个例子:

class ItemDivideComponent extends Component {
  render() {
    return (
      <View style={{height: 1,backgroundColor: 'skyblue'}}/>
    );
  }
};


<FlatList
  ItemSeparatorComponent={ItemDivideComponent}//分割线组件
/>

这里我们自定义了一个组件来设置分割线,当然我们像添加头部和尾部一样,在内部声明之后使用this._header的写法也是可以的!

设置空数据视图

ListEmptyComponent属性,可以为FlatList设置一个没有数据的时候展示的视图!,这个属性可以接收的参数类型比较多,可以是React Component,也可以是一个render函数,或者渲染好的element
所以设置空数据视图不仅可以像前边介绍的两种方式以外,还可以接收一个render函数
举个例子:

createEmptyView() { return ( <Text style={{fontSize: 40,alignSelf: 'center'}}>还没有数据哦!</Text> ); } <FlatList  ListEmptyComponent={this.createEmptyView()} />

设置item的key

在前一篇博客中,我们的设置data的时候,是这样的:

data={[
  {key: '大护法'},{key: '绣春刀II:修罗战场'},...         
]}

类似{key:你的数据value}这样的形式,是因为我们在设置data的时候,必须要为item设置key属性,否则会有一个黄色的警告弹出。而且我们需要注意的是这里每一个item的key是唯一的!,如果按照这样的写法,我们在数据中有重复的,比如{key: '大护法'},{key: '大护法'},这里的大护法只会显示一个,因为FlatList会认为这是一条数据,因为key相同!
那么为什么会这样?
因为FlatList中有一个属性:keyExtractor,用于为给定的item生成一个不重复的key若不指定此函数,则默认抽取item.key作为key值。若item.key也不存在,则使用数组下标index。因为前边没有指定该属性,所以就把item.key作为了key值,才会认定两个重复的数据是一条数据!

那么一般地,我们可以这样使用:

_keyExtractor = (item,index) => index;

<FlatList
  keyExtractor={this._keyExtractor}
/>

这样就把data中数组的下标作为了唯一的key
那么在data中指定数据的时候,就不用{key: '大护法'}这样写了,因为我们已经指定了唯一的key,而可以随意写{name: '大护法'}或者{movie: '大护法'},在渲染item的时候,取值用item.name或者item.movie即可!也不会有黄色的警告出现!

你明白了吗?

设置itemLayout

getItemLayout属性是一个可选的优化,用于避免动态测量内容尺寸的开销。如果我们知道item的高度,就可以为FlatList指定这一个属性,来使FlatList更加高效的运行!
举个例子:

getItemLayout={(data,index) => ({
  length: 44,offset: (44 + 1) * index,index
})}

我们在上边使用的时候指定了item的高度为44,所以length参数为44;我们设置了分割线,且指定分割线的高度是1,所以offset参数为44+1。综合来看,设置这个属性应这样写:

getItemLayout={(data,index) => ({ length: 你的itemheight,offset: (你的itemheight + ItemSeparatorheight) * index,index
})}

设置这一属性,在调用FlatList的跳转函数的时候非常有用,否则可能会很卡顿!如scrollToEnd(),scrollToIndex(),这两个方法后边再说!

下拉刷新

FlatList中有两个属性,可以用来设置下拉刷新。

  • refreshing在等待加载新数据时将此属性设为true,列表就会显示出一个正在加载的符号.
  • onRefresh如果设置了此选项,则会在列表头部添加一个标准的RefreshControl控件,以便实现“下拉刷新”的功能。同时你需要正确设置refreshing属性。

这里的RefreshControl控件,非常类似于Android v4包中的SwipeRefreshLayout,这里就不多说了,需要了解的可以查看相关文档!

如何使用,举个例子:

refreshing={this.state.refreshing}
onRefresh={() => {
  this.setState({refreshing: true})//开始刷新
  //这里模拟请求网络,拿到数据,3s后停止刷新
  setTimeout(() => {
    alert('没有可刷新的内容!');
    this.setState({refreshing: false});//停止刷新
  },3000);
}}

上拉加载

关于上拉加载,FlatList也封装有两个属性来实现:

  • onEndReachedThreshold:这个属性决定当距离内容最底部还有多远时触发onEndReached回调。需要注意的是此参数是一个比值而非像素单位。比如,0.5表示距离内容最底部的距离为当前列表可见长度的一半时触发。所以它的取值范围为:(0,1),不包含0和1。
  • onEndReached:列表被滚动到距离内容最底部不足onEndReachedThreshold设置的的距离时调用。

具体使用,举个例子:

onEndReachedThreshold={0.1}
onEndReached={({distanceFromEnd}) => (
  setTimeout(() => {
    this.setState((state) => ({
      data: state.data.concat(this._newData),}));
  },3000)
)}

这里我们设置的距离为列表可见长度的1/10,而触发了onEndReached函数时,我们设置了一个定时器,3s后,将data中的数据添加了新数据,从而达到上拉加载更多的效果!

函数

介绍

FlatList下有两个比较常用的函数:

  • scrollToEnd() 滚动到底部。如果不设置getItemLayout属性的话,可能会比较卡。
  • scrollToIndex()如果不设置getItemLayout属性的话,无法跳转到当前可视区域以外的位置。

如官方所言,使用这两个函数的时候,最好指定设置getItemLayout属性

使用

因为这两个是FlatList组件的函数,所以在使用这两个函数之前,首先我们要得到FlatList组件的引用。
这时候就需要ref属性。React提供的这个ref属性,表示为对组件真正实例的引用
关于ref属性的使用,可以去React官网查看API!

具体的使用:

ref={(flatList) => this._flatList = flatList}


this._flatList.scrollToEnd();

//viewPosition参数:0表示顶部,0.5表示中部,1表示底部
this._flatList.scrollToIndex({viewPosition: 0,index: this.state.text});

至此,关于FlatList进阶的相关基础内容就说完了!

完整的Demo

下面看一下完整的demo:

源码:

class FlatListTest extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: this._sourceData,refreshing: false,//初始化不刷新
      text: ''//跳转的行
    };
  }

  _header = function () {
    return (
      <Text style={{fontWeight: 'bold',fontSize: 20}}>热门电影</Text>
    );
  }

  _footer = () => (
    <Text style={{fontSize: 14,alignSelf: 'center'}}>到底啦,没有啦!</Text>
  )

  createEmptyView() {
    return (
      <Text style={{fontSize: 40,alignSelf: 'center'}}>还没有数据哦!</Text>
    );
  }

  //此函数用于为给定的item生成一个不重复的key
  //若不指定此函数,则默认抽取item.key作为key值。若item.key也不存在,则使用数组下标index。
  _keyExtractor = (item,index) => index;

  itemClick(item,index) {
    alert('点击了第' + index + '项,电影名称为:' + item.name);
  }

  _renderItem = ({item,index}) => {
    return (
      <TouchableOpacity
        activeOpacity={0.5}
        onPress={this.itemClick.bind(this,item,index)}>
        <Text style={flatListStyles.item}>{item.name}</Text>
      </TouchableOpacity>
    );
  }

  //点击按钮跳转
  onButtonPress() {
    //viewPosition参数:0表示顶部,0.5表示中部,1表示底部
    this._flatList.scrollToIndex({viewPosition: 0,index: this.state.text});
    //this._flatList.scrollToOffset({ animated: true,offset: 2000 });
  };

  onBtnPress2Botton() {
    this._flatList.scrollToEnd();
  }

  _sourceData = [
    {name: '大护法'},{name: '绣春刀II:修罗战场'},{name: '神偷奶爸3'},{name: '神奇女侠'},{name: '摔跤吧,爸爸'},{name: '悟空传'},{name: '闪光少女'},{name: '攻壳机动队'},{name: '速度与激情8'},{name: '蝙蝠侠大战超人'},{name: '蝙蝠侠大战超人'}
  ]

  _newData = [{name: '我是新添加的数据1'},{name: '我是新添加的数据2'},{name: '我是新添加的数据3'}]

  render() {
    return (
      <View style={flatListStyles.container}>
        <View style={{flexDirection: 'row',justifyContent: 'center',alignItems: 'center'}}>
          <TextInput
            style={{flex: 1}}
            placeholder="请输入要跳转的行号"
            onChangeText={(text) => this.setState({text})}
          />
          <Button title="跳转到行" onPress={this.onButtonPress.bind(this)} color={'skyblue'}/>
          <Button title="跳转到底部" onPress={this.onBtnPress2Botton.bind(this)} color={'green'}/>

        </View>
        <FlatList
          data={this.state.data}
          //使用 ref 可以获取到相应的组件
          ref={(flatList) => this._flatList = flatList}
          ListHeaderComponent={this._header}//header头部组件
          ListFooterComponent={this._footer}//footer尾部组件
          ItemSeparatorComponent={ItemDivideComponent}//分割线组件
          //空数据视图,可以是React Component,也可以是一个render函数,或者渲染好的element。
          ListEmptyComponent={this.createEmptyView()}
          keyExtractor={this._keyExtractor}
          //是一个可选的优化,用于避免动态测量内容尺寸的开销,不过前提是你可以提前知道内容的高度。
          //如果你的行高是固定的,getItemLayout用起来就既高效又简单.
          //注意如果你指定了SeparatorComponent,请把分隔线的尺寸也考虑到offset的计算之中
          getItemLayout={(data,index) => ( {length: 44,index} )}
          //决定当距离内容最底部还有多远时触发onEndReached回调。
          //注意此参数是一个比值而非像素单位。比如,0.5表示距离内容最底部的距离为当前列表可见长度的一半时触发。
          onEndReachedThreshold={0.1}
          //当列表被滚动到距离内容最底部不足onEndReachedThreshold的距离时调用
          onEndReached={({distanceFromEnd}) => (
            setTimeout(() => {
              this.setState((state) => ({
                data: state.data.concat(this._newData),}));
            },3000)
          )}
          refreshing={this.state.refreshing}
          onRefresh={() => {
            this.setState({refreshing: true})//开始刷新
            //这里模拟请求网络,拿到数据,3s后停止刷新
            setTimeout(() => {
              alert('没有可刷新的内容!');
              this.setState({refreshing: false});
            },3000);
          }}
          renderItem={this._renderItem}
        />
      </View>
    );
  }
}
;

class ItemDivideComponent extends Component {
  render() {
    return (
      <View style={{height: 1,backgroundColor: 'skyblue'}}/>
    );
  }
}
;

const flatListStyles = StyleSheet.create({
  container: {
    flex: 1,paddingTop: 22
  },item: {
    padding: 10,fontSize: 18,height: 44,},})

AppRegistry.registerComponent('AwesomeProject',() => FlatListTest);

结语

好了,关于FlatList基本的进阶内容都在这里了,我也是初学者,如果有什么错误或者疑问,还请不吝赐教! 我们下一篇再见!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom