我是本机反应的新手,这不是我编写此应用程序的人。
有人可以帮助我解决此错误吗,我认为是导致此问题的单位列表,因为仅当我加载页面或在列表中搜索内容时才会发生。我知道有关此错误的问题很多,但我找不到适合我的解决方案。
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;
我在此应用程序中使用react-native和expo。
答案 0 :(得分:2)
只需在您的待办事项列表中这样做
keyExtractor={(item, index) => String(index)}
答案 1 :(得分:2)
只需在您的单位列表中完成
keyExtractor={(id) => { id.toString(); }}
答案 2 :(得分:2)
我认为您的一些contact.id是相同的。因此您可以收到此警告。如果在FlatList中设置列表的索引号,则无法显示。
keyExtractor={(contact, index) => String(index)}
答案 3 :(得分:2)
不要动态使用索引来构建密钥。如果要构建密钥,则应尽可能在渲染之前进行。
如果您的联系人具有保证的唯一ID,则应使用该ID。如果没有,则应使用产生唯一键的函数在数据进入视图之前构建键
示例代码:
// Math.random should be unique because of its seeding algorithm.
// Convert it to base 36 (numbers + letters), and grab the first 9 characters
// after the decimal.
const keyGenerator = () => '_' + Math.random().toString(36).substr(2, 9)
// in component
key={contact.key}
答案 4 :(得分:0)
您可以尝试以下方法:
listKey={(item, index) => 'index' + index.toString()}
答案 5 :(得分:0)
我遇到了同样的错误,并且在这种情况下已解决:
不要以这种方式编码(使用async
)-每个项目都会重复渲染很多次(我不知道为什么)
Stub_Func = async () => {
const status = await Ask_Permission(...);
if(status) {
const result = await Get_Result(...);
this.setState({data: result});
}
}
componentDidMount() {
this.Stub_Func();
}
尝试类似的操作(使用then
):
Stub_Func = () => {
Ask_Permission(...).then(status=> {
if(status) {
Get_Result(...).then(result=> {
this.setState({data:result});
}).catch(err => {
throw(err);
});
}
}).catch(err => {
throw(err)
});
}
componentDidMount() {
this.Stub_Func();
}