Search code examples
react-nativeexpoflatlist

FlatList in Expo loads after refreshing the project again and renders the items twice causing duplicate keys


I am actually trying to get orders as objects stored in firebase and display them in the history screen but the flatlist shows an empty screen on initial render and displays the items on refreshing again resulting in that items are displayed twice and hence causes duplicate keys?? How should I make the flatlist render things on first go??

export const HistoryScreen = () => {
    
    const [isLoading, setIsLoading] = useState(true);
    const [ list, setList] = useState([]);

    var json = [];
    var keys = [];

    const firebaseRef = firebase.database().ref(`Orders/${orderData.firebaseUserId}`);

    const getJson = async () => {
        await firebaseRef.on("value" , (snapshot) => {
            json = snapshot.val();      
        });
    }

    const SendingData = async () => {
        await getJson();
        keys = Object.keys(json);

        //Mapping Data
        keys.map((key) => {
            let k = json[key];
            let appliance = Data.find((app) => app.title === k["Appliance_Name"]);
            
            let obj = {"id" : key, "title" : k['Appliance_Name'], "service" : k['Service_Requested'],
            "time" : k['Time'], "status" : k["Status"], "image" : appliance.image};

            list.push(obj);
        })
    }

    useEffect(() => {
        setTimeout(() => {
            setIsLoading(false);
        }, 3000);
    }, []);

    useEffect(() => {
        SendingData();
    })

    return (
        <SafeArea>
            <LinearGradient style={styles.screen} colors={[color.screenBackground.g3, color.screenBackground.g2,color.screenBackground.g2, color.screenBackground.g3]}>
                {isLoading ? (
                        <View style={styles.loader}>
                            <ActivityIndicator size="large" color={color.screenBackground.g4} />
                        </View>
                ) : (
                <View style={styles.screen}>
                    <Appointments>Your Appointments</Appointments>

                    <OrderCard>
                        <Scroll>
                            <FlatList style={styles.list}        
                                data = {list}
                                renderItem = { ({ item }) => (

                                    <Item>
                                        <View style={styles.view}>
                                            <View>
                                                <Image source={item.image} resizeMode='contain' style={styles.image}/>
                                            </View>
                                            <View style={styles.container}>
                                                <Title>{item.title}</Title>
                                                <Service>Job : {item.service}</Service>
                                                <Time>Booking Time : {item.time}</Time>
                                                <ID>Appointment ID : {item.id}</ID>
                                            </View>                                          
                                        </View>
                                        <Status>Status : {item.status}</Status>
                                    </Item>
                                )}

                                keyExtractor = {item => item.id}  
                            />                       
                        </Scroll>
                    </OrderCard>
                </View>
                )}
            </LinearGradient>
        </SafeArea>
    );
}

Solution

  • you need to enhance the method that you use to get data.

    The first thing you need to use the setList to add items and not list.push.

    const [isLoading, setIsLoading] = useState(true);
        const [ list, setList] = useState([]);
    
    
        const firebaseRef = firebase.database().ref(`Orders/${orderData.firebaseUserId}`);
    
        const SendingData = async () => {
            let data = []
            let tmp_keys;
            await firebaseRef.on("value" , (snapshot) => {
               let json = snapshot.val();
               tmp_keys = Object.keys(json);
                tmp_keys.map((key) => {
                let k = json[key];
                let appliance = Data.find((app) => app.title ===    k["Appliance_Name"]);
                let obj = {"id" : key, "title" : k['Appliance_Name'], "service" : k['Service_Requested'],
                    "time" : k['Time'], "status" : k["Status"], "image" : appliance.image};
               data.push(obj)
            });
           setLits(data)
            })
        }
    

    also the isLoading set to false can be done at the end of SendingData