Recyclerlistview: Scroll offset not preserve when update re-render

Created on 7 Jan 2021  路  5Comments  路  Source: Flipkart/recyclerlistview

Currently i face an issue whereby the scroll not preserve but jump to previous few item offset when re-render the view

Most helpful comment

Below is the code, the scroll keep offset to top when i change the checkbox state. Is there any other solutions?

import React, {Component} from "react";
import {Dimensions, TouchableOpacity} from "react-native";
import {RecyclerListView, DataProvider, LayoutProvider} from "recyclerlistview";
import {View, Body, Grid, Icon, ListItem, Right, Row, Button} from "native-base";
import Colors from "../constants/Colors";
import {TextInput} from "react-native-paper";
import {Text} from '../components/Themed';
import {useNavigation} from "@react-navigation/native";

const ViewTypes = {
    FULL: 0,
    HALF_LEFT: 1,
    HALF_RIGHT: 2
};

export default function RecycleTestComponent(props) {
    const navigation = useNavigation();
    const {mode, isShowCheckbox, data} = props;

    const [selected_leave, set_selected_leave] = React.useState([]);
    let dataProviderTemplate = new DataProvider((r1, r2) => {
        return r1 !== r2;
    });
    console.log(data)
    const [dataProvider, setDataProvider] = React.useState(dataProviderTemplate.cloneWithRows(data));


    React.useEffect(() => {
        set_selected_leave([])
    }, [isShowCheckbox])

    const isChecked = (itemId) => {
        const isThere = selected_leave.includes(itemId);
        return isThere;
    };

    const pressItem = ({leave_item}) => {
        if (!isShowCheckbox) {
            navigation.navigate('LeaveApprovalDetailScreen', {
                mode: mode,
                leave_item: leave_item,
            })
        } else {

            if (selected_leave.includes(leave_item.leave_appl_group_id)) {
                set_selected_leave(selected_leave.filter(item => item !== leave_item.leave_appl_group_id));

            } else {
                set_selected_leave(prevState => [...prevState, leave_item.leave_appl_group_id])
            }
        }
    }



    let {width} = Dimensions.get("window");
    const _layoutProvider = new LayoutProvider(
        index => {
            return ViewTypes.FULL;
        },
        (type, dim) => {
            dim.width = width;
            dim.height = 180;
        }
    );

    const _rowRenderer = React.useCallback((type, leave_item) => {
        if (leave_item) {
            let attachment_arr = []
            for (var i = 0; i < leave_item.leave_attachment.length; i++) {
                attachment_arr = attachment_arr.concat(leave_item.leave_attachment[i]);
            }
            return (
                <TouchableOpacity onPress={() => pressItem({leave_item})}>
                    <View noIndent style={{
                        width: Dimensions.get("window").width,
                        padding: 10,
                        height:180,
                        flexDirection: 'row',
                        borderBottomColor: Colors.lightgrey,
                        borderBottomWidth: 1,
                        backgroundColor: (isChecked(leave_item.leave_appl_group_id)) ? Colors.lightgrey : null
                    }}
                          key={leave_item.leave_appl_group_id}
                    >
                        {/*Left*/}
                        <View style={{flex: 1, justifyContent: 'center', alignContent: 'center',}}>
                            <Row>
                                <View style={{
                                    borderRadius: 4,
                                    backgroundColor: leave_status_color(leave_item.leave_status),
                                    padding: 4,
                                    height: 24
                                }}>
                                    <Text style={{
                                        fontSize: 12,
                                        color: Colors.milk_white,
                                        fontWeight: "bold"
                                    }}>{leave_item.leave_status_label}</Text>
                                </View>
                            </Row>
                            <Row>
                                <Text ellipsizeMode={'tail'} style={{fontSize: 14}}><Text
                                    style={{
                                        fontWeight: 'bold',
                                        color: Colors.darkblue
                                    }}>{leave_item.employee_no} {leave_item.employee_name} </Text> </Text>
                            </Row>

                            <Row>
                                <Text ellipsizeMode={'tail'} numberOfLines={1} style={{
                                    fontSize: 14,
                                    fontWeight: 'bold',
                                    color: Colors.darkgrey
                                }}>({leave_item.leave_code}) - {leave_item.leave_name}
                                </Text>
                            </Row>
                            <Row style={{marginBottom: 4}}>
                                <View style={{
                                    borderRadius: 4,
                                    borderWidth: 0.5,
                                    borderColor: Colors.grey,
                                    padding: 5,
                                    height: 26
                                }}>
                                    <Text style={{
                                        fontSize: 12,
                                        color: Colors.darkgrey,
                                        fontWeight: 'bold'
                                    }}>{leave_item.leave_start}</Text>
                                </View>
                                <View style={{justifyContent: 'center'}}><Text
                                    style={{
                                        fontSize: 12,
                                        color: Colors.darkgrey
                                    }}> until </Text></View>
                                <View style={{
                                    borderRadius: 4,
                                    borderWidth: 0.5,
                                    borderColor: Colors.grey,
                                    padding: 5,
                                    height: 26

                                }}>
                                    <Text style={{
                                        fontSize: 12,
                                        color: Colors.darkgrey,
                                        fontWeight: 'bold'
                                    }}>{leave_item.leave_end}</Text>
                                </View>
                            </Row>
                            <Row>
                                <View style={{
                                    borderRadius: 4,
                                    backgroundColor: Colors.blue,
                                    padding: 4,
                                    height: 24

                                }}>
                                    <Text style={{
                                        fontSize: 12,
                                        color: Colors.milk_white,
                                        fontWeight: "bold",
                                    }}>{leave_item.interval_format}</Text>
                                </View>
                            </Row>
                            <Row style={{marginTop: 4}}>
                                {
                                    (attachment_arr.length > 0) ?
                                        <View style={{alignSelf: 'center'}}>
                                            <Icon type={'AntDesign'} name={'paperclip'}
                                                  style={{
                                                      fontSize: 18,
                                                      padding: 2,
                                                      color: Colors.blue,
                                                  }}/>
                                        </View>

                                        : null
                                }


                                {
                                    (parseInt(leave_item.leave_emergency) == 1) ?
                                        <View style={{
                                            borderRadius: 4,
                                            backgroundColor: Colors.red,
                                            padding: 4,
                                            height: 24,
                                            marginRight: 4,
                                            marginTop: 4
                                        }}>
                                            <Text style={{
                                                fontSize: 12,
                                                color: Colors.milk_white,
                                                fontWeight: "bold"
                                            }}>Emergency</Text>
                                        </View>
                                        : null
                                }
                                {
                                    (parseInt(leave_item.leave_advance) == 1) ?
                                        <View style={{
                                            borderRadius: 4,
                                            backgroundColor: Colors.darkgrey,
                                            padding: 4,
                                            height: 24,
                                            marginRight: 4,
                                            marginTop: 4
                                        }}>
                                            <Text style={{
                                                fontSize: 12,
                                                color: Colors.milk_white,
                                                fontWeight: "bold"
                                            }}>Advance</Text>
                                        </View>
                                        : null
                                }

                            </Row>
                        </View>
                        {/*Right*/}
                        <View style={{width: 30}}>
                            <Row>
                                <View>
                                    <Text><Icon type="MaterialCommunityIcons"
                                                name={(isChecked(leave_item.leave_appl_group_id)) ? "checkbox-marked" : "checkbox-blank-outline"}
                                                style={{color: Colors.darkgrey}}/></Text>
                                </View>

                            </Row>
                            <Row>
                                <View style={{
                                    alignItems: 'center',
                                    alignContent: 'center',
                                    justifyContent: 'center',
                                    width: 30,
                                    height: 30,
                                    backgroundColor: Colors.blue,
                                    borderRadius: 4,
                                }}>
                                    <Icon type={'Ionicons'} name={'md-chatbox-sharp'}
                                          style={{
                                              fontSize: 20,
                                              color: Colors.milk_white,
                                          }}/>
                                </View>
                            </Row>
                        </View>
                    </View>
                </TouchableOpacity>
            )
        }
    }, [selected_leave])

    return <RecyclerListView forceNonDeterministicRendering={true} layoutProvider={_layoutProvider}
                             dataProvider={dataProvider}
                             rowRenderer={_rowRenderer}/>;
}

const leave_status_color = (leave_status) => {
    switch (parseInt(leave_status)) {
        case 3:
        case 7:
        case 8:
            return Colors.orange
            break;
        case 5:
            return Colors.red
            break;
        default:
            return Colors.blue
    }
}

https://user-images.githubusercontent.com/32726353/103963374-0a9cf400-5194-11eb-88b8-b9ede895e459.mp4

All 5 comments

Can you share sample code?

Below is the code, the scroll keep offset to top when i change the checkbox state. Is there any other solutions?

import React, {Component} from "react";
import {Dimensions, TouchableOpacity} from "react-native";
import {RecyclerListView, DataProvider, LayoutProvider} from "recyclerlistview";
import {View, Body, Grid, Icon, ListItem, Right, Row, Button} from "native-base";
import Colors from "../constants/Colors";
import {TextInput} from "react-native-paper";
import {Text} from '../components/Themed';
import {useNavigation} from "@react-navigation/native";

const ViewTypes = {
    FULL: 0,
    HALF_LEFT: 1,
    HALF_RIGHT: 2
};

export default function RecycleTestComponent(props) {
    const navigation = useNavigation();
    const {mode, isShowCheckbox, data} = props;

    const [selected_leave, set_selected_leave] = React.useState([]);
    let dataProviderTemplate = new DataProvider((r1, r2) => {
        return r1 !== r2;
    });
    console.log(data)
    const [dataProvider, setDataProvider] = React.useState(dataProviderTemplate.cloneWithRows(data));


    React.useEffect(() => {
        set_selected_leave([])
    }, [isShowCheckbox])

    const isChecked = (itemId) => {
        const isThere = selected_leave.includes(itemId);
        return isThere;
    };

    const pressItem = ({leave_item}) => {
        if (!isShowCheckbox) {
            navigation.navigate('LeaveApprovalDetailScreen', {
                mode: mode,
                leave_item: leave_item,
            })
        } else {

            if (selected_leave.includes(leave_item.leave_appl_group_id)) {
                set_selected_leave(selected_leave.filter(item => item !== leave_item.leave_appl_group_id));

            } else {
                set_selected_leave(prevState => [...prevState, leave_item.leave_appl_group_id])
            }
        }
    }



    let {width} = Dimensions.get("window");
    const _layoutProvider = new LayoutProvider(
        index => {
            return ViewTypes.FULL;
        },
        (type, dim) => {
            dim.width = width;
            dim.height = 180;
        }
    );

    const _rowRenderer = React.useCallback((type, leave_item) => {
        if (leave_item) {
            let attachment_arr = []
            for (var i = 0; i < leave_item.leave_attachment.length; i++) {
                attachment_arr = attachment_arr.concat(leave_item.leave_attachment[i]);
            }
            return (
                <TouchableOpacity onPress={() => pressItem({leave_item})}>
                    <View noIndent style={{
                        width: Dimensions.get("window").width,
                        padding: 10,
                        height:180,
                        flexDirection: 'row',
                        borderBottomColor: Colors.lightgrey,
                        borderBottomWidth: 1,
                        backgroundColor: (isChecked(leave_item.leave_appl_group_id)) ? Colors.lightgrey : null
                    }}
                          key={leave_item.leave_appl_group_id}
                    >
                        {/*Left*/}
                        <View style={{flex: 1, justifyContent: 'center', alignContent: 'center',}}>
                            <Row>
                                <View style={{
                                    borderRadius: 4,
                                    backgroundColor: leave_status_color(leave_item.leave_status),
                                    padding: 4,
                                    height: 24
                                }}>
                                    <Text style={{
                                        fontSize: 12,
                                        color: Colors.milk_white,
                                        fontWeight: "bold"
                                    }}>{leave_item.leave_status_label}</Text>
                                </View>
                            </Row>
                            <Row>
                                <Text ellipsizeMode={'tail'} style={{fontSize: 14}}><Text
                                    style={{
                                        fontWeight: 'bold',
                                        color: Colors.darkblue
                                    }}>{leave_item.employee_no} {leave_item.employee_name} </Text> </Text>
                            </Row>

                            <Row>
                                <Text ellipsizeMode={'tail'} numberOfLines={1} style={{
                                    fontSize: 14,
                                    fontWeight: 'bold',
                                    color: Colors.darkgrey
                                }}>({leave_item.leave_code}) - {leave_item.leave_name}
                                </Text>
                            </Row>
                            <Row style={{marginBottom: 4}}>
                                <View style={{
                                    borderRadius: 4,
                                    borderWidth: 0.5,
                                    borderColor: Colors.grey,
                                    padding: 5,
                                    height: 26
                                }}>
                                    <Text style={{
                                        fontSize: 12,
                                        color: Colors.darkgrey,
                                        fontWeight: 'bold'
                                    }}>{leave_item.leave_start}</Text>
                                </View>
                                <View style={{justifyContent: 'center'}}><Text
                                    style={{
                                        fontSize: 12,
                                        color: Colors.darkgrey
                                    }}> until </Text></View>
                                <View style={{
                                    borderRadius: 4,
                                    borderWidth: 0.5,
                                    borderColor: Colors.grey,
                                    padding: 5,
                                    height: 26

                                }}>
                                    <Text style={{
                                        fontSize: 12,
                                        color: Colors.darkgrey,
                                        fontWeight: 'bold'
                                    }}>{leave_item.leave_end}</Text>
                                </View>
                            </Row>
                            <Row>
                                <View style={{
                                    borderRadius: 4,
                                    backgroundColor: Colors.blue,
                                    padding: 4,
                                    height: 24

                                }}>
                                    <Text style={{
                                        fontSize: 12,
                                        color: Colors.milk_white,
                                        fontWeight: "bold",
                                    }}>{leave_item.interval_format}</Text>
                                </View>
                            </Row>
                            <Row style={{marginTop: 4}}>
                                {
                                    (attachment_arr.length > 0) ?
                                        <View style={{alignSelf: 'center'}}>
                                            <Icon type={'AntDesign'} name={'paperclip'}
                                                  style={{
                                                      fontSize: 18,
                                                      padding: 2,
                                                      color: Colors.blue,
                                                  }}/>
                                        </View>

                                        : null
                                }


                                {
                                    (parseInt(leave_item.leave_emergency) == 1) ?
                                        <View style={{
                                            borderRadius: 4,
                                            backgroundColor: Colors.red,
                                            padding: 4,
                                            height: 24,
                                            marginRight: 4,
                                            marginTop: 4
                                        }}>
                                            <Text style={{
                                                fontSize: 12,
                                                color: Colors.milk_white,
                                                fontWeight: "bold"
                                            }}>Emergency</Text>
                                        </View>
                                        : null
                                }
                                {
                                    (parseInt(leave_item.leave_advance) == 1) ?
                                        <View style={{
                                            borderRadius: 4,
                                            backgroundColor: Colors.darkgrey,
                                            padding: 4,
                                            height: 24,
                                            marginRight: 4,
                                            marginTop: 4
                                        }}>
                                            <Text style={{
                                                fontSize: 12,
                                                color: Colors.milk_white,
                                                fontWeight: "bold"
                                            }}>Advance</Text>
                                        </View>
                                        : null
                                }

                            </Row>
                        </View>
                        {/*Right*/}
                        <View style={{width: 30}}>
                            <Row>
                                <View>
                                    <Text><Icon type="MaterialCommunityIcons"
                                                name={(isChecked(leave_item.leave_appl_group_id)) ? "checkbox-marked" : "checkbox-blank-outline"}
                                                style={{color: Colors.darkgrey}}/></Text>
                                </View>

                            </Row>
                            <Row>
                                <View style={{
                                    alignItems: 'center',
                                    alignContent: 'center',
                                    justifyContent: 'center',
                                    width: 30,
                                    height: 30,
                                    backgroundColor: Colors.blue,
                                    borderRadius: 4,
                                }}>
                                    <Icon type={'Ionicons'} name={'md-chatbox-sharp'}
                                          style={{
                                              fontSize: 20,
                                              color: Colors.milk_white,
                                          }}/>
                                </View>
                            </Row>
                        </View>
                    </View>
                </TouchableOpacity>
            )
        }
    }, [selected_leave])

    return <RecyclerListView forceNonDeterministicRendering={true} layoutProvider={_layoutProvider}
                             dataProvider={dataProvider}
                             rowRenderer={_rowRenderer}/>;
}

const leave_status_color = (leave_status) => {
    switch (parseInt(leave_status)) {
        case 3:
        case 7:
        case 8:
            return Colors.orange
            break;
        case 5:
            return Colors.red
            break;
        default:
            return Colors.blue
    }
}

https://user-images.githubusercontent.com/32726353/103963374-0a9cf400-5194-11eb-88b8-b9ede895e459.mp4

I have the same issue.. when I modify local state, it messes up the scroll index and also the dynamic heights if I use forceDeterministicRendering and don't set a dim.height on the cells..

I had the same issue, but I managed to resolve it with the answers I find in here: issue-493
From what I see in your code, you should useState even for layout provider, not only for data.

Can you share sample code?

Can anyone Help me ?

I have to set disableRecycling={true} because it is showing same items again and again, with pagination on scrolling.
But after setting disableRecycling={true} now RecyclerListView is Flickering/Jumping on scrolling and
FPS are dropped more than 2500.

Any Solution Please ?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

waheedakhtar694 picture waheedakhtar694  路  6Comments

mmamoyco picture mmamoyco  路  7Comments

H-Shafiei picture H-Shafiei  路  8Comments

leifermendez picture leifermendez  路  8Comments

andrea7887 picture andrea7887  路  6Comments