Home > Software design >  Each child unique "key" prop in React Native
Each child unique "key" prop in React Native

Time:03-07

I can't understand why i get this warning when i have a unique key set. The warning only shows when reloading the app (R button in metro).

If i click back and forward or refresh the screen by scrolling it does not show the warning. I have tried both setting a index as below but also adding random Math numbers in a loop but the warning still shows.

The app works as intended but the warning really annoys me. I have been struggling with this for days now and all help is appreciated.

The warning:

ERROR  Warning: Each child in a list should have a unique "key" prop.

Check the render method of `GameScreen`. See https://reactjs.org/link/warning-keys for more information.

My code:

import React, {useEffect, useState} from 'react';
// more imports

function GameScreen({navigation, route}){
    let loadingView = [];
    
    // more not so important consts

    const [data_opponentInfo, setData_opponentInfo] = useState([null,null,null]);
    const [data_game, setData_game] = useState({rounds: {}, info: {}});

    const [isLoading, setIsLoading] = useState(true);
    const [refreshing, setRefreshing] = useState(false);
    
    const wait = (timeout) => {
        return new Promise(resolve => setTimeout(resolve, timeout));
      }

    const onRefresh = React.useCallback(() => {
        setRefreshing(true);
        loadMatchData();
        wait(1000).then(() => setRefreshing(false));
      }, []);        

    const loadMatchData = () => {
        // fetch here to get data from api and populate setData_game() and setData_opponentInfo()
    };   

    useEffect(() => {
        loadMatchData();
    }, []);  

    for (var x = 0; x < 6; x  ){
        if (x == 0){
            loadingView.push(<View style={[styles.loading,{borderBottomColor:'transparent'}]}><Spinner type="Radial" color="#fff" size={40} /></View>);
        } else if (x == 5) {            
            loadingView.push(<View style={[styles.loading,{borderBottomColor:'rgba(255,255,255,0.8)'}]}></View>);
        } else {
            loadingView.push(<View style={[styles.loading,{borderBottomColor:'transparent'}]}></View>);
        }
    }

    const list_rounds = Object.keys(data_game.rounds).map((item, index) => {
        // defining not important vars here

        // defining variables content_left and content_right here

        return (
            <React.Fragment key={index}>
                <View style={[styles.content_item_row,{backgroundColor: row_background}]}>

                    {content_left}   


                    <View style={styles.content_center_wrapper}>
                        <View style={[styles.content_center_round_wrapper,{backgroundColor:round_num_background}]}>
                            <Text style={styles.content_center_round_text}>{item}</Text>
                        </View>
                        <View style={styles.content_center_category_wrapper}>
                            <Text style={styles.content_center_category_text}>{round_delta}</Text>
                        </View>
                    </View>

                    {content_right}

                </View>        
            </React.Fragment>
        )
    });

    return (
        <View style={{flex:1}}> 
            {isLoading ? loadingView : list_rounds}
        </View>
    )
}

export default GameOverviewScreen;

const styles = StyleSheet.create({  
    // Styles here
});

CodePudding user response:

To avoid refresh all components when data change, you should use "key" attribute for your component.

if (x == 0){
        loadingView.push(<View key={`view_${i}`} style={[styles.loading,{borderBottomColor:'transparent'}]}><Spinner type="Radial" color="#fff" size={40} /></View>);

The best practice is to use a unique id and not an index as in this case.

  • Related