0

私の Redux ストアでは、アクティブな Report オブジェクトを保持しています。この複合オブジェクトには、id フィールドと uri フィールドを持つオブジェクトで構成される写真オブジェクトの配列があります。たとえば、Report オブジェクトは次のようになります。

{
    title: "some title",
    date: "some date",
    ... a bunch of other data
    photos: [
       {uri: someURI, id: some id},
       {uri: someURI, id: some id},
       {uri: someURI, id: some id},
   ]
}

これらのイメージ URI (ローカル ファイルではなく、firestore ストレージを指します) を次のように FlatList に読み込みます。

<FlatList
   ref={listRef}
   numColumns={3}
   columnWrapperStyle={{ marginBottom: 10 }}
   nestedScrollEnabled={true}
   showsVerticalScrollIndicator={false}
   data={activeReport?.photos}
   renderItem={renderImages}
/>

次に、この関数で renderItems を呼び出します。

const renderImages = ({ item, index }) => {
      const screenWidth = ((Dimensions.get('window').width - 50) / 3)
      const marginH = (index + 2) % 3 === 0 ? 10 : 0

      return (
         <AsyncImage
            image={item}
                key={item.id}
            onPress={() => navigation.navigate('Photo', { image: item })}
            containerStyles={{ width: screenWidth, alignItems: 'center'}}
            onLongPress={() => {
               Alert.alert('Delete Photo?', 'Are you sure you want to delete this photo?', [
                  {
                     text: 'Cancel',
                     style: 'cancel',
                  },
                  {
                     text: 'Delete',
                     onPress: () => {
                        _deleteImageAsync(item)
                     },
                     style: 'destructive',
                  },
               ])
            }}
         />
      )
   }

最後に、AsyncImage コンポーネントのコードを次に示します。

function AsyncImage({ imageStyles = {}, image, onPress, onLongPress, containerStyles }) {
   const [loading, setLoading] = useState(true)

   return (
      <TouchableOpacity
         key={image.id}
         activeOpacity={0.7}
         onPress={onPress}
         onLongPress={onLongPress}
         style={[styles.touchableWrapper, containerStyles]}>

         <ImageBackground
            source={require('../../../../assets/image.png')}
            resizeMode='cover'
            style={[styles.image, styles.placeholderImage]}
         />

         <Image
            style={[styles.image, imageStyles]}
            source={{ uri: image.uri }}
            resizeMode='cover'
            onLoadEnd={() => {
               setLoading(false)
            }}
         />

         {loading && (
            <>
               <ActivityIndicator animating={true} size={36} color={colors.colorPrimary} style={styles.indicator} />
            </>
         )}
      </TouchableOpacity>
   )
}

const areEqual = (prevProps, nextProps) => {
   const { image } = nextProps
   const { image: prevImage } = prevProps
   return image.uri === prevImage.uri
}

const styles = StyleSheet.create({
   touchableWrapper: {
      borderRadius: 5,
      overflow: 'hidden',
      marginHorizontal: 5,
   },
   image: {
      backgroundColor: colors.colorCharcoalDark,
      resizeMode: 'cover',
      width: '100%',
      aspectRatio: 1,
      borderColor: colors.colorGrayDark,
      borderWidth: 0.5,
      borderRadius: 5,
   },
   placeholderImage: {
      position: 'absolute',
      top: 0,
      bottom: 0,
      left: 0,
      right: 0,
   },
   indicator: {
      position: 'absolute',
      top: 0,
      bottom: 0,
      left: 0,
      right: 0,
   },
})

export default React.memo(AsyncImage, areEqual)

これが私の写真削除機能です:

const _deleteImageAsync = async (photo) => {
      if (!photo) return
      try {
         // delete image from report in firestore
         const reportRef = db.collection('reports').doc(activeReport.reportID)
         const report = (await reportRef.get()).data()
            
         // make sure photo exists before trying to remove it from firestore
         if (report.photos.some((p) => p.id === photo.id)) {
            reportRef.update({
               photos: firebase.firestore.FieldValue.arrayRemove(photo),
            })
         } else {
                throw new Error('Could not delete photo. Please try again')
            }
         // delete photo from storage
         const ref = storage.ref(activeReport?.reportID).child(photo.id)
         await ref.delete()

            dispatch(removeReportPhoto(photo))

      } catch (error) {
            // todo: handle error here
         console.log('Delete photo: ', error.message)
         alert('was not able to delete photo from cloud storage.')
      }
   }

問題

アレイに新しい写真を追加すると、すべて問題ありません。ただし、配列から要素を削除すると、React.memo を使用しているにもかかわらず、一部の (すべてではない) 画像がリロードされます。

その理由を探るのに何時間も何日も費やしました。道に迷いました。この問題について何か助けていただければ幸いです

誰かが私のコードをもっと見る必要がある場合は、私に知らせてください。

4

0 に答える 0