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.

List is not updated/rerendered unless scrolled far away and back

See original GitHub issue

I’m trying to display a checkbox alongside each row in the list. Upon clicking on the checkbox, I want it to -be selected/de-selected. I do this by updating the array element property. However, the row is not updated until I scroll far away and then scroll back. I also tried the extendedState prop but that did not help too.

checkboxSelected(item) {
    item.selected = !item.selected
}

<Checkbox checked={!!item.selected} onPress={this.checkboxSelected.bind(this, item)} />

Any help would be much appreciated. Thanks

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:4
  • Comments:12

github_iconTop GitHub Comments

5reactions
AbdallaElabdcommented, Aug 13, 2018

@sksin28 The problem is, you’re mutating the object directly, instead of making a new object. That means that the reference is the same

listItem.selected = !listItem.selected

And when the rowHasChanges runs, it won’t see that there are any changes.

const row1 = {
  label: 'First Row',
  selected: false
}

// This is where the issue is
row1.selected = true;

Instead, you should be making a new object

const row 2 = {
  ...row,
  selected: true
}

So, in your code:

this.setState(prevState => {
  return {
    list: _.map(prevState.list, listItem => {
       if (listItem.name === item.name) {
         // Here, you should return a new object.
         return {
            ...listItem,
            listItem.selected = !listItem.selected
           };
        }
        return listItem;
    })
  };
});
2reactions
sksin28commented, Aug 15, 2018

@rasanu This is how I got it going in my case.

class MyList extends Component {
    constructor(props) {
        super(props);
        let list = [{name:'a', selected:false}, {name:'b', selected:false}, {name:'c', selected:false}];

        const { width } = Dimensions.get('window');


        this._dataProvider = new DataProvider((r1, r2) => {
            return r1.name !== r2.name || (r1.name === r2.name && r1.selected !== r2.selected);
        });

        this._layoutProvider = new LayoutProvider(
            index => {
                return 1;
            },
            (type, dim) => {
                dim.width = width;
                dim.height = 120;
            }
        );

        this.state = {
            list,
            dataProvider: this._dataProvider.cloneWithRows(list)
        };
    }

    _rowRenderer(type, item) {
        return (
            <View>
                <CardItem>
                    <Body>
                        <Text>{item.name}</Text>
                    </Body>
                    <Right>
                        <CheckBox checked={!!item.selected} onPress={this.checkboxSelect.bind(this, item)} />
                    </Right>
                </CardItem>
            </View>
        );
    }

    checkboxSelect(item) {
        this.setState(prevState => {
            return {
                list: _.map(prevState.list, listItem => {
                    if (listItem.name === item.name) {
                        return {
                            ...listItem,
                            selected: !listItem.selected
                        };
                    }
                    return listItem;
                })
            };
        });
    }

    render() {
        return (
            <RecyclerListView
                layoutProvider={this._layoutProvider}
                dataProvider={this.state.dataProvider.cloneWithRows(this.state.list)}
                rowRenderer={this._rowRenderer.bind(this)}
            />
        );
    }
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Avoid rerendering every component in list while updating only ...
When the messages state updates it's a new array, and so it must be rerendered. React's reconciliation needs to rerender the array and...
Read more >
How to stop re-rendering lists in React? - Alex Sidorenko
Components always re-render. First, let's simplify our example by removing all props from the Item . We will still update the parent state...
Read more >
Understanding how and when SwiftUI decides to redraw views
Another issue that I investigated is one where scrolling performance suffered greatly when just one or two items in a list were updated....
Read more >
overscroll-behavior - CSS: Cascading Style Sheets | MDN
The overscroll-behavior CSS property sets what a browser does when reaching the boundary of a scrolling area.
Read more >
Usage | FlashList
Switch from FlatList to FlashList and render the list once. ... If this isn't provided initialScrollIndex might not scroll to the provided ...
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