Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How I can resolve this : Warning: Encountered two children with the same key, `%s`

I am new to react-native and this is not me who program this app.

Could someone help me to fix this error, I think its the flatlist who cause this because it happen only I load the page or search something on the list. I know there is a lot a question about this error but I don't find a solution for me.

Warning: Encountered two children with the same key,%s. Keys should be unique so that components maintain their identity across updates.

ContactScreen.js

import React from 'react';
import { Button, View, FlatList, Alert, StyleSheet, KeyboardAvoidingView } from 'react-native';
import { ListItem, SearchBar } from 'react-native-elements';
import Ionicons from 'react-native-vector-icons/Ionicons';
import { Contacts } from 'expo';
import * as Api from '../rest/api';
import theme from '../styles/theme.style';
import { Contact, ContactType } from '../models/Contact';

class ContactsScreen extends React.Component {
  static navigationOptions = ({ navigation }) => {
    return {
      headerTitle: "Contacts",
      headerRight: (
        <Button
          onPress={() => navigation.popToTop()}
          title="Déconnexion"
        />
      ),
    }
  };

  constructor(props) {
    super(props);

    this.state = {
      contacts: [],
      search: '',
      isFetching: false,
      display_contacts: []
    }
  }

  async componentDidMount() {
    this.getContactsAsync();
  }

  async getContactsAsync() {
    const permission = await Expo.Permissions.askAsync(Expo.Permissions.CONTACTS);
    if (permission.status !== 'granted') { return; }

    const contacts = await Contacts.getContactsAsync({
        fields: [
          Contacts.PHONE_NUMBERS,
          Contacts.EMAILS,
          Contacts.IMAGE
        ],
        pageSize: 100,
        pageOffset: 0,
    });


    const listContacts = [];
    if (contacts.total > 0) {
      for(var i in contacts.data) {
        let contact = contacts.data[i];
        let id = contact.id;
        let first_name = contact.firstName;
        let middle_name = contact.middleName;
        let last_name = contact.lastName;
        let email = "";
        if ("emails" in  contact && contact.emails.length > 0) {
          email = contact.emails[0].email;
        }
        let phone = "";
        if ("phoneNumbers" in contact && contact.phoneNumbers.length > 0) {
          phone = contact.phoneNumbers[0].number;
        }
        listContacts.push(new Contact(id, first_name, middle_name, last_name, email, phone, ContactType.UP));
      }
    }

    const soemanContacts = await Api.getContacts();
    if (soemanContacts.length > 0) {
      for(var i in soemanContacts) {
        let contact = soemanContacts[i];
        let id = contact.contact_id.toString();
        let first_name = contact.contact_first_name
        let last_name = contact.contact_last_name;
        let email = contact.contact_email;
        let phone = contact.contact_phone.toString();
        listContacts.push(new Contact(id, first_name, "", last_name, email, phone, ContactType.DOWN));
      }
    }

    listContacts.sort((a, b) => a.name.localeCompare(b.name));
    this.setState({contacts: listContacts});
    this.setState({ isFetching: false });
    this.updateSearch(null);
  }

  async addContactAsync(c) {
    const contact = {
      [Contacts.Fields.FirstName]: c.firstName,
      [Contacts.Fields.LastName]: c.lastName,
      [Contacts.Fields.phoneNumbers]: [
        {
          'number': c.phone
        },
      ], 
      [Contacts.Fields.Emails]: [
        {
          'email': c.email
        }
      ]
    }
    const contactId = await Contacts.addContactAsync(contact);
  }

  onRefresh() {
    this.setState({ isFetching: true }, function() { this.getContactsAsync() });
  }

  updateSearch = search => {
    this.setState({ search });
    if(!search) {
      this.setState({display_contacts: this.state.contacts});
    }
    else {

      const res = this.state.contacts.filter(contact => contact.name.toLowerCase().includes(search.toLowerCase()));
      console.log(res);
      this.setState({display_contacts: res});
      console.log("contact display "+ this.state.display_contacts);
    }
  };

  toggleContact(contact) {
    switch(contact.type) {
      case ContactType.SYNC:
        break;
      case ContactType.DOWN:
        this.addContactAsync(contact);
        break;
      case ContactType.UP:
        Api.addContact(contact);
        break;
    }
    /*Alert.alert(
      'Synchronisé',
      contact.name + 'est déjà synchronisé'
    );*/
  }

  renderSeparator = () => (
    <View style={{ height: 0.5, backgroundColor: 'grey', marginLeft: 0 }} />
  )

  render() {
    return (
      <View style={{ flex: 1 }}>
      <KeyboardAvoidingView style={{ justifyContent: 'flex-end' }} behavior="padding" enabled>
        <SearchBar
          platform="default"
          lightTheme={true}
          containerStyle={styles.searchBar}
          inputStyle={styles.textInput}
          placeholder="Type Here..."
          onChangeText={this.updateSearch}
          value={this.state.search}
          clearIcon
        />
        <FlatList
          data={this.state.display_contacts}
          onRefresh={() => this.onRefresh()}
          refreshing={this.state.isFetching}
          renderItem={this.renderItem}
          keyExtractor={contact => contact.id}
          ItemSeparatorComponent={this.renderSeparator}
          ListEmptyComponent={this.renderEmptyContainer()}
        />
      </KeyboardAvoidingView>
      </View>
    );
  }

  renderItem = (item) => {
    const contact = item.item;
    let icon_name = '';
    let icon_color = 'black';
    switch(contact.type) {
      case ContactType.SYNC:
        icon_name = 'ios-done-all';
        icon_color = 'green';
        break;
      case ContactType.DOWN:
        icon_name = 'ios-arrow-down';
        break;
      case ContactType.UP:
        icon_name = 'ios-arrow-up';
        break;
    }
    return (
      <ListItem
        onPress={ () => this.toggleContact(contact) }
        roundAvatar
        title={contact.name}
        subtitle={contact.phone}
        //avatar={{ uri: item.avatar }}
        containerStyle={{ borderBottomWidth: 0 }}
        rightIcon={<Ionicons name={icon_name} size={20} color={icon_color}/>}
      />
    );
  }

  renderEmptyContainer() {
    return (
      <View>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  searchBar: {
    backgroundColor: theme.PRIMARY_COLOR
  },
  textInput: {
    backgroundColor: theme.PRIMARY_COLOR,
    color: 'white'
  }
});

export default ContactsScreen;

I use react-native and expo for this application.

like image 701
Sam Avatar asked Apr 12 '19 12:04

Sam


People also ask

How do you resolve warning each child in a list should have a unique key prop?

Keys only need to be unique among siblings. They don't need to be unique globally. After the warning, you will also see a line mentioning to "Check the render method of `Component`.". This way, you will know exactly which component is causing the error, and where to look for the bug.

What is key prop and what is the benefit of using it in arrays of elements?

React's key prop gives you the ability to control component instances. Each time React renders your components, it's calling your functions to retrieve the new React elements that it uses to update the DOM. If you return the same element types, it keeps those components/DOM nodes around, even if all the props changed.

Do not use array index in keys React?

Disallow usage of Array index in keys ( react/no-array-index-key ) Warn if an element uses an Array index in its key . The key is used by React to identify which items have changed, are added, or are removed and should be stable. It's a bad idea to use the array index since it doesn't uniquely identify your elements.

Are not valid as a React child?

The React. js error "Objects are not valid as a React child" occurs when we try to directly render an object or an array in our JSX code. To solve the error, use the map() method to render arrays or access properties on the object in your JSX code.


1 Answers

Just do this in you flatlist

keyExtractor={(item, index) => String(index)}
like image 163
Paras Korat Avatar answered Sep 21 '22 20:09

Paras Korat