How do i rerender my screen after deletion from list? - javascript

Hello I've been looking through several threads on stackoverflow but I haven't been able to solve my problem. I have an app where you can save movies to a watchlist. On this specific screen I want to display a users watchlist and give them the ability to delete it from the list. Currently the function is indeed deleting the movie from the list and removing it from firebase but i can't get my screen to rerender to visually represent the deletion.
This is the code right now:
export default function MovieWatchlistTab(props: any) {
let { movies } = props;
let movieWatchlist: any[] = [];
const [watchlistSnapshot, setWatchlistSnapshot] = useState();
const user: firebase.User = auth().currentUser;
const { email } = user;
const watchlistRef = firestore().collection("Watchlist");
useEffect(() => {
getWatchlistSnapshot();
}, []);
const getWatchlistSnapshot = async () => {
setWatchlistSnapshot(await watchlistRef.where("userId", "==", email).get());
};
const convertDataToArray = () => {
const convertedMovieList = [];
for (let movie in movies) {
let newMovie = {
backdrop: movies[movie].backdrop,
overview: movies[movie].overview,
release: movies[movie].release,
title: movies[movie].title,
};
convertedMovieList.push(newMovie);
}
movieWatchlist = convertedMovieList;
};
const renderMovieList = () => {
convertDataToArray();
return movieWatchlist.map((m) => {
const handleOnPressDelete = () => {
const documentRef = watchlistRef.doc(watchlistSnapshot.docs[0].id);
const FieldValue = firestore.FieldValue;
documentRef.set(
{
movies: {
[m.title]: FieldValue.delete(),
},
},
{ merge: true }
);
movieWatchlist.splice(
movieWatchlist.indexOf(m),
movieWatchlist.indexOf(m) + 1
);
console.log("movieWatchlist", movieWatchlist);
};
const swipeButtons = [
{
text: "Delete",
color: "white",
backgroundColor: "#b9042c",
onPress: handleOnPressDelete,
},
];
return (
<Swipeout right={swipeButtons} backgroundColor={"#18181b"}>
<View key={m.title} style={{ marginTop: 10, flexDirection: "row" }}>
<Image
style={{ height: 113, width: 150 }}
source={{
uri: m.backdrop,
}}
/>
<View>
<Text
style={{
flex: 1,
color: "white",
marginLeft: 10,
fontSize: 17,
}}
>
{m.title}
</Text>
<Text style={{ flex: 1, color: "white", marginLeft: 10 }}>
Release: {m.release}
</Text>
</View>
</View>
</Swipeout>
);
});
};
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#18181b",
}}
>
<ScrollView
style={{ flex: 1 }}
contentContainerStyle={{
width: Dimensions.get("window").width,
}}
>
{renderMovieList()}
</ScrollView>
</View>
);
}
I've been trying to play around with useStates and I think the answer is in that direction but I just can't seem to get it to work anyway. Any help would be appreciated!

There are a few lines in your code that show a misunderstand of React state. You have a value let movieWatchlist: any[] = []; that you reassign in convertDataToArray() and mutate in handleOnPressDelete. That's just not how we do things in React and it's not going to trigger updates properly. movieWatchlist either needs to be a stateful variable created with useState.
Do the movies passed in through props change? If they do, then you don't need to store them in state here. You could just return an array from convertDataToArray() rather than setting a variable and returning void.
To be honest it's really not clear what convertDataToArray is even doing as it seems like newMovie is either the same or a subset of the original movie object. If the point is to remove the other properties aside from these four, that's not actually needed. If the prop movies is already an array, just delete this whole function and use movies directly. If it's a keyed object, use Object.values(movies) to get it as an array.
I'm thoroughly confused as to what we are getting from props and what we are getting from firebase. It seems like we would want to update the snapshot state after deletion, but you only run your useEffect once on mount.
You may still have errors, but this code should be an improvement:
interface Movie {
backdrop: string;
overview: string;
release: string;
title: string;
}
const MovieThumbnail = (props: Movie) => (
<View key={props.title} style={{ marginTop: 10, flexDirection: "row" }}>
<Image
style={{ height: 113, width: 150 }}
source={{
uri: props.backdrop
}}
/>
<View>
<Text
style={{
flex: 1,
color: "white",
marginLeft: 10,
fontSize: 17
}}
>
{props.title}
</Text>
<Text style={{ flex: 1, color: "white", marginLeft: 10 }}>
Release: {props.release}
</Text>
</View>
</View>
);
export default function MovieWatchlistTab() {
const [watchlistSnapshot, setWatchlistSnapshot] = useState<DocumentSnapshot>();
const user: firebase.User = auth().currentUser;
const { email } = user;
const watchlistRef = firestore().collection("Watchlist");
const getWatchlistSnapshot = async () => {
const results = await watchlistRef.where("userId", "==", email).get();
setWatchlistSnapshot(results.docs[0]);
};
useEffect(() => {
getWatchlistSnapshot();
}, []);
const deleteMovie = async (title: string) => {
if ( ! watchlistSnapshot ) return;
const documentRef = watchlistRef.doc(watchlistSnapshot.id);
const FieldValue = firestore.FieldValue;
await documentRef.set(
{
movies: {
[title]: FieldValue.delete()
}
},
{ merge: true }
);
// reload watch list
getWatchlistSnapshot();
};
// is this right? I'm just guessing
const movies = ( watchlistSnapshot ? watchlistSnapshot.data().movies : []) as Movie[];
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#18181b"
}}
>
<ScrollView
style={{ flex: 1 }}
contentContainerStyle={{
width: Dimensions.get("window").width
}}
>
{movies.map((m) => (
<Swipeout
right={[
{
text: "Delete",
color: "white",
backgroundColor: "#b9042c",
// need to pass the title to the delete handler
onPress: () => deleteMovie(m.title)
}
]}
backgroundColor={"#18181b"}
>
<MovieThumbnail {...m} />
</Swipeout>
))}
</ScrollView>
</View>
);
}

Related

VirtualizedList: You have a large list that is slow to update - make sure your renderItem function renders

Im working on a react-native project and what I'm trying to do is for the user to have the possibility to select phone numbers in his contact list.
When the user selects one or more contacts, the app won't work, and it shows this error on the console: VirtualizedList: You have a large list that is slow to update - make sure your renderItem function renders components that follow React performance best practices like PureComponent, shouldComponentUpdate, etc.
ContactList.js
unction ContactList() {
const [refreshing, setRefreshing] = React.useState(false);
const [itemChecked, setItemChecked] = useState([]);
const [checked, setChecked] = useState(new Map());
const [contacts, setContacts] = useState([]);
const [filter, setFilter] = useState([]);
const [search, setSearch] = useState('');
const [data, setData] = useState(filter)
useEffect(() => {
(async () => {
const { status } = await Contacts.requestPermissionsAsync();
if (status === 'granted') {
const { data } = await Contacts.getContactsAsync({
fields: [Contacts.Fields.PhoneNumbers],
// fields: [Contacts.Fields.Name],
});
if (data.length > 0) {
setContacts(data);
setFilter(data);
// console.log('contact', contacts[1]);
// console.log('filter', filter);
}
}
})();
}, []);
const searchFilter = (text) => {
if (text) {
const newData = contacts.filter((item) => {
const itemData = item.name ? item.name.toUpperCase() : ''.toUpperCase();
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
setFilter(newData);
setSearch(text);
} else {
setFilter(contacts);
setSearch(text);
}
};
const onChangeValue = (item) => {
checked.set(item, true);
};
useEffect(() => {
checked &&
setData((previous) => [...previous, {phone: contacts} ])
}, [checked],
)
const renderItem = ({ item, index }) => {
return (
<SafeAreaView>
<ScrollView>
<TouchableOpacity style={{ flexDirection: 'row', flex: 1 }}>
<View style={{ flex: 1, borderTopWidth: 0.5, borderTopColor: 'grey', marginBottom: 15 }}>
<Text onPress={() => setChecked(true)} style={{ fontSize: 20, marginHorizontal: 10 }}>
{item.name + ' '}
</Text>
<Text style={{ fontSize: 17, marginHorizontal: 10, marginTop: 5, color: 'grey' }}>
{item.phoneNumbers && item.phoneNumbers[0] && item.phoneNumbers[0].number}
</Text>
</View>
<View style={{ flex: 1, borderTopWidth: 0.5, borderTopColor: 'grey' }}>
<CheckBox
style={{ width: 15, height: 15 }}
right={true}
checked={checked.get(index)}
onPress={()=> onChangeValue(index)}
/>
</View>
</TouchableOpacity>
</ScrollView>
</SafeAreaView>
);
};
return (
<SafeAreaView style={styles.container}>
<View style={styles.container}>
<View
style={{
height: 40,
justifyContent: 'center',
backgroundColor: '#EEEEEE',
width: '90%',
marginHorizontal: 20,
marginTop: 15,
borderRadius: 10,
}}
>
<Feather name="search" size={20} color="grey" style={{ position: 'absolute', left: 32 }} />
<TextInput
placeholder="Search"
placeholderTextColor="#949494"
style={{
left: 20,
paddingHorizontal: 35,
fontSize: 20,
}}
value={search}
onChangeText={(text) => {
searchFilter(text);
setSearch(text);
}}
/>
</View>
<FlatList
style={{ marginTop: 15 }}
data={contacts && filter}
keyExtractor={(item) => `key-${item.id.toString()}`}
renderItem={renderItem}
ListEmptyComponent={<Text message="No contacts found." />}
/>
</View>
</SafeAreaView>
);
}
export default ContactList;
How can I solve this bug?

React Native Flip Card not Working on flip

I am trying to make a flip card game. I used GestureFlipView for flip card animation. I want to display these flip card in 3X3 grid and for that I have used from react native. But the problem occurs that cards are not getting flipped and it is showing vague behaviour as well. Just the last card working fine and other cards are doing unpredictable behaviour.
Github Repo: https://github.com/akhilomar/React-Native-Number-Game
CardScreen: https://i.stack.imgur.com/Cliww.png
Card Component
import {View, Text, SafeAreaView, TouchableOpacity} from 'react-native';
import GestureFlipView from 'react-native-gesture-flip-card';
const Cards = (props) => {
const [flipType, setFlip] = useState('left');
useEffect(() => {
})
const renderFront = () => {
return(
<TouchableOpacity onPress = {() => {
this.flipView.flipRight()
setFlip('right');
console.log("Pressed" + `${props.val}`)
}} >
<View style = {{backgroundColor:'red', width: 100, height: 100, alignItems: 'center', justifyContent: 'center'}}>
<Text style = {{color: "white", fontSize: 20}}>Swipe Me</Text>
</View>
</TouchableOpacity>
);
};
const renderBack = () => {
return(
<View style = {{backgroundColor:'blue', width: 100, height: 100, alignItems: 'center', justifyContent: 'center'}}>
<Text style = {{color: "white", fontSize: 30}}>{props.val}</Text>
{/* <TouchableOpacity onPress = {() => {
(flipType === 'left') ? this.flipView.flipRight() : this.flipView.flipLeft();
setFlip((flipType === 'left') ? 'right' : 'left');
}} style = {{padding: 10, backgroundColor: 'purple', width: 100, height: 40, alignItems: 'center', justifyContent: 'center'}}>
<Text style = {{color: 'white'}}>Reverse</Text>
</TouchableOpacity> */}
</View>
);
};
//ref = {(ref) => this.flipView = ref}
return(
<SafeAreaView style = {{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<GestureFlipView ref = {(ref) => this.flipView = ref} width={300} height = {500}>
{renderFront()}
{renderBack()}
</GestureFlipView>
</SafeAreaView>
);
}
export default Cards;```
**Card List Component**
```import React from 'react';
import {SafeAreaView, View, FlatList, Dimensions, StyleSheet } from 'react-native';
import Cards from './Cards';
const CardScreen = () => {
// const data = ['1','2','3','4','5','6','7','8','9'];
const DATA = [
{
id: '1',
title: '1',
},
{
id: '2',
title: '2',
},
{
id: '3',
title: '3',
},
{
id: '4',
title: '4',
},
{
id: '5',
title: '5',
},
{
id: '6',
title: '6',
},
{
id: '7',
title: '7',
},
{
id: '8',
title: '8',
},
{
id: '9',
title: '9',
}
];
const Shuffle = (arr1) => {
var ctr = arr1.length, temp, index;
while (ctr > 0) {
index = Math.floor(Math.random() * ctr);
ctr--;
temp = arr1[ctr];
arr1[ctr] = arr1[index];
arr1[index] = temp;
}
return arr1;
}
const numColumns = 3;
const size = Dimensions.get('window').width/numColumns;
const styles = StyleSheet.create({
itemContainer: {
width: size,
height: size,
},
item: {
flex: 1,
margin: 3,
backgroundColor: 'lightblue',
}
});
return(
<>
<FlatList
data={DATA}
renderItem={({ item }) => (
<View style={styles.itemContainer}>
<Cards val = {item.value}/>
</View>
)}
keyExtractor={item => item.id}
numColumns={numColumns} />
{/* {
data.map((index, item) => {
return(
<View style={styles.itemContainer}>
<Cards val = {item}/>
</View>
);
})
} */}
</>
);
}
export default CardScreen;```
You need to use ref correctly. you can Read about it here
const Cards = (props) => {
//first define ref
const flipViewRef = React.useRef();
//in onPress use it like this
<TouchableOpacity onPress = {() => {
flipViewRef.current.flipRight()
...
}} >
//in GestureFlipView assign it like this
<GestureFlipView ref={flipViewRef} />
}
The primary cause of your troubles is the fact that you are using a this reference within a functional component. As explained here, the value of this will be determined by how the function is called, and might even be undefined. A more reliable approach of using this is from a class context. For React, that means using a class component, rather than a functional component, which is what is being used here. You can read about function and class components here.
Something else to consider is if a FlatList is appropriate here. Typically, this component is used to improve performance for rendering large lists. Instead of using a FlatList, I would recommend using something simpler, such as a set of View components to draw the cards. Here is a complete example based on your code:
import React, { useState } from 'react';
import { View, Dimensions, StyleSheet, Text, TouchableOpacity } from 'react-native';
import GestureFlipView from 'react-native-gesture-flip-card';
const Card = (props: any) => {
const [flipType, setFlip] = useState('left');
let flipView: any;
const onFrontPress = () => {
flipView.flipRight()
setFlip('right');
}
const cardDimensions = { width: 0.9 * props.size, height: 0.9 * props.size };
const renderFront = () => {
return (
<TouchableOpacity onPress={onFrontPress} style={[styles.front, cardDimensions]}>
<Text style={styles.frontText}>Swipe Me</Text>
</TouchableOpacity>
);
};
const renderBack = () => {
return (
<View style={[styles.back, cardDimensions]}>
<Text style={styles.backText}>{props.val}</Text>
</View>
);
};
return (
<GestureFlipView ref={(ref) => flipView = ref} width={props.size} height={props.size}>
{renderFront()}
{renderBack()}
</GestureFlipView>
);
}
const CardRow = () => {
const size = Dimensions.get('window').width / 3;
return (
<View style={styles.rowContainer}>
<Card size={size} />
<Card size={size} /{ width: 0.9 * props.size, height: 0.9 * props.size }>
<Card size={size} />
</View>
);
}
const CardScreen = () => {
return (
<View style={styles.container}>
<CardRow />
<CardRow />
<CardRow />
</View>
);
}
const styles = StyleSheet.create({
container: {
flexDirection: 'column',
flex: 1,
},
rowContainer: {
flexDirection: 'row',
justifyContent: 'space-evenly',
},
back: {
backgroundColor: 'blue',
alignItems: 'center',
justifyContent: 'center'
},
backText: {
color: "white",
fontSize: 30
},
front: {
backgroundColor: 'green',
alignItems: 'center',
justifyContent: 'center',
},
frontText: {
color: "white",
fontSize: 20
}
});
export default CardScreen;

Correctly toggling playback state using react-native-track-player for live audio streaming React Native app (shoutcast)

I can't seem to get react-native-track-player fully working in my radio streaming app (shoutcast). The TouchableOpacity I use to toggle the playback seems to only work after the second press.. Even then, the toggle doesn't seem to work reliably. I think I have the logic set up incorrectly..
I also realize that I should be updating MetaData via react-native-track-player, rather than the custom hook that I wrote.
If anyone can point out my errors, I'd appreciate it! Thanks in advance 🙂
Using:
React Native 0.60.5
react-native-track-player 1.2.4
home screen logic:
...
const [playingState, setState] = useState(true)
const [song, setSong] = useState('');
const [musician, setMusician] = useState('');
useEffect(() => {
let repeat;
async function fetchData() {
try {
const res = await fetch(" * my API url ");
const json = await res.json();
setSong(json.data[0].track.title);
setMusician(json.data[0].track.artist);
repeat = setTimeout(fetchData, 26000);
} catch (error) {
console.error(error.message)
}
}
fetchData();
return () => {
if (repeat) {
clearTimeout(repeat);
}
}
}, []);
var songTitle = JSON.stringify(song)
var musicianName = JSON.stringify(musician)
const playbackState = usePlaybackState();
async function setup() {
await TrackPlayer.setupPlayer({});
await TrackPlayer.updateOptions({
stopWithApp: true,
capabilities: [
TrackPlayer.CAPABILITY_PLAY,
TrackPlayer.CAPABILITY_PAUSE,
TrackPlayer.CAPABILITY_STOP
],
compactCapabilities: [
TrackPlayer.CAPABILITY_PLAY,
TrackPlayer.CAPABILITY_PAUSE
]
});
}
useEffect(() => {
setup();
}, []);
async function togglePlayback() {
const currentTrack = await TrackPlayer.getCurrentTrack();
if (currentTrack == null) {
await TrackPlayer.reset();
await TrackPlayer.add({
id: 0,
title: songTitle,
url: " my audio stream URL ",
artist: musicianName,
album: null,
date: null,
genre: null}
);
await TrackPlayer.play();
} else {
if (playbackState === TrackPlayer.STATE_PAUSED) {
setState(!playingState)
await TrackPlayer.play();
} else {
await TrackPlayer.pause();
}
}
}
...
main screen front end:
...
<TouchableOpacity
onPress={() => togglePlayback()}
style={[
styles.playButtonContainer,
screenData.isLandscape && styles.playButtonContainerLandscape
]}>
{playingState ? (
<View style={{ alignContent: 'center', justifyContent: 'center' }}>
<Image
source={playButton}
style={styles.playPauseButton}
resizeMode='contain'
/>
</View>
) : (
<View style={{ alignContent: 'center', justifyContent: 'center' }}>
<Pulse color='white' numPulses={3} diameter={400} speed={20} duration={2000}
style={{ alignSelf: 'center', opacity: 50, zIndex: 0 }} />
<Image
source={pauseButton}
style={styles.playPauseButton}
resizeMode='contain'
/>
<LottieView
source={visualizer}
autoPlay
loop
style={{
zIndex: 1,
width: screenWidth,
height: 200,
position: 'absolute',
alignSelf: 'center'
}}
isPaused={false}
/>
</View>
)}
</TouchableOpacity>
{
playingState ? (
<Text
style={styles.trackTitle}>{''}</Text>
) : (
<Text
style={styles.trackTitle}>{song}</Text>
)
}
{
playingState ? (
<Text style={styles.tuneInTitle}>Tap the play button to tune in</Text>
) : (
<Text style={styles.artistName}>{musician}</Text>
)
}
...

React-native search bar - error: undefined is not a function (near '... this.state.books.filter...')

I can't figure out what I am doing wrong here.
I added a searchbar but when I write something in the textfield it gives me the error: "undefined is not a function (near '... this.state.books.filter...')"
Below is some of my code.
What am I doing wrong?
state = {
books: {},
};
componentDidMount() {
firebase
.database()
.ref('/Books')
.on('value', snapshot => {
this.setState({ books: snapshot.val() });
});
}
searchBooks = value => {
const { books } = this.state;
const bookArray = Object.values(books);
const filteredBooks = bookArray.filter(book => {
let bookLowercase = (book.bookname).toLowerCase();
let searchTermLowercase = value.toLowerCase();
return bookLowercase.indexOf(searchTermLowercase) > -1;
});
this.setState({ books: filteredBooks });
};
render() {
const { books } = this.state;
if (!books) {
return null;
}
const bookArray = Object.values(books);
const bookKeys = Object.keys(books);
return (
<View style={styles.container}>
{/*Searchbar */}
<View style={{ height: 80, backgroundColor: '#c45653', justifyContent: "center", paddingHorizontal: 5 }}>
<View style={{ height: 50, backgroundColor: 'white', flexDirection: 'row', padding: 5, alignItems: 'center' }}>
<TextInput
style={{
fontSize: 24,
marginLeft: 15
}}
placeholder="Search"
onChangeText={value => this.searchBooks(value)}
/>
</View>
</View>
<FlatList
style={{ backgroundColor: this.state.searchBarFocused ? 'rgba(0,0,0,0.3)' : 'white' }}
data={bookArray}
keyExtractor={(item, index) => bookKeys[index]}
renderItem={({ item, index }) => (
<BookListItem
book={item}
id={bookKeys[index]}
onSelect={this.handleSelectBook}
/>
)}
/>
</View>
);
You're initializing this.state.books as an Object.
state = {
books: {},
};
Objects have no filter function. You probably want to use an Array instead.
state = {
books: [],
};
Then you'll be able to use this.state.books.filter() with the Array's filter function.

How to prevent duplicate images when uploaded to firebase?

I have some issue when I want to upload images to firebase (real-time database & storage), in real-time DB, I have Images object has one image as the default, and I don't want to overwrite when I upload other images so I used spread operators ...,
SO,
when I pick One Image and click to upload them it's work and saved without duplicated, but when I pick two or more I see at least two images duplicate after they uploaded so how can I solve these?
structure
here is my function "_SaveImagesToFirebase"
class GalleryScreen extends Component {
constructor(props) {
super(props);
this.state = {
images: [],
newImages: []
};
}
pickMultiple = () => {
ImagePicker.openPicker({
width: 300,
height: 400,
multiple: true,
cropping: true
})
.then(img => {
this.setState({
newImages: img.map(i => {
return {
uri: i.path,
width: i.width,
height: i.height,
mime: i.mime
};
})
});
})
.then(() => this._SaveImagesToFirebase())
.catch(e => console.log(e));
};
_SaveImagesToFirebase = () => {
const uid = firebase.auth().currentUser.uid; // Provider
const { newImages } = this.state;
const provider = firebase.database().ref(`providers/${uid}`);
let imagesArray = [];
newImages.map(image => {
let file = image.uri;
const path = "Img_" + Math.floor(Math.random() * 1500);
const ref = firebase
.storage()
.ref(`provider/${uid}/ProviderGalary/${path}`);
ref.put(file).then(() => {
ref
.getDownloadURL()
.then(images => {
imagesArray.push({
uri: images
});
console.log("Out-imgArray", imagesArray);
})
.then(() => {
provider
.update({
Images: [...this.state.images, ...imagesArray] // Here is the issue
})
.then(() => console.log("done with imgs"));
});
});
});
setTimeout(() => {
console.log("timeout", this.state.images);
}, 8000);
};
componentDidMount() {
const uid = firebase.auth().currentUser.uid;
firebase
.database()
.ref(`providers/${uid}`)
.on("value", snapshot => {
let uri = snapshot.val().Images;
let images = [];
Object.values(uri).forEach(img => {
images.push({ uri: img.uri });
});
this.setState({ images });
});
}
render() {
return (
<View style={styles.container}>
{this.state.images.length === 0 ? (
<View
style={{
flex: 1,
// alignSelf: "center",
backgroundColor: "#fff"
}}
>
<Text
style={{
alignSelf: "center",
padding: 10,
fontSize: 17,
color: "#000"
}}
>
Please upload images
</Text>
</View>
) : (
<FlatList
numColumns={2}
key={Math.floor(Math.random() * 1000)}
data={this.state.images}
style={{
alignSelf: "center",
marginTop: 10
}}
renderItem={({ item }) => {
return (
// <TouchableOpacity style={{ margin: 5, flexGrow: 1 }}>
// <View>
// <Lightbox underlayColor="#fff" backgroundColor="#000">
// <Image
// key={Math.floor(Math.random() * 100)}
// source={{ uri: item.uri }}
// style={{
// alignSelf: "center",
// borderRadius: 15,
// width: width / 2 - 17,
// height: 200
// }}
// width={180}
// height={200}
// resizeMethod="scale"
// resizeMode="cover"
// />
// </Lightbox>
// </View>
// </TouchableOpacity>
<TouchableOpacity
key={Math.floor(Math.random() * 100)}
style={{
margin: 5,
width: width / 2 - 17,
height: 200
}}
>
<Lightbox
style={{ flex: 1 }}
underlayColor="#fff"
backgroundColor="#000"
>
<Image
source={{ uri: item.uri }}
style={{
borderRadius: 15,
width: "100%",
height: "100%"
}}
resizeMethod="auto"
resizeMode="cover"
/>
</Lightbox>
</TouchableOpacity>
);
}}
keyExtractor={(item, index) => index.toString()}
/>
)}
<TouchableOpacity
onPress={() => this.pickMultiple()}
style={{
alignSelf: "flex-end",
width: 57,
height: 57,
right: 10,
bottom: 80,
justifyContent: "center",
alignItems: "center",
borderRadius: 100,
backgroundColor: "#fff"
}}
>
<Icon name="ios-add-circle" size={70} color="#2F98AE" />
</TouchableOpacity>
</View>
);
}
}
export default GalleryScreen;
First, create a merging function that manipulate the arrays with duplicates by key (in your case uri field)
function extractUniques(key, array) {
const dic = {}
for (const item of array) {
dic[item[key]] = item
}
return Object.values(dic)
}
Now use it where it hearts
provider.update({
Images: extractUniques('uri', [...this.state.images, ...imagesArray]) // Here is the issue
})

Categories