According to the official documentation, rn’s native-provided components that enable scrolling lists include scrollView, FlatList, and SectionList. However, the native components provided by the authorities have had various problems, so this article will also recommend a third-party implementation of the scrolllist component and briefly explain how to use it.
1. The ScrollView and FlatList
The obvious drawback of ScrollView is that it renders all list items, both visible and invisible, which naturally creates an obvious problem. When a list is a long list with many items, performance issues become very significant. One solution to this problem is to control the number of items rendered in a ScrollView. This requires you to use JS to determine which items to display, when to add new items, and when to remove items that are not displayed. If the items are still irregular, such as the height is dynamically variable, You also need to consider the performance impact of view object creation and collection, which can be very complicated to implement yourself. Another relatively simple option is to use the official long-list component FlatList. The official documentation gives a recommendation: render visible items first, not all. To use the FlatList component, you must provide the data and renderItem attributes:
import React, { Component } from "react";
import { FlatList, StyleSheet, Text, View } from "react-native";
export default class FlatListDemo extends Component {
renderItem = ({ item }) => {
return <Text style={styles.item}>{item.key}</Text>;
}
render () {
return (
<View style={styles.container}>
<FlatList
data={[
{ key: "Zhang" },
{ key: "Bill" },
{ key: "Fifty" },
]}
renderItem={this.renderItem}
/>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 22,
},
item: {
padding: 10,
fontSize: 18,
height: 44,
}
});
Copy the code
FlatList biggest advantage is the long list of scenarios of high performance, but in actual measurement, the part of the android will also exist in old type obviously card phenomenon, the reason is that the fast scroll needs a large number of deleted and new list item object, is the need to consume a large amount of computation and memory performance, so there is not smooth on the part of the old android models to the problem. The description article provided by the big guy in the group can refer to here.
2. SectionList
If the data to be rendered is grouped, the SectionList component is officially recommended.
import React, { Component } from "react";
import { SectionList, StyleSheet, Text, View } from "react-native";
export default class SectionListDemo extends Component {
defaultValues = {
sections: [
{
title: "Fruit",
data: [The word "apple"."Banana"."Pineapple"]
},
{
title: "Dairy products",
data: ["Yogurt"."Pure milk"."Walnut milk"]]}}; renderItem = ({ item }) => {return <Text style={styles.item}>{item}</Text>;
};
renderSectionHeader = ({ section }) => {
return <Text style={styles.sectionHeader}>{section.title}</Text>;
};
render() {
return (
<View style={styles.container}>
<SectionList
sections={this.defaultValues.sections}
renderItem={this.renderItem}
renderSectionHeader={this.renderSectionHeader}
keyExtractor={({ item, index}) => index}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 22
},
sectionHeader: {
paddingTop: 2,
paddingLeft: 10,
paddingRight: 10,
paddingBottom: 2,
fontSize: 14,
fontWeight: "bold",
backgroundColor: "Rgba (247247247,1.0)"
},
item: {
padding: 10,
fontSize: 18,
height: 44
}
});
Copy the code
3. recycler-list-view
This is a third party RN scrolllist component that the author describes as follows:
RecyclerListView uses “cell recycling” to reuse views that are no longer visible to render items instead of creating new view objects. Creation of objects is very expensive and comes with a memory overhead which means as you scroll through the list the memory footprint keeps going up. Releasing invisible items off memory is another technique but that leads to creation of even more objects and lot of garbage collections. Recycling is the best way to render infinite lists that does not compromise performance or memory efficiency.
They’ve used a concept called cell recycling to replace the traditional method of destroying invisible items and creating new view objects by adding them. ** Since creating objects is a very performance intensive operation, this means that you can consume a lot of memory when scrolling through lists quickly. Reclaiming view objects of invisible elements is a wasteful activity in the author’s view. Continuous destruction leads to continuous creation. Therefore, the author can improve performance by reusing existing view objects to reduce creation and destruction operations. Those who are interested can check out the details here.
The core of recyclerlistView component is to understand the three necessary properties dataProvider, layoutProvider and rowRenderer.
3.1 dataProvider
The dataProvider consists of two parts: the first is a new dataProvider instance that provides a parameter to compare whether two data are the same data, that is, whether they are the same object.
/** * The dataProvider must be provided to compare whether two rows of data are the same */letdataProvider = new DataProvider((r1, r2) => r1 ! == r2);Copy the code
We then use the cloneWithRows method of the DataProvider instance, passing in an array of data as arguments and returning a processed wrapped DataProvider instance object as the value of this.state. DataProvider. This value is finally passed to the dataProvider property of the RecyclerListView.
This. State = {dataProvider: dataProvider cloneWithRows (enclosing _generateArray (100)), / / a production contains a 100 element array}Copy the code
This part is processing the data.
3.2 layoutProvider
This part is dealing with the view elements. First, provide a view element type object, which is convenient for mapping view element categories later:
/** * const ViewTypes = {FULL: 0, HALF_LEFT: 1, HALF_RIGHT: 2,};Copy the code
Then new a LayoutProvider instance and provide two parameters.
/** * layoutProvider is also mandatory * param1: The first argument returns the item type according to the index, which corresponds to the default type in viewTypestypeParam2: The second parameter is based ontypeDataProvider = / this._layoutProvider = new LayoutProvider(index => {LayoutProvider = new LayoutProvider(index => {LayoutProvider = new LayoutProvider)if (index % 3 === 0) {
return ViewTypes.FULL;
} else if (index % 3 === 1) {
return ViewTypes.HALF_LEFT;
} else {
returnViewTypes.HALF_RIGHT; }},type, dim) => {
switch (type) {
case ViewTypes.FULL:
dim.width = width;
dim.height = 140;
break;
case ViewTypes.HALF_LEFT:
dim.width = width / 2;
dim.height = 160;
break;
case ViewTypes.HALF_RIGHT:
dim.width = width / 2;
dim.height = 160;
break; default: dim.width = 0; dim.height = 0; }})Copy the code
As you can see, the first argument returns the ViewTypes of the data element based on type, and the second argument does the processing of the view element based on the element’s ViewTypes.
3.3 rowRenderer
This thing is easy to understand. First of all, it returns the view element of the list item, and you can define what kind of view you want to return.
/ * * *typeData returns the view component * here you can base on demandtypeReturn different view elements */ _rowRenderer (type, data) {// We can return any view here, CellContainer class has no special meaning here switch (type) {
case ViewTypes.FULL:
return (
<CellContainer style={styles.container}>
<Text>Data: {data}</Text>
</CellContainer>
);
case ViewTypes.HALF_LEFT:
return (
<CellContainer style={styles.containerGridLeft}>
<Text>Data: {data}</Text>
</CellContainer>
);
case ViewTypes.HALF_RIGHT:
return (
<CellContainer style={styles.containerGridRight}>
<Text>Data: {data}</Text>
</CellContainer>
);
default:
returnnull; }}Copy the code
The CellContainer used here has no special meaning and is completely custom.
4. A simple example of recycler-list-view use
Examples of use refer to the official demo, add some notes to help understand, personal feeling or according to the example to write again, can more quickly master the basic usage:
import React, { Component } from 'react';
import { View, Text, Dimensions } from "react-native";
import { RecyclerListView, DataProvider, LayoutProvider } from "recyclerlistview"; /** * const ViewTypes = {FULL: 0, HALF_LEFT: 1, HALF_RIGHT: 2,};letcontainerCount = 0; /** * class CellContainer extends Component {constructor (props) {super(props); this._containerId = containerCount++; }render () {
return( <View {... This. Props} > {this.props. Children}< Text> cell ID: {this._containerid}</Text> </View>)}}export default class RecycleTestComponent extends Component {
constructor (props) {
super(props);
let { width } = Dimensions.get("window"); /** * The dataProvider must be provided to compare whether two rows of data are the same */letdataProvider = new DataProvider((r1, r2) => r1 ! == r2); /** * layoutProvider is also mandatory * param1: The first argument returns the item type according to the index, which corresponds to the default type in viewTypestypeParam2: The second parameter is based ontypeDataProvider = / this._layoutProvider = new LayoutProvider(index => {LayoutProvider = new LayoutProvider(index => {LayoutProvider = new LayoutProvider)if (index % 3 === 0) {
return ViewTypes.FULL;
} else if (index % 3 === 1) {
return ViewTypes.HALF_LEFT;
} else {
returnViewTypes.HALF_RIGHT; }},type, dim) => {
switch (type) {
case ViewTypes.FULL:
dim.width = width;
dim.height = 140;
break;
case ViewTypes.HALF_LEFT:
dim.width = width / 2;
dim.height = 160;
break;
case ViewTypes.HALF_RIGHT:
dim.width = width / 2;
dim.height = 160;
break; default: dim.width = 0; dim.height = 0; } } ) this._rowRenderer = this._rowRenderer.bind(this); This. State = {dataProvider: dataProvider cloneWithRows (enclosing _generateArray (100)), / / a production contains a 100 element array}} / * * *typeData returns the view component * here you can base on demandtypeReturn different view elements */ _rowRenderer (type, data) {// We can return any view here, CellContainer class has no special meaning here switch (type) {
case ViewTypes.FULL:
return (
<CellContainer style={styles.container}>
<Text>Data: {data}</Text>
</CellContainer>
);
case ViewTypes.HALF_LEFT:
return (
<CellContainer style={styles.containerGridLeft}>
<Text>Data: {data}</Text>
</CellContainer>
);
case ViewTypes.HALF_RIGHT:
return (
<CellContainer style={styles.containerGridRight}>
<Text>Data: {data}</Text>
</CellContainer>
);
default:
return null;
}
}
_generateArray (n) {
return new Array(n).fill(1).map((item, index) => index);
}
render () {
return (
<RecyclerListView
layoutProvider={this._layoutProvider}
dataProvider={this.state.dataProvider}
rowRenderer={this._rowRenderer}
></RecyclerListView>
)
}
}
const styles = {
container: {
justifyContent: "space-around",
alignItems: "center",
flex: 1,
backgroundColor: "#00a1f1"
},
containerGridLeft: {
justifyContent: "space-around",
alignItems: "center",
flex: 1,
backgroundColor: "#ffbb00"
},
containerGridRight: {
justifyContent: "space-around",
alignItems: "center",
flex: 1,
backgroundColor: "#7cbb00"}};Copy the code
These are just a few of the ways I know how to implement scrolling lists in Rn, and if there’s a better way to do it, feel free to leave a comment.