:scroll: Drop-in replacement for ListView, FlatList, and VirtualizedList.
Drop-in replacement for React Native's
ListView,
FlatList, and
VirtualizedList.
It supports Immutable.js to give you faster performance and less headaches.
If you answered yes to ANY of these questions, this project can help. Check out the examples below.
For FlatList and VirtualizedList:
For ListView (deprecated as of React Native v0.59):
The screenshot above shows two different lists. The first uses this data:
Immutable.fromJS({ 'Section A': [ 'foo', 'bar', ], 'Section B': [ 'fizz', 'buzz', ], })
The second list is even simpler:
Immutable.Range(1, 100)
There's an example app here if you'd like to see it in action.
Install:
Import it in your JS:
For FlatList and VirtualizedList:
import { ImmutableVirtualizedList } from 'react-native-immutable-list-view';
For ListView:
import { ImmutableListView } from 'react-native-immutable-list-view/lib/ImmutableListView';
Goodbye,
keyExtractorboilerplate!
Note: This example diff looks much better on GitHub than on npm's site. Red means delete, green means add.
-import { Text, View, FlatList } from 'react-native'; +import { Text, View } from 'react-native'; +import { ImmutableVirtualizedList } from 'react-native-immutable-list-view';import style from './styles'; import listData from './listData';
class App extends Component {
renderItem({ item, index }) { return {item}; }
render() { return ( Welcome to React Native!
<flatlist data="{listData}" getitem="{(items," index> items.get(index)}
getItemCount={(items) => items.size}
keyExtractor={(item, index) => String(index)}
<immutablevirtualizedlist immutabledata="{listData}" renderitem="{this.renderItem}"></immutablevirtualizedlist>
</flatlist></view>
);
}}
You can remove all that boilerplate in your constructor, as well as lifecycle methods like
componentWillReceivePropsif all they're doing is updating your
dataSource.
ImmutableListViewwill handle all of this for you.
Note: This example diff looks much better on GitHub than on npm's site. Red means delete, green means add.
-import { Text, View, ListView } from 'react-native'; +import { Text, View } from 'react-native'; +import { ImmutableListView } from 'react-native-immutable-list-view/lib/ImmutableListView';import style from './styles'; import listData from './listData';
class App extends Component {
constructor(props) {
super(props);
const dataSource = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2,
sectionHeaderHasChanged: (s1, s2) => s1 !== s2,
});
const mutableData = listData.toJS();
this.state = {
dataSource: dataSource.cloneWithRowsAndSections(mutableData),
};
}
componentWillReceiveProps(newProps) {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(newProps.listData),
});
}
renderRow(rowData) {
return <text style="{style.row}">{rowData}</text>;
}
renderSectionHeader(sectionData, category) { return {category}; }
render() { return (
<view style="{style.container}">
<text style="{style.welcome}">
Welcome to React Native!
</text>
<listview datasource="{this.state.dataSource}" immutabledata="{listData}" renderrow="{this.renderRow}" rendersectionheader="{this.renderSectionHeader}"></listview>
</view>
); }
}
All the props supported by React Native's underlying List are simply passed through, and should work exactly the same. You can see all the VirtualizedList props or ListView props on React Native's website.
You can customize the look of your list by implementing
renderItemfor FlatList and VirtualizedList or
renderRowfor ListView.
Here are the additional props that
ImmutableVirtualizedListand
ImmutableListViewaccept:
| Prop name | Data type | Default value? | Description | |-----------|-----------|----------------|-------------| |
immutableData| Any
Immutable.Iterable| Required. | The data to render. See below for some examples. | |
rowsDuringInteraction|
number|
undefined| How many rows of data to initially display while waiting for interactions to finish (e.g. Navigation animations). | |
sectionHeaderHasChanged|
func|
(prevSectionData, nextSectionData) => false| Only needed if your section header is dependent on your row data (uncommon; see
ListViewDataSource's constructor for details). | |
renderEmpty|
stringor
func|
undefined| If your data is empty (e.g.
null,
[],
{}) and this prop is defined, then this will be rendered instead. Pull-refresh and scrolling functionality will be lost. Most of the time you should use
renderEmptyInListinstead. | |
renderEmptyInList|
stringor
func|
'No data.'| If your data is empty (e.g.
null,
[],
{}) and this prop is defined, then this will be rendered instead. Pull-refresh and scrolling functionality will be kept! See below for more details. |
Also see React Native's
FlatListExamplefor more inspiration.
Methods such as
scrollToEndare passed through just like the props described above. You can read about them here for ListView or here for FlatList and VirtualizedList.
The references to the raw
VirtualizedListor
ListViewcomponent are available via
getVirtualizedList()or
getListView(). These references allow you to access any other methods on the underlying List that you might need.
ImmutableListViewaccepts several standard formats for list data. Here are some examples:
[rowData1, rowData2, ...]
{ section1: [ rowData1, rowData2, ... ], ... }
{ section1: { rowId1: rowData1, rowId2: rowData2, ... }, ... }
To try it out yourself, you can use the example app!
Support is coming soon for section headers with
ImmutableVirtualizedListtoo, similar to
SectionList. See PR #34.
The optional
renderEmptyInListprop takes a string and renders an Immutable List displaying the text you specified. By default, this text is simply
No data., but you can customize this based on your state. For example:
render() { const emptyText = this.state.isLoading ? "Loading..." : this.state.errorMsg ? "Error!" : "No data.";return ( ); }
The empty list will receive all the same props as your normal list, so things like pull-to-refresh will still work.