从状态中删除项目后平面列表不重新渲染

Flatlist not re-rendering after deleting an item from the state

我正在开发一个 React Native 应用程序,

在这个应用程序中,我有一个捕获视图的图像,如果用户捕获图像,它将存储在状态挂钩中,如果存储了一些东西,它将显示在 Flatlist 中。

如果我们认为用户需要从列表中删除一个项目,那我提供了一个删除按钮。当用户点击它时,该项目应该从状态中删除并更新 Flatlist。

我的问题是:从状态中删除项目后,我的视图不会重新呈现。我可以保证数据成功从状态中删除,但我的 Flatlist 没有更新。

我的代码如下,请帮我找到答案。提前致谢。

以下代码用于从状态中删除项目。

const [selectedFiles, setSelectedFiles] = useState([]);

const removeItemFromArray = (index: number) => {
     let imagesArray = selectedFiles;
     imagesArray.splice(index, 1);
     setSelectedFiles(imagesArray);
}

平面列表

<FlatList
 showsHorizontalScrollIndicator={false}
                    data={selectedFiles}
                    renderItem={({ item, index }) => {
                        return (
                            <ImagePreviewSlider
                                itemData={item}
                                viewImage={() => viewImage(index)}
                                deleteItem={() => removeItemFromArray(index)}
                            />
                        );
                    }}
                />

------------完整代码-------------

photoUpload.tsx

import React, { useState } from "react";
import {
    View,
    Text,
    StyleSheet,
    ScrollView,
    Image,
    ImageBackground,
    TouchableOpacity,
    Modal,
    FlatList
} from "react-native";
import ImagePicker from 'react-native-image-picker/lib/commonjs';
import ComponentStyles, { FONT_FAMILY, COLORS } from "../../../../constants/Component.styles";
import IconF from 'react-native-vector-icons/FontAwesome';
import ActionButton from "../../../../components/ActionButton";
import ImagePreviewSlider from "../../../../subComponents/ProgressBarWithImage";

import InspectionCheckListItem from './InspectionCheckListRow';

const ImageUpload = props => {

    /**
     * image capturing and upload tab view
     */
    const [modalVisible, setModalVisible] = useState(false);
    const [selectedFiles, setSelectedFiles] = useState([]);

    /**
     * used to open popup dialog / state hook will be updated.
     */
    const openModal = () => {
        // setModalVisible(true);
        props.navigation.navigate('Inspection result');
    }

    /**
     * when user click on previous button this method will be worked.
     */
    const previousTab = () => {
        props.navigation.navigate('Inspection checkList');
    }

    /**
     * below method used to close the popup dialog. 
     */
    const colseModal = () => {
        setModalVisible(false);
    }

    /**
     * @chooseFile method is a alert dialog / here user can select camera or galery
     * @ImagePicker method used to open camera and collect picture / select picture from galery(function)
     */
    const chooseFile = () => {
        const options = {
            title: 'Select an option',
            storageOptions: {
                skipBackup: true,
                path: 'images',
            },
        };
        ImagePicker.showImagePicker(options, (response) => {
            // console.log('Response = ', response);
            if (response.didCancel) {
                console.log('User cancelled image picker');
            } else if (response.error) {
                console.log('ImagePicker Error: ', response.error);
            } else {
                // let source = response;
                // You can also display the image using data:
                let source = {
                    uri: 'data:image/jpeg;base64,' + response.data
                };
                setImagesToHooks(source);
            }
        });
    };

    /**
     * 
     * @param newImage base64- converted image
     */
    const setImagesToHooks = (newImage) => {
        // This will update the array. Refer the blog link for more information.
        let imagesArray = [...selectedFiles, newImage];
        setSelectedFiles(imagesArray);

    };

    const removeItemFromArray = (index: number) => {
        let imagesArray = selectedFiles;
        imagesArray.splice(index, 1);
        setSelectedFiles(imagesArray);
    }

    const viewImage = (index: number) => {
        console.log("view item : ########  : ");
    }

    return (
        <View style={{ backgroundColor: COLORS.WHITE_BG, flex: 1, borderTopLeftRadius: 30, borderTopRightRadius: 30 }}>

            <View style={{ flexDirection: 'row', width: '100%', height: '90%' }}>
                <View style={{ width: '50%', height: '100%', padding: "2%" }}>
                    <TouchableOpacity style={{ width: '100%', height: 300, alignItems: 'center', justifyContent: 'center' }} onPress={chooseFile}>
                        <ImageBackground style={{ width: '100%', height: 300, alignItems: 'center', justifyContent: 'center' }} resizeMode={'stretch'}
                            source={require('../../../../assets/images/Rectangle_image_upload.png')} >
                            <IconF style={{ color: COLORS.ASH_AE }} name="camera" size={80} />
                            <Text style={{ color: COLORS.ASH_AE }}>Take image or upload from device</Text>
                        </ImageBackground>
                    </TouchableOpacity>
                </View>

                <View style={{ width: '50%', marginTop: 5, }}>
                    {/* <ProgressBar array={selectedFiles} deleteItem={(value) => deleteItemFromArray(value)}/> */}
                    <FlatList
                        showsHorizontalScrollIndicator={false}
                        data={selectedFiles}
                        renderItem={({ item, index }) => {
                            return (
                                <ImagePreviewSlider
                                    itemData={item}
                                    viewImage={() => viewImage(index)}
                                    deleteItem={() => removeItemFromArray(index)}
                                />
                            );
                        }}
                    />
                </View>
            </View>
            <View style={styles.actionButton}>
                <ActionButton
                    title={'Previous'}
                    color={COLORS.PINK}
                    customBtnStyle={{
                        height: 65,
                        width: '85%',
                    }}
                    onPress={() => previousTab()}
                />
                <ActionButton
                    title={'Next'}
                    color={COLORS.GREEN_42}
                    customBtnStyle={{
                        height: 65,
                        width: '100%',
                    }}
                    onPress={() => openModal()}
                />
            </View>

            <View>
                <Modal
                    animationType="fade"
                    transparent={true}
                    visible={modalVisible} >
                    <View style={styles.modalContainer}>
                        <View style={styles.centeredView}>
                            <View style={{ flexDirection: 'row', alignItems: 'center' }}>
                                <TouchableOpacity style={{ flex: 0.2 }} onPress={colseModal}>
                                    <Image source={require('../../../../assets/images/ic-close.png')} style={{ height: 20, width: 20, marginRight: 10 }} />
                                </TouchableOpacity>
                            </View>
                            <View style={styles.columnView}>
                                <Text style={styles.contentTitle}>Inspection of pharmacies</Text>
                                <Text style={styles.contentSubTitle}>Checklist:</Text>

                                <View style={styles.rowView}>
                                    <View style={{ flex: 1, alignSelf: 'center' }} >
                                        <Text style={styles.tableText}>Description</Text>
                                    </View>
                                    <View style={{ flex: 1, alignSelf: 'center' }} >
                                        <Text style={styles.tableText}>Validiry</Text>
                                    </View>
                                    <View style={{ flex: 1, alignSelf: 'center' }} >
                                        <Text style={styles.tableText}>Remark</Text>
                                    </View>
                                </View>
                            </View>
                            <View style={{ flex: 2, width: '100%', flexDirection: 'column' }}>
                                {/* <InspectionCheckListItem array={InspectionList.items} /> */}
                            </View>
                        </View>
                    </View>
                </Modal>
            </View>
        </View>
    );
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center'
    },
    modalContainer: {
        position: 'absolute',
        width: '100%',
        height: '100%',
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: 'rgba(100,100,100, 0.5)',
        padding: 20,
    },
    centeredView: {
        position: 'relative',
        width: '90%',
        height: '90%',
        backgroundColor: COLORS.WHITE_FC,
        padding: 20,
    },
    inspectionNumber: {
        flex: 1.5,
        fontSize: 18,
        color: COLORS.BLUE_69,
        fontFamily: FONT_FAMILY.BOLD
    },
    modalTitle: {
        flex: 2,
        fontSize: 12,
        color: COLORS.GREEN_42,
        fontFamily: FONT_FAMILY.BOLD
    },
    contentTitle: {
        fontSize: 18,
        color: COLORS.BLUE_69,
        fontFamily: FONT_FAMILY.REGULAR,
    },
    contentSubTitle: {
        fontSize: 18,
        color: COLORS.BLUE_69,
        fontFamily: FONT_FAMILY.BOLD,
    },
    columnView: {
        flexDirection: 'column',
        justifyContent: 'center',
        alignItems: 'center'
    },
    rowView: {
        flexDirection: 'row',
        justifyContent: 'center',
        alignItems: 'center',
        marginTop: '5%'
    },
    tableText: {
        fontSize: 18,
        color: COLORS.BLUE_69,
        fontFamily: FONT_FAMILY.LIGHT,
        justifyContent: 'center',
        alignSelf: 'center'
    },
    actionButton: {
        flex: 1,
        flexDirection: 'row',
        justifyContent: 'center',
        alignItems: 'flex-end',
        position: 'relative',
        bottom: '2%',
        left: 0,
    }
});

export default ImageUpload;

ProgressBarWithImage.tsx

import React, { Component } from "react";
import {
    View,
    Text,
    StyleSheet,
    TouchableOpacity
} from "react-native";
import IconMC from 'react-native-vector-icons/MaterialCommunityIcons';
import { ProgressBar } from '@react-native-community/progress-bar-android';
import { COLORS, FONT_FAMILY } from "../constants/Component.styles";

const ProgressBarWithImage = props => {
    return (
        <View style={styles.container}>
            <View style={{ justifyContent: 'center', alignItems: 'center', backgroundColor: COLORS.PINK, opacity: 0.3, height: 40, width: 40, borderRadius: 100 }}>
                <TouchableOpacity onPress={props.viewImage}>
                    <IconMC style={{ color: COLORS.PINK, opacity: 100 }} name="file-image" size={30} />
                </TouchableOpacity>
            </View>

            <View style={{ marginLeft: 20, }}>
                <View style={{ flexDirection: 'row', alignItems: 'center', width: '100%' }}>
                    <Text style={{ fontSize: 15, color: COLORS.BLUE_2C, fontFamily: FONT_FAMILY.SEMI_BOLD }}>Photo01.PNG</Text>
                    <View style={{ flex: 1 }} />
                    <TouchableOpacity onPress={props.deleteItem}>
                        <IconMC style={{ color: COLORS.ASH_AE, opacity: 100, marginLeft: 60, }} name="close" size={20} />
                    </TouchableOpacity>
                </View>
                <Text style={{ fontSize: 15, color: COLORS.ASH_AE, fontFamily: FONT_FAMILY.SEMI_BOLD }}>7.5Mb</Text>
                <ProgressBar
                    styleAttr="Horizontal"
                    indeterminate={false}
                    progress={1}
                />
            </View>
        </View>
    );
};

const styles = StyleSheet.create({
    container: {
        alignItems: 'center',
        justifyContent: 'center',
        flexDirection: 'row',
        width: '100%',
        marginTop: 20,

    },

});

export default ProgressBarWithImage;

只需使用 flatList 的 extraData 属性重新渲染 flatList。

只需添加此状态

const [refreshFlatlist, setRefreshFlatList] = useState(false);

然后在 removeItemFromArray 函数中添加以下行

setRefreshFlatList(!refreshFlatlist)

最后,在 flatList 中添加这个属性

extraData(refreshFlatlist)