A drop-in replacement for React Native's ListView
.
It supports Immutable data out-of-the-box to give you faster performance 🐎 and less headaches 🤕.
- Do you find yourself re-implementing
rowHasChanged
and savingdataSource
to your state over and over? - Do you use Immutable data, only to write wrappers for data access in order to use them with a ListView?
- Do you listen for lifecycle events simply so you can update
dataSource
-- and thus you can't easily use pure functional components with lists? - Do you have nested objects in your state so a shallow diff won't cut it for pure rendering?
- Do you use a navigator and want better performance while animating?
If you answered yes to ANY of these questions, this project will surely be of help. Check out the examples below!
npm install --save react-native-immutable-list-view
import ImmutableListView from 'react-native-immutable-list-view';
ImmutableListView
supports all the props of React Native's ListView,
but instead of passing in a dataSource
, you should should pass in a prop called immutableData
consisting of the data you'd like to display. ImmutableListView
will handle creating an efficient dataSource
for you.
Other than this small change, everything else will be exactly the same as ListView
.
There's an example app here if you'd like to see it in action; have a look at the example diff below if you want to implement it yourself.
You can remove all that boilerplate in your constructor, as well as methods like
componentWillReceiveProps
if all they're doing is updating your dataSource
.
ImmutableListView
will handle this for you. Check out this example diff:
Note: it looks much better on GitHub than on npm's site.
-import { Text, View, ListView } from 'react-native';
+import { Text, View } from 'react-native';
+import ImmutableListView from 'react-native-immutable-list-view';
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 <Text style={style.header}>{category}</Text>;
}
render() {
return (
<View style={style.container}>
<Text style={style.welcome}>
Welcome to React Native!
</Text>
- <ListView
- dataSource={this.state.dataSource}
+ <ImmutableListView
+ immutableData={listData}
renderRow={this.renderRow}
renderSectionHeader={this.renderSectionHeader}
/>
</View>
);
}
}
All the props that React Native's ListView
supports are passed through, and should work exactly the same.
Prop name | Data type | Default value? | Description |
---|---|---|---|
immutableData |
Immutable.Iterable |
Required. | The data to render. |
rowsDuringInteraction |
number |
undefined |
How many rows of data to initially display while waiting for interactions to finish (e.g. Navigation animations). If unspecified, this will not have any effect. |
sectionHeaderHasChanged |
func |
(prevSectionData, nextSectionData) => false |
Return true if your section header is dependent on your row data (uncommon). See ListViewDataSource#constructor for more info. |
Simple, right?
ImmutableListView
accepts several standard formats
for list data. Here are some examples:
[ <rowData1>, <rowData2>, ... ]
{
section1: [
<rowData1>,
<rowData2>,
...
],
...
}
{
section1: {
rowID_1: <rowData1>,
rowID_2: <rowData2>,
...
},
...
}
To try it out yourself, you can use the example app!
When using section headers, ImmutableListView
treats certain types of Immutable.Map
slightly differently
than ListView
treats an equivalent plain JS Map
. See the snapshot test output
here
for an example of how ImmutableListView
behaves.
It seems based on the current documentation
that ImmutableListView
is behaving as expected, and in fact regular ListView
is the one being weird.
In any case, you should make sure to test this behavior yourself if you're using a Map
with section headers.
Other than this, the two should behave identically. You can verify this with the unit tests here.
- Fork it!
- Create your feature branch:
git checkout -b my-new-feature
- Commit your changes:
git commit -am 'Add some feature'
- Push to the branch:
git push origin my-new-feature
- Submit a pull request :D