Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React-native and Firebase ListView integration

I've a problem integrating the Firebase with React-Native. The code below doesn't generate a listview as I expected. My assumption is that messages.val() doesn't return a correct format. When I try to console log "messages" variable it returns as follow

Object {text: "hello world", user_id: 1}

Code :

class Test extends Component {

    constructor(props) {
        super(props);
        this.state = {
            dataSource: new ListView.DataSource({
               rowHasChanged: (row1, row2) => row1 !== row2
            })
        };
    }

    componentWillMount() {
        this.dataRef = new Firebase("https://dummy.firebaseio.com/");
        this.dataRef.on('child_added', function(snapshot){
            var messages = snapshot.val();
            this.setState({
                dataSource: this.state.dataSource.cloneWithRows(messages)
            });       
        }.bind(this));
    }

    renderRow(rowData, sectionID, rowID) {
        console.log(this.state.dataSource);
        return (
            <TouchableHighlight
            underlayColor='#dddddd'>
                <View>
                    <Text>{rowData.user_id}</Text>
                    <Text>{rowData.text}</Text>
                </View>
            </TouchableHighlight>
        )
    }

    render() {
        return (
            <View>
                <ListView
                  dataSource={this.state.dataSource}
                  renderRow={this.renderRow.bind(this)}
                  automaticallyAdjustContentInsets={false} />
            </View>    
        );
    }

}
like image 368
Ittikorn S. Avatar asked Sep 23 '26 01:09

Ittikorn S.


1 Answers

I do not know what data you have in your Firebase database, but from what I understand, you should get multiple "on_child_added" events for all items you have, so you should not pass it to "cloneWithRows" method. You should pass the whole dataset to it.

While the documentation on react native side is a bit "silent" currently about how the ListView data source works and what should be passed to "cloneWithRows", documentation in the code (ListViewDataSource.js) is pretty good in fact, and it's explicit, that you should always provide full data set to "cloneWithRows" method (similarly to view reconciliation, the datasource will automatically calculate the difference and only modify the data that has actually changed).

Also, there is a very good write-up by @vjeux on why they implemented ListView the way they did, including explaining the optimisation strategies they chose (different than iOS's UITableView).

So in your case you should rather accumulate all the rows somewhere else and only pass the whole array of messages to cloneWithRows or relay on the incremental behaviour of cloneWithRows and continuously append the incoming elements to cloneWithRows as they come as in below example (it's supposed to be fast so give it a try).

The documentation copy&paste from ListViewDataSource.js:

/**
 * Provides efficient data processing and access to the
 * `ListView` component.  A `ListViewDataSource` is created with functions for
 * extracting data from the input blob, and comparing elements (with default
 * implementations for convenience).  The input blob can be as simple as an
 * array of strings, or an object with rows nested inside section objects.
 *
 * To update the data in the datasource, use `cloneWithRows` (or
 * `cloneWithRowsAndSections` if you care about sections).  The data in the
 * data source is immutable, so you can't modify it directly.  The clone methods
 * suck in the new data and compute a diff for each row so ListView knows
 * whether to re-render it or not.
 *
 * In this example, a component receives data in chunks, handled by
 * `_onDataArrived`, which concats the new data onto the old data and updates the
 * data source.  We use `concat` to create a new array - mutating `this._data`,
 * e.g. with `this._data.push(newRowData)`, would be an error. `_rowHasChanged`
 * understands the shape of the row data and knows how to efficiently compare
 * it.
 *
 * ```
 * getInitialState: function() {
 *   var ds = new ListViewDataSource({rowHasChanged: this._rowHasChanged});
 *   return {ds};
 * },
 * _onDataArrived(newData) {
 *   this._data = this._data.concat(newData);
 *   this.setState({
 *     ds: this.state.ds.cloneWithRows(this._data)
 *   });
 * }
 * ```
 */
like image 143
Jarek Potiuk Avatar answered Sep 24 '26 20:09

Jarek Potiuk