0

我在平面列表中有一个联系人列表,我制作了一个随机颜色生成器函数,它将为带有用户名字缩写的联系人个人资料图像占位符生成随机背景颜色。我在列表中添加了一个删除按钮,以便用户可以删除特定的联系人。如果用户按下删除按钮,我已经制作了一个自定义弹出对话框来要求确认。我正在从本地领域数据库中获取列表。

现在的问题是,当我单击删除按钮时,它会重新呈现整个列表,每次单击删除按钮时,用户图像占位符的背景颜色都会发生变化。但是预期的行为应该是当我单击删除按钮时,我的自定义弹出窗口将出现,如果用户确认删除,则列表可以重新呈现,但只需单击删除按钮即可重新呈现。我不熟悉反应备忘录。我尝试在 generateRandomColor 函数甚至自定义弹出窗口上应用它,但没有任何效果。下面是我的原始代码。有人,请帮助,我在过去的两天里被困住了。

联系人列表代码如下:-

import React from 'react';
import {useState, useEffect, useCallback} from 'react';
import {
  View,
  Text,
  FlatList,
  StatusBar,
  SafeAreaView,
  TouchableOpacity,
  StyleSheet,
  Linking,
  Animated,
  Modal,
} from 'react-native';
import {CustomDialog} from '@components/CustomDialog';

import {Header} from '@components/Header';
import Fonts from '@utils/Fonts';
import {Colors} from '@theme';
import WhatsappIcon from '@images/svgs/whatsapp.svg';
import DeleteIcon from '@images/svgs/delete.svg';
import {
  realm,
  insertNewContactList,
  updateContactList,
  deleteContactList,
  queryAllContactLists,
} from '@database/realmDB';

const RecentSaved = ({navigation}) => {
  const [recentSavedContacts, setRecentSavedContacts] = useState([]);
  const [visible, setVisible] = useState(false);

  useEffect(() => {
    const tasks = realm.objects('Contact');
    // set state to the initial value of your realm objects
    setRecentSavedContacts([...tasks]);
    tasks.addListener(() => {
      // update state of tasks to the updated value
      setRecentSavedContacts([...tasks]);
    });

    return () => {
      // Remember to remove the listener when you're done!
      tasks.removeAllListeners();

      // Call the close() method when done with a realm instance to avoid memory leaks.
      realm.close();
    };
  }, []);

  const InitialIcon = ({initials}) => {
    return (
      <View
        style={[
          Styles.initialsIconContainer,
          {backgroundColor: generateColor()},
        ]}>
        <Text style={Styles.initialsIconText}>{initials}</Text>
      </View>
    );
  };

  const generateColor = () => {
    const randomColor = Math.floor(Math.random() * 16777215)
      .toString(16)
      .padStart(6, '0');
    return `#${randomColor}`;
  };


  const onDelete = id => {
    // deleteContactList(id)
    //   .then()
    //   .catch(error => {
    //     alert(`Failed to delete todoList with id = ${id}, error=${error}`);
    //   });
    setVisible(true);
  };

  const recentContactCards = ({item, index}) => {
    return (
      <View style={Styles.flatListCard}>
        <View style={Styles.flatListSubView}>
          <View style={{flexDirection: 'row', marginLeft: 10}}>
            <InitialIcon
              initials={
                item.name
                  ? item.name.slice(0, 2).toUpperCase()
                  : `+${item.number.slice(0, 2)}`
              }
            />
            <View style={{justifyContent: 'center'}}>
              {item.name ? (
                <Text style={Styles.nameTitle}>{item.name}</Text>
              ) : null}

              <Text style={item.name ? Styles.numberTitle : Styles.nameTitle}>
                +{item.number}
              </Text>
            </View>
          </View>
          <View style={{flexDirection: 'row'}}>
            <TouchableOpacity
              style={{marginRight: 15}}>
              <WhatsappIcon width={25} height={25} />
            </TouchableOpacity>
            <TouchableOpacity
              onPress={() => onDelete(item.id)}
              style={{marginRight: 10}}>
              <DeleteIcon width={25} height={25} />
            </TouchableOpacity>
          </View>
        </View>
        <View style={Styles.separatorLine} />
      </View>
    );
  };

  return (
    <SafeAreaView style={Styles.safeAreaContainer}>
      <StatusBar barStyle="light-content" backgroundColor={Colors.AppTheme} />
      <Header title="Recent" />
      <FlatList
        data={recentSavedContacts}
        contentContainerStyle={Styles.flatListContainer}
        keyExtractor={(item, index) => Math.random().toString()}
        renderItem={recentContactCards}
        ListEmptyComponent={() => {
          return (
            <View style={Styles.emptyListView}>
              <Text>There are no saved Contacts</Text>
            </View>
          );
        }}
      />

      <CustomDialog visible={visible}>
        <View style={{alignItems: 'center'}}></View>
        <View style={{alignItems: 'center'}}>
          <DeleteIcon width={45} height={45} />
        </View>

        <Text style={Styles.nameTitle}>
          Are you sure you want to delete this contact?
        </Text>
        <View
          style={{
            flexDirection: 'row',
            justifyContent: 'space-between',
            width: '90%',
            alignSelf: 'center',
          }}>
          <TouchableOpacity
            style={{
              borderWidth: 1,
              borderRadius: 10,
              padding: 10,
              backgroundColor: 'red',
              width: '40%',
            }}
            onPress={() => setVisible(false)}>
            <Text style={[Styles.nameTitle, {marginLeft: 15, color: 'white'}]}>
              Cancel
            </Text>
          </TouchableOpacity>
          <TouchableOpacity
            style={{
              borderWidth: 1,
              borderRadius: 10,
              padding: 10,
              backgroundColor: 'red',
              width: '40%',
            }}
            onPress={() => setVisible(false)}>
            <Text style={[Styles.nameTitle, {marginLeft: 15, color: 'white'}]}>
              Confirm
            </Text>
          </TouchableOpacity>
        </View>
      </CustomDialog>
    </SafeAreaView>
  );
};

const Styles = StyleSheet.create({
  safeAreaContainer: {flex: 1, backgroundColor: 'white'},
  initialsIconContainer: {
    alignItems: 'center',
    justifyContent: 'center',
    borderRadius: 25,
    width: 50,
    height: 50,
  },
  initialsIconText: {color: 'white', fontSize: 20},
  flatListContainer: {
    backgroundColor: Colors.white,
    flexGrow: 1,
  },
  flatListCard: {
    height: 70,
    backgroundColor: Colors.white,
    margin: 10,
    alignItems: 'center',
    borderRadius: 35,
  },
  flatListSubView: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    width: '100%',
  },
  emptyListView: {
    flexGrow: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  nameTitle: {
    ...Fonts.openSansSemiBold,
    fontSize: 15,
    color: 'black',
    marginLeft: 20,
  },
  numberTitle: {
    ...Fonts.openSansRegular,
    fontSize: 15,
    color: 'gray',
    marginLeft: 20,
  },
  separatorLine: {
    height: 2,
    backgroundColor: '#F2F2F2',
    width: '100%',
    position: 'absolute',
    bottom: 2,
  },
  modalBackGround: {
    flex: 1,
    backgroundColor: 'rgba(0,0,0,0.5)',
    justifyContent: 'center',
    alignItems: 'center',
  },
  modalContainer: {
    width: '80%',
    backgroundColor: 'white',
    paddingHorizontal: 20,
    paddingVertical: 30,
    borderRadius: 20,
    elevation: 20,
  },
  header: {
    width: '100%',
    height: 40,
    alignItems: 'flex-end',
    justifyContent: 'center',
  },
});

export default RecentSaved;

自定义对话框组件代码如下:-

import React, {useState, useEffect, useCallback} from 'react';
import {View, StyleSheet, Animated, Modal} from 'react-native';

const CustomDialog = ({visible, children}) => {
  const [showModal, setShowModal] = useState(visible);
  const scaleValue = React.useRef(new Animated.Value(0)).current;
  useEffect(() => {
    toggleModal();
  }, [visible]);
  const toggleModal = () => {
    if (visible) {
      setShowModal(true);
      Animated.spring(scaleValue, {
        toValue: 1,
        duration: 300,
        useNativeDriver: true,
      }).start();
    } else {
      setTimeout(() => setShowModal(false), 200);
      Animated.timing(scaleValue, {
        toValue: 0,
        duration: 300,
        useNativeDriver: true,
      }).start();
    }
  };
  return (
    <Modal transparent visible={showModal}>
      <View style={Styles.modalBackGround}>
        <Animated.View
          style={[Styles.modalContainer, {transform: [{scale: scaleValue}]}]}>
          {children}
        </Animated.View>
      </View>
    </Modal>
  );
};

const Styles = StyleSheet.create({
  modalBackGround: {
    flex: 1,
    backgroundColor: 'rgba(0,0,0,0.5)',
    justifyContent: 'center',
    alignItems: 'center',
  },
  modalContainer: {
    width: '80%',
    backgroundColor: 'white',
    paddingHorizontal: 20,
    paddingVertical: 30,
    borderRadius: 20,
    elevation: 20,
  },
  header: {
    width: '100%',
    height: 40,
    alignItems: 'flex-end',
    justifyContent: 'center',
  },
});

export default CustomDialog;
4

1 回答 1

0

将您的联系人卡片和自定义弹出窗口分离到一个组件中。通过道具将已删除的联系人传递给父级,这将确保不会重新渲染,因为弹出窗口上的状态更新将特定于该联系人卡片而不是整个屏幕 父组件

import {useState, useEffect, useCallback} from 'react';
import {
  View,
  Text,
  FlatList,
  StatusBar,
  SafeAreaView,
  TouchableOpacity,
  StyleSheet,
  Linking,
  Animated,
  Modal,
} from 'react-native';

import {Header} from '@components/Header';
import Fonts from '@utils/Fonts';
import {Colors} from '@theme';
import WhatsappIcon from '@images/svgs/whatsapp.svg';
import DeleteIcon from '@images/svgs/delete.svg';
import {
  realm,
  insertNewContactList,
  updateContactList,
  deleteContactList,
  queryAllContactLists,
} from '@database/realmDB';


const RecentSaved = ({navigation}) => {
  const [recentSavedContacts, setRecentSavedContacts] = useState([]);
  
  useEffect(() => {
    const tasks = realm.objects('Contact');
    // set state to the initial value of your realm objects
    setRecentSavedContacts([...tasks]);
    tasks.addListener(() => {
      // update state of tasks to the updated value
      setRecentSavedContacts([...tasks]);
    });

    return () => {
      // Remember to remove the listener when you're done!
      tasks.removeAllListeners();

      // Call the close() method when done with a realm instance to avoid memory leaks.
      realm.close();
    };
  }, []);

 const onDelete = id => {
     deleteContactList(id)
       .then()
       .catch(error => {
         alert(`Failed to delete todoList with id = ${id}, error=${error}`);
       });
 
    //update ur contactlist

  };


  return (
    <SafeAreaView style={Styles.safeAreaContainer}>
      <StatusBar barStyle="light-content" backgroundColor={Colors.AppTheme} />
      <Header title="Recent" />
      <FlatList
        data={recentSavedContacts}
        contentContainerStyle={Styles.flatListContainer}
        keyExtractor={(item, index) => Math.random().toString()}
        renderItem={({item,index})=>{
        return
        <recentContactCards delete=onDelet(item.id)/>
        }}
        ListEmptyComponent={() => {
          return (
            <View style={Styles.emptyListView}>
              <Text>There are no saved Contacts</Text>
            </View>
          );
        }}
      />

      
    </SafeAreaView>
  );
};

const Styles = StyleSheet.create({
  safeAreaContainer: {flex: 1, backgroundColor: 'white'},
  initialsIconContainer: {
    alignItems: 'center',
    justifyContent: 'center',
    borderRadius: 25,
    width: 50,
    height: 50,
  },
  initialsIconText: {color: 'white', fontSize: 20},
  flatListContainer: {
    backgroundColor: Colors.white,
    flexGrow: 1,
  },
  flatListCard: {
    height: 70,
    backgroundColor: Colors.white,
    margin: 10,
    alignItems: 'center',
    borderRadius: 35,
  },
  flatListSubView: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    width: '100%',
  },
  emptyListView: {
    flexGrow: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  nameTitle: {
    ...Fonts.openSansSemiBold,
    fontSize: 15,
    color: 'black',
    marginLeft: 20,
  },
  numberTitle: {
    ...Fonts.openSansRegular,
    fontSize: 15,
    color: 'gray',
    marginLeft: 20,
  },
  separatorLine: {
    height: 2,
    backgroundColor: '#F2F2F2',
    width: '100%',
    position: 'absolute',
    bottom: 2,
  },
  modalBackGround: {
    flex: 1,
    backgroundColor: 'rgba(0,0,0,0.5)',
    justifyContent: 'center',
    alignItems: 'center',
  },
  modalContainer: {
    width: '80%',
    backgroundColor: 'white',
    paddingHorizontal: 20,
    paddingVertical: 30,
    borderRadius: 20,
    elevation: 20,
  },
  header: {
    width: '100%',
    height: 40,
    alignItems: 'flex-end',
    justifyContent: 'center',
  },
});

export default RecentSaved;

接触组件

import React from 'react';
import {useState, useEffect, useCallback} from 'react';
import {
  View,
  Text,
  FlatList,
  StatusBar,
  SafeAreaView,
  TouchableOpacity,
  StyleSheet,
  Linking,
  Animated,
  Modal,
} from 'react-native';

import {Header} from '@components/Header';
import Fonts from '@utils/Fonts';
import {Colors} from '@theme';
import WhatsappIcon from '@images/svgs/whatsapp.svg';
import DeleteIcon from '@images/svgs/delete.svg';
import {
  realm,
  insertNewContactList,
  updateContactList,
  deleteContactList,
  queryAllContactLists,
} from '@database/realmDB';



 
  const recentContactCards = ({item, index}) => {
  const [visible, setVisible] = useState(false);
    const InitialIcon = ({initials}) => {
    return (
      <View
        style={[
          Styles.initialsIconContainer,
          {backgroundColor: generateColor()},
        ]}>
        <Text style={Styles.initialsIconText}>{initials}</Text>
      </View>
    );
  };

  const generateColor = () => {
    const randomColor = Math.floor(Math.random() * 16777215)
      .toString(16)
      .padStart(6, '0');
    return `#${randomColor}`;
  };



const onDelete=()=>{
  setvisible(true)
}
const RequestDeleted()=>{
    props.delete?.()
    setvisible(false)

}
  

    return (
      <View style={Styles.flatListCard}>
        <View style={Styles.flatListSubView}>
          <View style={{flexDirection: 'row', marginLeft: 10}}>
            <InitialIcon
              initials={
                item.name
                  ? item.name.slice(0, 2).toUpperCase()
                  : `+${item.number.slice(0, 2)}`
              }
            />
            <View style={{justifyContent: 'center'}}>
              {item.name ? (
                <Text style={Styles.nameTitle}>{item.name}</Text>
              ) : null}

              <Text style={item.name ? Styles.numberTitle : Styles.nameTitle}>
                +{item.number}
              </Text>
            </View>
          </View>
          <View style={{flexDirection: 'row'}}>
            <TouchableOpacity
              style={{marginRight: 15}}>
              <WhatsappIcon width={25} height={25} />
            </TouchableOpacity>
            <TouchableOpacity
              onPress={() => onDelete(item.id)}
              style={{marginRight: 10}}>
              <DeleteIcon width={25} height={25} />
            </TouchableOpacity>
          </View>
        </View>
        <View style={Styles.separatorLine} />

        <CustomDialog visible={visible}>
        <View style={{alignItems: 'center'}}></View>
        <View style={{alignItems: 'center'}}>
          <DeleteIcon width={45} height={45} />
        </View>

        <Text style={Styles.nameTitle}>
          Are you sure you want to delete this contact?
        </Text>
        <View
          style={{
            flexDirection: 'row',
            justifyContent: 'space-between',
            width: '90%',
            alignSelf: 'center',
          }}>
          <TouchableOpacity
            style={{
              borderWidth: 1,
              borderRadius: 10,
              padding: 10,
              backgroundColor: 'red',
              width: '40%',
            }}
            onPress={() => setVisible(false)}>
            <Text style={[Styles.nameTitle, {marginLeft: 15, color: 'white'}]}>
              Cancel
            </Text>
          </TouchableOpacity>
          <TouchableOpacity
            style={{
              borderWidth: 1,
              borderRadius: 10,
              padding: 10,
              backgroundColor: 'red',
              width: '40%',
            }}
            onPress={() => {RequestDeleted()}}>
            <Text style={[Styles.nameTitle, {marginLeft: 15, color: 'white'}]}>
              Confirm
            </Text>
          </TouchableOpacity>
        </View>
      </CustomDialog>
      </View>
    );
  };
export default recentContactCards

**PS 这只是一个简短的概述,您可能需要进行一些更改以避免错误**

于 2021-10-12T06:41:33.817 回答