ReactNative's FlatList usage and pitfall encapsulation summary,

Source: Internet
Author: User

ReactNative's FlatList usage and pitfall encapsulation summary,

In rn, FlatList is a high-performance list component, which is an upgraded version of the ListView component and greatly improves the performance. Of course, we recommend that you use FlatList when implementing the list function, do not use ListView, or ScrollView. As for FlatList, let's first review the functions it supports.

  1. Fully cross-platform.
  2. Supports horizontal layout.
  3. Callback events can be configured when the row component is displayed or hidden.
  4. Supports separate header components.
  5. Separate tail components are supported.
  6. Supports custom line separation between rows.
  7. Supports pull-down refresh.
  8. Supports up-pull loading.
  9. You can jump to a specified row (ScrollToIndex ).

This article does not detail how to use it. If you want to know how to use it, please refer to some examples of my GitHub https://github.com/xiehui999/helloreactnative. This article mainly introduces the big pitfall during my use and the secondary encapsulation of the FlatList.

Next, let's take a simple example. This example is also available in our article.

<FlatList data = {this. state. dataList} extraData = {this. state} refreshing = {this. state. isRefreshing} onRefresh = {() => this. _ onRefresh ()} keyExtractor = {(item, index) => item. id} ItemSeparatorComponent = {() => <View style = {height: 1, backgroundColor: '# D6D6D6' }}/ >} renderItem = {this. _ renderItem} ListEmptyComponent = {this. emptyComponent} // defines the empty layout. emptyComponent = () =>{ return <View style = {height: '000000', alignItems: 'center', justifyContent: 'center' ,}> <Text style ={{ fontSize: 16 }}> no data pull-down refresh </Text> </View>}

In the above Code, we mainly look at ListEmptyComponent, which indicates the layout of filling when no data is available. Generally, a prompt message is displayed in the middle, to facilitate the introduction, a data-free pull-down refresh is displayed. The above Code seems to have no data center display, but after running it, you are dumpfounded, and no data is displayed in the middle of the top. At this time, the height of 100% does not produce any effect. Of course, you try to use flex: 1 to fill the High View of the View with the remaining full screen, but it still does not work.

So why is it ineffective? If you are curious, let's take a look at the source code. The source code path is react-native --> Libraries --> Lists. All components in the list are in this directory. We first go to the FlatList file to search for the keyword ListEmptyComponent. If this component is not used, go to render.

 render() {  if (this.props.legacyImplementation) {   return (    <MetroListView     {...this.props}     items={this.props.data}     ref={this._captureRef}    />   );  } else {   return (    <VirtualizedList     {...this.props}     renderItem={this._renderItem}     getItem={this._getItem}     getItemCount={this._getItemCount}     keyExtractor={this._keyExtractor}     ref={this._captureRef}     onViewableItemsChanged={      this.props.onViewableItemsChanged && this._onViewableItemsChanged     }    />   );  } }

MetroListView (the internal implementation is ScrollView) is the old ListView implementation method, and the VirtualizedList is a new implementation with better performance. Let's go to this file

// Some code const itemCount = this is omitted. props. getItemCount (data); if (itemCount> 0 ){.... omitted code} else if (ListEmptyComponent) {const element = React. isValidElement (ListEmptyComponent )? ListEmptyComponent // $ FlowFixMe: <ListEmptyComponent/>; cells. push (/* $ FlowFixMe (> = 0.53.0 site = react_native_fb, react_native_oss) This * comment suppresses an error when upgrading Flow's support for React. * To see the error delete this comment and run Flow. */<View key = "$ empty" onLayout = {this. _ onLayoutEmpty} style = {inversionStyle }>{ element} </View> ,);}

Here we can see that the ListEmptyComponent has a level of view, and the view adds the style inversionStyle.

Const inversionStyle = this. props. inverted? This. props. horizontal? Styles. horizontallyInverted: styles. verticallyInverted: null; style: verticallyInverted: {transform: [{scaleY:-1}] ,}, horizontallyInverted: {transform: [{scaleX:-1}] ,},

The above style is added with an animation without setting the height. Therefore, we use height: '000000' or flex: 1 in ListEmptyComponent.

To achieve the desired effect, we need to set the height to a specific value. How big is the value set? If you set a style for the FlatList and set a color for the background property, it is found that the FlatList has a default height (flex: 1) that occupies the remaining screen ). In this case, we can set the view height in ListEmptyComponent to the FlatList height. To obtain the FlatList height, we can get it through onLayout.

Code adjustment:

// Create the variable fHeight = 0; <FlatList data = {this. state. dataList} extraData = {this. state} refreshing = {this. state. isRefreshing} onRefresh = {() => this. _ onRefresh ()} keyExtractor = {(item, index) => item. id} ItemSeparatorComponent = {() => <View style = {height: 1, backgroundColor: '# D6D6D6' }}/ >} renderItem = {this. _ renderItem} onLayout = {e => this. fHeight = e. nativeEvent. layout. height} ListEmptyComponent = {this. emptyComponent} // defines the empty layout emptyComponent = () =>{ return <View style = {height: this. fHeight, alignItems: 'center', justifyContent: 'center', }}> <Text style ={{ fontSize: 16 }}> no data </Text> </View>}

Through the above adjustment, we found that the running on Android has achieved the desired effect, but on iOS, It is uncontrollable, occasionally center display, and occasionally display to the top. The reason is that the onLayout call time on iOS is slightly different from that on Android (the onLayout has no callback when emptyComponent rendering occurs in iOS, and fHeight has no value yet ).

So in order to apply the changed value to emptyComponent, we set the fHeight to the state.

state={  fHeight:0}onLayout={e => this.setState({fHeight: e.nativeEvent.layout.height})}

This setting should be perfect, but we can still achieve the perfect effect on android, and there is a problem of flashing back and forth on iOS. Print the log and find that the value is always 0 and the measured value is converted back and forth. Here we only need to be the measured value, so we modify onLayout

           onLayout={e => {             let height = e.nativeEvent.layout.height;             if (this.state.fHeight < height) {               this.setState({fHeight: height})             }           }}

After processing, we finally achieved the perfect effect on ios.

In addition to the above pitfalls, I personally feel that there is also a pitfall that is onEndReached. if we implement the drop-down function, we will use this attribute. When we mention it, we will certainly mention onEndReachedThreshold, in the FlatList, onEndReachedThreshold is a number type, which indicates that onEndReached is triggered when there are multiple distances at the bottom. Note that the meanings of onEndReachedThreshold in FlatList and ListView are different, in ListView, onEndReachedThreshold indicates the number of pixels at the bottom of the page that triggers onEndReached. The default value is 1000. FlatList indicates a multiple (also called a ratio, not a pixel). The default value is 2.

We can see the following implementation according to the general rule:

      <FlatList        data={this.state.dataList}        extraData={this.state}        refreshing={this.state.isRefreshing}        onRefresh={() => this._onRefresh()}        ItemSeparatorComponent={() => <View style={{          height: 1,          backgroundColor: '#D6D6D6'        }}/>}        renderItem={this._renderItem}        ListEmptyComponent={this.emptyComponent}        onEndReached={() => this._onEndReached()}        onEndReachedThreshold={0.1}/>

Then we add the following code to componentDidMount:

  componentDidMount() {    this._onRefresh()  }

That is to say, start loading the first page of data. In the drop-down list, execute onEndReached to load more data and update the data source dataList. It looks perfect, ..... after running the command, you will find that onEndReached has been called cyclically (or executed multiple times) until all data is loaded. You may have guessed the reason because _ onRefresh takes time to load data, the render method is executed before the data request arrives. Because there is no data at this time, the onEndReached method is executed once, which is equivalent to loading the data twice.

The onEndReachedThreshold value is required for the number of onEndReached executions. Therefore, we must set onEndReachedThreshold with caution. If you understand it as setting pixels, you must set it to a relatively large number, for example, 100 is finished .... in my opinion, setting 0.1 is a good value.

Through the above analysis, I personally feel that it is necessary to perform a secondary encapsulation of the FlatList. According to my own needs, I performed a secondary encapsulation.

Import React, {Component,} from 'react 'import {FlatList, View, StyleSheet, ActivityIndicator, Text} from 'react-native' import PropTypes from 'prop-types '; export const FlatListState = {IDLE: 0, LoadMore: 1, Refreshing: 2}; export default class Com extends Component {static propTypes = {refreshing: PropTypes. oneOfType ([PropTypes. bool, PropTypes. number]),}; state = {listHeight: 0,} render () {v Ar {ListEmptyComponent, parts} = this. props; var refreshing = false; var emptyContent = null; var parts = null if (ListEmptyComponent) {emptyContent = React. isValidElement (ListEmptyComponent )? ListEmptyComponent: <ListEmptyComponent/>} else {emptyContent = <Text style = {styles. emptyText}> no data pull-down refresh </Text>;} if (ItemSeparatorComponent) {separatorComponent = React. isValidElement (ItemSeparatorComponent )? ItemSeparatorComponent: <ItemSeparatorComponent/>} else {separatorComponent = <View style = {height: 1, backgroundColor: '# D6D6D6' }}/>;} if (typeof this. props. refreshing = "number") {if (this. props. refreshing === FlatListState. refreshing) {refreshing = true} else if (typeof this. props. refreshing = "boolean") {refreshing = this. props. refreshing} else if (typeof this. props. refreshing! = "Undefined") {refreshing = false} return <FlatList {... this. props} onLayout = {(e) => {let height = e. nativeEvent. layout. height; if (this. state. listHeight 

In propTypes, we use oneOfType to limit the refreshing type. If ListEmptyComponent is defined, the refreshing type is defined by using custom View. Similarly, ItemSeparatorComponent can also be customized.

A ListFooterComponent is defined during data loading from the drop-down menu, which indicates that the user is loading data. If the refreshing attribute is boolean, it indicates that the drop-down loading function is not available. If the refreshing attribute is number, pageSize must be passed, whether the remainder of the data source length and pageSize is equal to 0 to determine whether more data exists (more data is available only when the last request data is equal to pageSize, and onEndReached is not required if the data size is smaller ). Of course, the above Code is also very simple, I believe it is easy to understand, other will not be introduced. The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.