question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

ListView does not render correctly when row moved to above the current scroll position

See original GitHub issue

For a ListView with multiple headers and enough data to scroll, if the list is scrolled to the bottom and an item is added at the top (above the viewable area), then the ListView renders rows and headers on top of each other (or sometimes just really close to each other). Also, there will be empty spaces where presumably one of those rows/headers belong.

Note that if you modify the example to either have 1 header or use cloneWithRows with no headers, the problem seems to go away.

This was not a problem in RN 0.25.1 but is a problem as of v0.31.0-rc.0. I tested on iPhone 6s, both simulator and real device.

To reproduce, run the following code on an iPhone 6s, scroll all the way to the bottom, and click on a row near the bottom, then scroll back up and feast your eyes on the disaster. For best results, click on a few rows.

componentWillMount: function() {
        this._listData = {
            "header 1": [
              "item 1",
              "item 2",
              "item 3",
              "item 4",
              "item 5",
              "item 6",
              "item 7",
              "item 8",
              "item 9",
              "item 10",
              "item 11",
              "item 12",
              "item 13",
              "item 14",
              "item 15",
              "item 16",
              "item 17",
              "item 18",
              "item 19",
              "item 20",
              "item 21",
              "item 22",
              "item 23",
              "item 24",
              "item 25",
              "item 26",
              "item 27",
              "item 28",
              "item 29",
            ],
            "header 2": [
              "item 30",
              "item 31",
              "item 32",
              "item 33",
              "item 34",
              "item 35",
              "item 36",
              "item 37",
              "item 38",
              "item 39",
              "item 40",
              "item 41",
              "item 42",
              "item 43",
              "item 44",
              "item 45",
              "item 46",
              "item 47",
              "item 48",
              "item 49",
              "item 50",
              "item 51",
              "item 52",
              "item 53",
              "item 54",
              "item 55",
              "item 56",
              "item 57",
              "item 58",
              "item 59",
            ],
        }
},

getInitalState: function() {
        return {
            ds: new ListView.DataSource( {
                        rowHasChanged: (r1, r2) => r1 !== r2,
                        sectionHeaderHasChanged: (s1, s2) => s1 !== s2
                        }
            ).cloneWithRowsAndSections(
                this._listData
            ),
        };
},

render: function() {
        return (
            <ListView
                dataSource = { this.state.ds }
                renderRow = {
                    ( rowData, sectionId, rowId, highlightRow ) =>
                    {
                        return (
                            <Text
                                onPress = {
                                    () => {
                                        this._listData = JSON.parse( JSON.stringify( this._listData ) );

                                        this._listData[sectionId].splice( rowId, 1 );

                                        let newSection = Object.keys( this._listData )[ 0 ];

                                        this._listData[newSection].unshift( rowData );

                                        this.setState(
                                            {
                                                ds: this.state.ds.cloneWithRowsAndSections( this._listData )
                                            }
                                        );
                                    }
                                }
                                style = {{padding:8}}
                            >
                                { rowData }
                            </Text>
                        );

                    }
                }
                renderSectionHeader = { ( sectionData, sectionId ) => { return ( <Text> { "HEADER:" + sectionId } </Text>) } }
            />
        );
},

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:2
  • Comments:9 (1 by maintainers)

github_iconTop GitHub Comments

4reactions
nicholeufcommented, Nov 8, 2016

Scrolling above the content is a good workaround, but any idea when this will be fixed?

2reactions
sharq1commented, Sep 5, 2016

When debugging ListView/ScrollView components led me nowhere I decided to hack around the problem. One way that worked was switching scroll component on renderScrollComponent attribute with each change that would lead to rendering error. This forced redraw of the whole list.

But the not-so-hacky workaround is just to scroll to the top of the list before actually modifying it, like so:

  componentWillReceiveProps(props) {
    this.refs.listview.scrollTo({y: 0})
    this._updateDataSource(props)
  }
Read more comments on GitHub >

github_iconTop Results From Across the Web

Maintain/Save/Restore scroll position when returning to a ...
Explanation: ListView.getFirstVisiblePosition() returns the top visible list item. But this item may be partially scrolled out of view, and if you want ...
Read more >
ListView Class (Windows.UI.Xaml.Controls) - UWP
For example, if you put a ListView inside of a ScrollViewer, you can't scroll the ScrollViewer with the mouse wheel when the pointer...
Read more >
ListView (GUI) - Syntax & Usage
When the phrase "row number" is used on this page, it refers to a row's current position within the ListView. The top row...
Read more >
ListView class - widgets library
ListView is the most commonly used scrolling widget. It displays its children one after another in the scroll direction. In the cross axis,...
Read more >
Slow rendering
To fix jank, inspect which frames aren't completing in 16.7ms, and look for what is going wrong. Is Record View#draw taking abnormally long...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found