Access dynamically rendered children's state - javascript

I'm working on a system to multi-select elements from a FlatList to then remove from AsyncStorage the data related to the selected elements. How it works is:
-Parent component passes to child inside FlatList a state that will hold children's functions, like this:
export default function Parent({ navigation }) {
const [ productsInfo, setProductsInfo ] = useState([]);
const [ selectedProducts, setSelectedProducts ] = useState([]);
const [ selectCount, setSelectCount ] = useState(0);
<FlatList data={productsInfo}
renderItem={({ item }) => (
<Child item={item}
selectedProducts={selectedProducts}
selectCount={selectCount}
setSelectCount={setSelectCount}/>
)}/>
-Children components fill parent's array state with their callback functions:
const Child = ({ item, selectedProducts, selectCount, setSelectCount }) => {
const [ selected, setSelected ] = useState(false);
useEffect(() => {
selectedProducts.push([selected, setSelected]); //filling parent's state
}, []);
-Parent handles children's state through callback functions passed on previous step (with useEffect)
export default function Parent({ navigation }) {
const [ selectedProducts, setSelectedProducts ] = useState([]);
const [ selectCount, setSelectCount ] = useState(0);
const selectAll = () => {
selectedProducts.map(product => {
let setSelected = product[1]; //second element is the setState of child
setSelected(true);
});
setSelectCount(selectedProducts.length);
}
-Children handle their own state when they're pressed:
const Child = ({ item, selectedProducts, selectCount, setSelectCount }) => {
const [ selected, setSelected ] = useState(false);
const handleSelect = () => {
setSelected(!selected);
let count = selected ? selectCount - 1 : selectCount + 1;
setSelectCount(count); //parent's state
}
Now this all works, everything gets highlighted correctly and the counter of selected elements checks out. The problem is when I go to confirm deletion of selected elements (or the data they're rendered upon) and I iterate through the children's boolean state. They all turn out as false, even if they're true since they are highlighted, since they change color based on that state.
export default function Parent({ navigation }) {
const deleteSelected = async () => {
await selectedProducts.map(product => {
let selected = product[0]; //first element is the state's value, boolean
console.log(selected); //all false
});
}
It needs to know at which index there are true value so it can delete data at those indexes, but they never turn out true.
Do you know why this happens? I'll leave the whole code below.
import React, { useEffect, useState } from 'react';
import {
FlatList,
StyleSheet,
View,
Text,
TouchableHighlight,
Alert
} from 'react-native';
import Icon from '#expo/vector-icons/MaterialIcons';
import AsyncStorage from '#react-native-async-storage/async-storage';
import { TouchableNativeFeedback } from 'react-native-gesture-handler';
const Product = ({ item, selectedProducts, selectCount, setSelectCount }) => { //Child
const [ selected, setSelected ] = useState(false);
const handleSelect = () => {
setSelected(!selected);
let count = selected ? selectCount - 1 : selectCount + 1;
setSelectCount(count);
}
useEffect(() => {
selectedProducts.push([selected, setSelected]);
}, []);
return (
<TouchableHighlight onPress={() => handleSelect()}>
<View style={[styles.productContainer, {backgroundColor: selected ? '#DDDDDD' : '#F8F8F8'}]}>
<View>
<Text style={styles.productTitle}>{item.name}</Text>
</View>
<View style={styles.productDetailsContainer}>
<View style={styles.productDetails}>
<Text style={styles.productDetailsTitle}>Prezzo attuale</Text>
<Text>{item.currentPrice}</Text>
</View>
<View style={styles.productDetails}>
<Text style={styles.productDetailsTitle}>Prezzo più basso</Text>
<Text>{item.lowestPrice}</Text>
</View>
<View style={styles.productDetails}>
<Text style={styles.productDetailsTitle}>Prezzo target</Text>
<Text>{item.targetPrice}</Text>
</View>
</View>
</View>
</TouchableHighlight>);
}
export default function WatchlistDeleteScreen({ navigation }) { //Parent
const [ productsInfo, setProductsInfo ] = useState([]);
const [ selectedProducts, setSelectedProducts ] = useState([]);
const [ selectCount, setSelectCount ] = useState(0);
const selectAll = () => {
selectedProducts.map(product => {
let setSelected = product[1];
setSelected(true);
});
setSelectCount(selectedProducts.length);
}
const deleteSelected = async () => {
await selectedProducts.map(product => {
let selected = product[0];
console.log(selected);
});
}
useEffect(() => {
const getData = async () => {
await AsyncStorage.getItem('productsInfo')
.then(data => JSON.parse(data))
.then(jsonData => {
setProductsInfo(jsonData);
})
.catch(error => {});
}
getData();
}, []);
return (
<View style={{flex: 1}}>
<View style={styles.header}>
<View style={styles.headerIconsContainer}>
<TouchableNativeFeedback onPress={() => { navigation.pop() }}
background={TouchableNativeFeedback.Ripple('default', true)}>
<Icon name={'close'} size={27} color={'black'} />
</TouchableNativeFeedback>
<Text style={{fontWeight: 'bold', fontSize: 20, marginLeft: 25}}>{selectCount}</Text>
</View>
<View style={styles.headerIconsContainer}>
<View style={styles.icons}>
<TouchableNativeFeedback onPress={() => { selectAll() }}
background={TouchableNativeFeedback.Ripple('default', true)}>
<Icon name={'select-all'} size={27} color={'black'} />
</TouchableNativeFeedback>
</View>
{selectCount > 0 &&
<View style={styles.icons}>
<TouchableNativeFeedback onPress={() => { deleteSelected() }}
background={TouchableNativeFeedback.Ripple('default', true)}>
<Icon name={'check'} size={27} color={'black'} />
</TouchableNativeFeedback>
</View>}
</View>
</View>
<FlatList data={productsInfo}
renderItem={({ item }) => (
<Product item={item}
selectedProducts={selectedProducts}
selectCount={selectCount}
setSelectCount={setSelectCount}/>
)}/>
</View>
);
}
const styles = StyleSheet.create({
header: {
backgroundColor: 'white',
height: 58,
elevation: 4,
justifyContent: 'space-between',
paddingLeft: 10,
paddingRight: 10,
flexDirection: 'row',
alignItems: 'center'
},
headerIconsContainer: {
flexDirection: 'row',
alignItems: 'center'
},
screenTitle: {
fontWeight: 'bold',
fontSize: 20
},
productContainer: {
padding: 10
},
productTitle: {
fontWeight: 'bold',
fontSize: 19,
borderBottomColor: 'grey',
borderBottomWidth: 0.2
},
productDetailsTitle: {
fontWeight: 'bold',
fontSize: 14
},
productDetailsContainer: {
flexDirection: 'row',
flexWrap: 'wrap',
padding: 5,
justifyContent: 'space-between'
},
productDetails: {
flexWrap: 'wrap'
},
icons: {
marginLeft: 25
}
});

The problem
This is wrong:
useEffect(() => {
selectedProducts.push([selected, setSelected]);
}, []);
The selectedProducts is a state variable and should be considered immutable: push does not mutates the variable itself (its the same array), but adds an element to it (a side effect). You should avoid this and only use setSelectedProducts instead. Even more, in the browser console you should have a message warning about useEffect not having the correct dependencies array. Try this instead:
// Add extra argument setSelectedProducts
const Child = ({ item, selectedProducts, setSelectedProducts, selectCount, setSelectCount }) => {
const [ selected, setSelected ] = useState(false);
useEffect(() => {
// Filling parent's state
setSelectedProducts([
...selectedProducts,
[selected, setSelected],
]);
}, [setSelectedProducts, selectedProducts, selected, setSelected]);
Now, this shows part of the problem here: there are circular dependencies. In this fixed useEffect example, it will be fired each time one or more of its dependencies changes. As we are changing selectedProducts in the callback (indirectly, using setSelectedProducts), it will be called again, and again, and again.
The solution
You need to pass the responsibility of managing the list of states (and, thus, the list of selected ones) to the list containing them (here, WatchlistDeleteScreen). This will receive a (un)select me message from each product:
const Product = ({ item, selected, toggleSelected }) => { //Child
return (
<TouchableHighlight onPress={toggleSelected}> // Without `()`: No extra function
//...
</TouchableHighlight>
);
}
export default function WatchlistDeleteScreen({ navigation }) { //Parent
const [ productsInfo, setProductsInfo ] = useState([]);
const [ selectedProducts, setSelectedProducts ] = useState([]);
// Mark all products as selected
const selectAll = () => {
setSelectedProducts(
productsInfo.map(() => true)
);
}
// Mark all products as unselected
const deleteSelected = () => {
setSelectedProducts(
productsInfo.map(() => false)
);
}
// Toggles a single product selection state
const toggleSelected = (index) => {
const selectedProductsNew =
selectedProducts.map(
// Only toggle the matching index product
(poductState, i) => i === index ? !value : value
);
// But full array is updated, respecting React
// immutability and state change controller
setSelectedProducts( selectedProductsNew );
}
// Fetch items. No need to async/await if you use .then/.catch
useEffect(() => {
AsyncStorage.getItem('productsInfo')
.then(data => JSON.parse(data))
.then(jsonData => {
setProductsInfo(jsonData);
// Also create an array with the states of all
// products to unselected
deleteSelected();
})
.catch(error => {});
}, [setProductsInfo, deleteSelected]);
// Just to be clear. You can use selectedProducts.length directly
// from the JSX
const selectCount = selectedProducts.length;
return (
// ...
<FlatList
data={productsInfo}
// Also get `index` from FlatList
// https://reactnative.dev/docs/flatlist#renderitem
renderItem={({ item, index }) => (
<Product
item={item}
// Pass `selected` state (managed in parent, used in child)
selected={selectedProducts[index]}
// Pass `index` to the `toggleSelected` function
toggleSelected={toggleSelected.bind(this, index)}/>
)}
/>
// ...
)
}

Related

How do I change the state of a variable from a separate component

I am trying to use React's context hook to store data that is filled out throughout different components. The data is then packaged together and sent to firebase. All of the variables states are changing as expected except for one, the exercise name.
Context
export const PrContext = createContext({});
export const PrProvider = ({children}) => {
const [numExercises,setNumExercises] = useState(0);
const [exercise,setExercise] = useState('Select Exercise');
const [reps,setReps] = useState('');
const [weight, setWeight] = useState('');
const [notes,setNotes] = useState('default note');
const todayDate = getCurrentDate();
return(
<PrContext.Provider
value = {{
numExercises,
setNumExercises,
exercise,
setExercise,
reps,
setReps,
weight,
setWeight,
notes,
setNotes,
sendPrData: async () => {
try {
await setDoc(doc(db,'UsersData',userInfo.user),{
Exercise:{exercise},
Reps:{reps},
Weight:{weight},
});
}catch(e){
console.log(e)
}
},
}}
>
{children}
</PrContext.Provider>
)
}
The screen that holds the components
const PrEnteryScreen = ({}) => {
return(
<View style = {{height:'100%',width:'100%',backgroundColor:'#141212'}}>
<SafeAreaView style = {{alignItems:'center'}}>
{/**
* use context for pr information
*/}
<PrProvider>
<PopDown/>
<RepsWeightTextInput/>
<NotesInput/>
<SubmitPr />
</PrProvider>
</SafeAreaView>
</View>
);
};
export default PrEnteryScreen;
Component whose text I want to change
if (
Platform.OS === "android" &&
UIManager.setLayoutAnimationEnabledExperimental
) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
const PopDown = () => {
const value = useContext(PrContext)
const [isOpen,setIsOpen] = useState(false)
const [listHeight,setListHeight] = useState(0)
const [textName,setTextName] = useState()
//eventually want to change text based on exercise state
const toggleOpen = ({}) => {
setIsOpen(value => !value);
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
}
useEffect(() =>{
setTextName(value.exercise);
},[value.exercise])
useEffect(() =>{
EXERCISE_DATA.forEach(()=>{
setListHeight(value => value+50)
})
},[isOpen])
return(
<View>
<TouchableOpacity
onPress = {toggleOpen}
>
<View
style={styles.buttonBackground}
>
<Text style = {styles.Text}>{textName}</Text>
</View>
</TouchableOpacity>
<View style = {{alignItems:'center'}}>
<SelectExerciseModal style = {isOpen ? styles.show: styles.hidden} listHeight = {listHeight} />
</View>
</View>
)
}
const styles = StyleSheet.create({
hidden:{
height:0,
},
show:{ backgroundColor: '#9B9A9A', width: 250 , borderRadius: 20},
buttonBackground:{
backgroundColor: '#9B9A9A',
width: 335,
borderRadius:41,
alignItems:'center',
marginHorizontal:25,
height:200,
justifyContent:'center'
},
Text:{
fontWeight:'bold',
fontSize:40,
color:'white',
alignItems:'center'
}
});
export default PopDown;
When I change value.exercise the change is not registered in the popdown component and the text does not change.
list of options component
This component pops out of the popdown component and provides a list of exercises to choose from.
export const EXERCISE_DATA = [
'Bench',
'Squat',
'Deadlift',
]
const SelectExerciseModal = ({listHeight,style}) =>{
return(
<View style = {[style,listHeight]}>
<View style={{
alignItems: 'center',
justifyContent:'center'
}}>
<PrProvider>
<FlatList
data={EXERCISE_DATA}
keyExtractor={item => item}
renderItem={({ item }) => <ExerciseListComponent exerciseName={item} />} />
</PrProvider>
</View>
</View>
)
}
export default SelectExerciseModal;
Exercise list component
const ExerciseListComponent = ({exerciseName}) => {
const value = useContext(PrContext);
useEffect(()=>{
console.log(value.exercise)
},[value.exercise])
return(
<View>
<TouchableOpacity
onPress={()=>{{value.setExercise(exerciseName)}}}
>
<Text style = {styles.text}>
{exerciseName}
</Text>
</TouchableOpacity>
</View>
)
}
const styles = StyleSheet.create({
text:{
fontSize:56,
color:'white'
},
})
export default ExerciseListComponent;
const SubmitPr = () => {
const value = useContext(PrContext);
const [Reps,SetReps] = useState('');
const [Exercise,SetExercise] = useState('Select a Exercise');
const [Weight, SetWeight] = useState('');
const [email,setEmail] = useState('not working');
const auth = useContext(AuthContext)
const getInfo = useCallback(()=>{
SetReps(value.reps);
SetExercise(value.exercise);
SetWeight(value.weight);
setEmail(auth.user);
console.log(props.state)
});
const date = getCurrentDate();
return(
<TouchableOpacity
onPress={async () => {
getInfo()
try {
await setDoc(doc(db,'UsersData',date),{
Exercise:{Exercise},
Reps:{Reps},
Weight:{Weight},
});
}catch(e){
console.log(e)
}
}}
>
<View style = {styles.submitButton}>
<Text style = {styles.textStyle}>Submit</Text>
</View>
</TouchableOpacity>
)
};
styles = StyleSheet.create({
submitButton:{
width:209,
height:100,
backgroundColor:'#9B9A9A',
borderRadius:80,
justifyContent:'center',
alignItems:'center',
marginTop:50
},
textStyle:{
color:'white',
fontSize:30,
fontWeight:'bold'
}
})
export default SubmitPr;
Additional Info:
When i press one of the exercise list components it logs the new state of value.exercise through the useEffect hook but when I go to press submit the state of value.exercise is unchanged. Additionally the popdown component's text isn't changing to the new state of value.exercise.

how to assign each list item to the same button in react native

this is my
homePage
as you can see I have some items and a button that I use to add them to the chartScreen, which is chartScreen , I'm using context api to store items in cartContext.js where each item has its own key to make things easier but I cannot correlate the logic for how to assign each item to the button so whenever I press the button its own item gets added to the chartScreen.
const CartContext = createContext();
export function CartProvider({ children }){
const [items, setItems] = useState(
[
{
title: "Pınar",
text: "Pınar Klasik Dana Sucuk (225g)",
pic: <Image
style={styles.image1}
source={require("./Images/klasik_dana_sucuk_paket.png")} />,
key: 1,
},
{
text: "Pınar Uzun Sosis (225g)",
pic: <Image
style={styles.image1}
source={require("./Images/pinar_uzun_sosis.png")} />,
key: 2,
},
]
const [store, setStore] = useState([]);
const addToCart = (text) => {
setStore((prevState) => [
...prevState,
text,
]);
}
return (
<CartContext.Provider value={{items,setItems, addToCart, store}}>
{children}
</CartContext.Provider>
)
I found a cheeky way to send a specific item from addButton.js
const AddButton = () => {
const { items } = useContext(CartContext);
const { addToCart } = useContext(CartContext);
return (
<TouchableOpacity style={styles.button} onPress={() => addToCart(items[0])}>
<Text>+</Text>
</TouchableOpacity>
)
}
and in the chartScreen I view it just like this
const ChartScreen = () => {
const { store } = useContext(CartContext);
if(store.length != 0) {
return (
<FlatList
data={store}
renderItem={({ item }) => (
<View style={styles.listItem}>
<Text style={styles.itemText}>{item.pic} {item.text}</Text>
</View>
)}
/>
)
}
this is for sure not even the wrong way to achieve the goal so can you help me?
You can import your button and make it common for all the items, and pass the value to it.
Here is your button code
const AddButton = ({item}) => {
const { items } = useContext(CartContext);
const { addToCart } = useContext(CartContext);
return (
<TouchableOpacity style={styles.button} onPress={() =>
addToCart(item?.text)}>
<Text>+</Text>
</TouchableOpacity>
)
}
Here you can make button for all you item
const ChartScreen = () => {
const { store } = useContext(CartContext);
if(store.length != 0) {
return (
<FlatList
data={store}
renderItem={({ item }) => (
<View style={styles.listItem}>
<Text style={styles.itemText}>{item.pic} {item.text}</Text>
<AddButton item={item} />
</View>
)}
/>
)
}

React-Native Key Error - All Elements are deleted even though there is a unique key added to the KeyExtractor

I am adding a unique key to the FlatList and in theory only the button i press is supposed to be deleted but instead all elements are deleted
import { render } from "react-dom";
import {
View,
Text,
StyleSheet,
FlatList,
Button,
TouchableOpacity,
} from "react-native";
import { Context } from "../context/BlogContext";
import { Entypo } from "#expo/vector-icons";
const IndexScreen = function () {
const { state, addBlogPost, deleteBlogPost } = useContext(Context);
return (
<View>
<Button title="Add Post" onPress={() => addBlogPost()} />
<FlatList
data={state}
keyExtractor={(blogPosts) => blogPosts.title}
renderItem={({ item }) => {
return (
<View style={styles.row}>
<Text style={styles.title}>
{item.title} - {item.id}
</Text>
<TouchableOpacity
onPress={() => {
deleteBlogPost(item.id);
}}
>
<Entypo style={styles.icon} name="trash" />
</TouchableOpacity>
</View>
);
}}
/>
</View>
);
};
const styles = StyleSheet.create({
row: {
flexDirection: "row",
justifyContent: "space-between",
paddingHorizontal: 10,
paddingVertical: 20,
borderTopWidth: 1,
borderColor: "gray",
},
title: {
fontSize: 18,
},
icon: {
fontSize: 24,
},
});
export default IndexScreen;
Context Screen:
import createDataContext from "./createDataContext";
const blogReducer = function (state, action) {
switch (action.type) {
case "delete_blogpost":
return state.filter((blogPosts) => {
blogPosts.id !== action.payload;
});
case "add_blogpost":
return [
...state,
{
id: Math.floor(Math.random() * 99999),
title: `Blog Post #${state.length + 1}`,
},
];
default:
return state;
}
};
const addBlogPost = function (dispatch) {
return () => {
dispatch({ type: "add_blogpost" });
};
};
const deleteBlogPost = (dispatch) => {
return (id) => {
dispatch({ type: "delete_blogpost", payload: id });
};
};
export const { Context, Provider } = createDataContext(
blogReducer,
{ addBlogPost, deleteBlogPost },
[]
);
and
export default function (reducer, actions, initialState) {
const Context = React.createContext();
const Provider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState);
// actions === { addBlogPost : (dispatch) => {return () => {}}}
const boundActions = {};
for (let key in actions) {
boundActions[key] = actions[key](dispatch);
}
return (
<Context.Provider value={{ state, ...boundActions }}>
{children}
</Context.Provider>
);
};
return { Context, Provider };
}
i dont know how to solve this. all titles are unique as they have different numbers but still all are deleted!!!!!!!!!!!!
here is the pic of the app

Reset state after unmount screen - Hooks?

After getting data from API I set it to state, and render items in Flatlist,
when I select any item from it I manipulate data and add a new property to item object named as "toggle: true"
and it's works well when I select any item from list I add a border based on toggle,
But when I go back to previous screen then re open the lists screen I can see the border rendered around the items, although I reset the state when the unmounted screen
So what's the wrong I made here?
Code snippet
Data
export default {
...
services: [
{
id: 0,
name: 'nameS0',
logo:
'https://cdn2.iconfinder.com/data/icons/hotel-98/64/hair-dryer-tools-beauty-hairdressing-512.png',
price: 19.99,
},
],
employees: [
{
id: 0,
name: 'name0',
img:
'https://www.visualelementmedia.com/wp-content/uploads/2015/04/person-4-400x629.jpg',
},
...
],
};
const VendorProfile = ({navigation}) => {
const [services, setServices] = React.useState(null);
const [employees, setEmployees] = React.useState(null);
const [serviceSelected, setServiceSelected] = React.useState(null);
const [employeeSelected, setEmployeeSelected] = React.useState(null);
// For selected Item (services, employees)
const itemSelected = (data, id) => {
const updated = data.map((item) => {
item.toggle = false;
if (item.id === id) {
item.toggle = true;
data === services
? setServiceSelected(item)
: setEmployeeSelected(item);
}
return item;
});
data === services ? setServices(updated) : setEmployees(updated);
};
...
const renderEmployees = ({item}) => {
return (
<TouchableOpacity
onPress={() => itemSelected(employees, item.id)}
delayPressIn={0}
style={styles.employeeContainer}>
<EmployeePattern style={{alignSelf: 'center'}} />
<View style={styles.employeeLogo}>
<Image
source={{uri: item.img}}
style={[styles.imgStyle, {borderRadius: 25}]}
/>
</View>
<View style={{marginTop: 30}}>
<Text style={{textAlign: 'center'}}> {item.name}</Text>
</View>
<View style={{marginTop: 10, alignSelf: 'center'}}>
{item.toggle && <AntDesign name="check" size={25} color="#000" />} // here it's stuck after back and reopen the screen
</View>
</TouchableOpacity>
);
};
React.useEffect(() => {
setServices(VendorProfileData.services);
setEmployees(VendorProfileData.employees);
() => {
setServices(null);
setEmployees(null);
};
}, []);
return (
<View style={styles.container}>
<FlatList
data={services}
renderItem={renderServices}
horizontal
keyExtractor={(item) => item.id.toString()}
contentContainerStyle={{
justifyContent: 'space-between',
flexGrow: 1,
}}
/>
.....
</View>
);
};
Ok so after trying multiple times, i got it
change this
const updated = data.map((item) => {
to this
const updated = data.map((old) => {
let item = {...old};
and please make sure everything is working and we didn't break a thing :),
On your ItemSelected function you are passing the whole employees list, and going through it now thats fine, but when you changing one item inside this list without "recreating it" the reference to that item is still the same "because its an object" meaning that we are modifying the original item, and since we are doing so, the item keeps its old reference, best way to avoid that is to recreate the object,
hope this gives you an idea.

How to save State in React Native to Firebase

I am creating an app that allows a user to select multiple items from a Flatlist and the state changes once selected. However when I move away from that screen, all the selected items go back to the unselected state. How can use Firebase to save that state so it doesn't revert when I leave the screen? I am also open to alternative solutions to this issue.
Thank you for your time.
export default function StoreCatalogue({ navigation }) {
const { data, status } = useQuery('products', fetchProducts)
const [catalogueArray, setCatalogueArray] = useState([])
const [isSelected, setIsSelected] = useState([])
const [addCompare, setAddCompare] = useState(false)
const storeToDB = async (item) => {
if (!addCompare) {
await db.collection('users').doc(auth.currentUser.uid).collection('myProducts').doc(item.storeName + item.genName).set({
product_id: item.id,
product_genName: item.genName
})
} else {
await db.collection('users').doc(auth.currentUser.uid).collection('myProducts').doc(item.storeName + item.genName).delete()
}
}
const clickHandler = async (item) => {
setAddCompare(
addCompare ? false : true
)
if (isSelected.indexOf(item) > -1) {
let array = isSelected.filter(indexObj => {
if (indexObj == item) {
return false
}
return true
})
setIsSelected(array)
} else {
setIsSelected([
...isSelected, item
])
}
}
return (
<View style={styles.container}>
<FlatList
extraData={isSelected}
keyExtractor={(item) => item.id}
data={catalogueArray}
renderItem={({ item }) => (
<TouchableOpacity style={styles.btn} onPress={() => { storeToDB(item); clickHandler(item) }}>
<MaterialCommunityIcons name='plus-circle-outline' size={24} color={isSelected.indexOf(item) > -1 ? 'grey' : 'green'} />
<View style={{ position: 'absolute', bottom: 3 }}>
<Text style={{ fontSize: 10, textAlign: 'center', color: isSelected.indexOf(item) > -1 ? 'grey' : 'green' }}>{isSelected.indexOf(item) > -1 ? 'item \nAdded' : 'Add to\n Compare '}</Text>
</View>
</TouchableOpacity>
)}
/>
</View>
)
}
The problem is when you leave a screen the state gets reset to original, you can use Redux to store the state separately and on an event store the information on firebase once.
Firebase can be costly for this operation since every read and write will be chargeable.

Categories