Suvra.D
Suvra.D

Reputation: 91

React Native - Encountered two children with the same key, `221`

I am trying to fetch data through API. The data is returned in array, i parsed it to JSON and it shows perfectly in Console Log. But i can't show it on screen, the console shows following warning,

Warning: Encountered two children with the same key, 221. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

This is my code:

    import React from 'react';
    import { Container, Header, Title, Drawer, Content, Button, Left, Right, Body, Text} from 'native-base';
    import { Alert, View, TouchableOpacity, SafeAreaView } from 'react-native';
    import { MaterialIcons } from '@expo/vector-icons';
    import { Ionicons } from '@expo/vector-icons';
    import SideBar from './components/SideBar';
    import { FlatList } from 'react-native-gesture-handler';

    export default class QrScan extends React.Component{
    constructor(props) {
    super(props)

    this.state = {
        resourcedata:'',    
    };
    this.resourceAllocationList = this.resourceAllocationList.bind(this);       
    }

    closeDrawer = () => {
    this.drawer._root.close();
    }

    openDrawer = () => {
    this.drawer._root.open();
    }

    resourceAllocationList() {
    fetch('https://api.idepoz.com/ncl/api/getResource', {
        method: 'GET',
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
        },
    }).then((response) => response.json())
    .then((responseJson) => {
        if(responseJson)
        {
            var jsonData = JSON.stringify(responseJson.data);
            var resultdata = JSON.parse(jsonData);
            //console.log(resultdata);
            this.setState({resourcedata:resultdata});
        }
        
    }).catch((error) => {
        console.error(error);
    });
    }

    render()
    {
    const getHeader = () => {
        return <Text>{'Resource Allocation'}</Text>;
    };

    const getFooter = () => {
        if (this.state.loading) {
            return null;
        }
        return <Text>{'Loading...'}</Text>;
    };

    return(
        <Drawer
        ref={(ref) => { this.drawer = ref; }}
        content={<SideBar navigator={this.navigator} closeDrawer={this.closeDrawer} usertoken= 
        {this.props.navigation.state.params.usertoken} />}
        onClose={() => this.closeDrawer()} >
            <Container>
                <Header>
                    <Left>
                        <Button transparent onPress={this.openDrawer.bind(this)}>
                            <MaterialIcons name="list" size={40} color="#FFFFFF" />
                        </Button>
                    </Left>
                    <Body>
                        
                    </Body>
                    <Right>
                    <Button transparent>
                        <Ionicons  name="search" size={40} color="#FFFFFF" onPress={() => 
                        Alert.alert('Search Button pressed')} />
                    </Button>   
                    </Right>
                </Header>
                <Content>
                    <SafeAreaView style={{ 
                            flexDirection:"row",
                            justifyContent:'center',
                            marginTop: 20, 
                            alignItems: 'center',
                            marginHorizontal: 20,
                        }}>
                        
                        <TouchableOpacity onPress={this.resourceAllocationList}>
                            <Text>Press Here</Text>
                            <FlatList data={this.state.resourcedata}
                            renderItem={({ item }) => {
                                <Text>{ item.id }</Text>
                            }}
                            ListHeaderComponent={getHeader}
                            ListFooterComponent={getFooter}/>
                        </TouchableOpacity>
                        
                    </SafeAreaView>
                </Content>
            </Container>
        </Drawer>
        );
        }
        }

Return Data in Console shows like below:

Array [ Object { "allocation_space": 1, "created_at": "2021-03-26 15:49:55", "created_by": 1, "date": "2021-04-19", "deleted_at": null, "deleted_by": null, "duration": "01:00:00", "employee_id": 2, "end_time": "01:05:00", "id": 73, "is_active": 1, "is_payable": 1, "order_plan_id": 1, "price": 13, "resources_allocation_id": 73, "serviceuser_id": 1, "start_time": "00:05:00", "status": "Approved", "updated_at": "2021-04-19 07:56:08", "updated_by": 1, }.........

Can anyone help how to return above data on screen ?

Upvotes: 1

Views: 2409

Answers (1)

Hessuew
Hessuew

Reputation: 773

Try adding extraData prop to Flatlist.
"By passing extraData={selected} to FlatList we make sure FlatList itself will re-render when the state changes. Without setting this prop, FlatList would not know it needs to re-render any items because it is a PureComponent and the prop comparison will not show any changes." https://docs.expo.dev/versions/latest/react-native/flatlist/

Also adding "key" prop to your Flatlist Text element will take away the error if you don't have multiple same ids in your data. In that case you could use index as key, but this is not the best practice.
So changing your flatlist to...

<FlatList
  data={this.state.resourcedata}
  extraData={this.state.resourcedata}
  renderItem={({ item }) => {
   <Text key={item.id}>{ item.id }</Text>
  }}
  ListHeaderComponent={getHeader}
  ListFooterComponent={getFooter
 />

Also I have used props like: initialNumToRender={8} windowSize={16} to reduce memory consumption but this depends on your use case and list size
More information about Flatlist props: https://docs.expo.dev/versions/latest/react-native/flatlist/

(This is my first answer to question so be merciful to me)

EDIT

If braces {} are used in renderItem={} there needs to be return ()

keyExtractor={(item, index) => index.toString()}
renderItem={({ item, index }) => {  
 return (
   <Text key={index }>{ item.id }</Text>
  );
}}

Otherwise you could use normal braces () in renderItem which would look like...

keyExtractor={(item, index) => index.toString()}
renderItem={({ item, index }) => (  
    <Text key={index}>{ item.id }</Text>
  )
}

I usually use {} and return as then I can even put logic before return () statement like console.log()

Upvotes: 2

Related Questions