I am very new to React Native and still in exploring phase but I am using it for my school project. How do I translate my array of prediction using react-native-translator package? Theres only examples by using Hooks but Im using class component. This is how I get my array of prediction output:
<View style={styles.predictionWrapper}>
{isModelReady && image && (
<Text style={styles.text}>
Predictions: {predictions ? '' : 'Predicting...'}
</Text>
)}
{isModelReady &&
predictions &&
predictions.map(p => this.renderPrediction(p))}
</View>
Now I want to do translation below it. Something like this:
<View>
<Translator
from="en"
to="ms"
value={isModelReady &&
predictions &&
predictions.map(p => this.renderPrediction(p))}
onTranslated={}
/>
<Text>{result}</Text>
</View>
);
But I am not sure how should I do it with class component. I really hope someone can give me an idea how to do it.
This is my full code:
class Home extends React.Component {
state = {
isTfReady: false,
isModelReady: false,
predictions: null,
image: null
}
async componentDidMount() {
await tf.ready()
this.setState({
isTfReady: true
})
this.model = await mobilenet.load()
this.setState({ isModelReady: true })
//Output in Expo console
console.log(this.state.isTfReady)
this.getPermissionAsync()
}
getPermissionAsync = async () => {
if (Constants.platform.ios) {
const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL)
if (status !== 'granted') {
alert('Sorry, we need camera roll permissions to make this work!')
}
}
}
imageToTensor(rawImageData) {
const TO_UINT8ARRAY = true
const { width, height, data } = jpeg.decode(rawImageData, TO_UINT8ARRAY)
// Drop the alpha channel info for mobilenet
const buffer = new Uint8Array(width * height * 3)
let offset = 0 // offset into original data
for (let i = 0; i < buffer.length; i += 3) {
buffer[i] = data[offset]
buffer[i + 1] = data[offset + 1]
buffer[i + 2] = data[offset + 2]
offset += 4
}
return tf.tensor3d(buffer, [height, width, 3])
}
classifyImage = async () => {
try {
const imageAssetPath = Image.resolveAssetSource(this.state.image)
const response = await fetch(imageAssetPath.uri, {}, { isBinary: true })
const rawImageData = await response.arrayBuffer()
const imageTensor = this.imageToTensor(rawImageData)
const predictions = await this.model.classify(imageTensor)
this.setState({ predictions })
console.log(predictions)
} catch (error) {
console.log(error)
}
}
selectImage = async () => {
try {
let response = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3]
})
if (!response.canceled) {
const source = { uri: response.uri }
this.setState({ image: source })
this.classifyImage()
}
} catch (error) {
console.log(error)
}
}
renderPrediction = prediction => {
return (
<Text key={prediction.className} style={styles.text}> {prediction.className} </Text>
)
}
translateTo() {
const [value, setValue] = useState('renderPrediction');
const [result, setResult] = useState('');
return (
<View>
<Translator
from="en"
to="fr"
value={value}
onTranslated={(t) => setResult(t)}
/>
<TextInput value={value} onChangeText={(t) => setValue(t)} />
<Text>{result}</Text>
</View>
);
}
// naviScreen = () => {
// const navigation = useNavigation();
// navigation.navigate('ScanScreen');
// }
render() {
const { isTfReady, isModelReady, predictions, image } = this.state;
return (
<View style={styles.container}>
<StatusBar barStyle='light-content' />
<View style={styles.loadingContainer}>
<View style={styles.loadingModelContainer}>
{(isTfReady && isModelReady) ? (
<Text style={styles.text}> APP IS READY FOR SCANNING! </Text>) : <ActivityIndicator size='small' />}
</View>
</View>
<TouchableOpacity
style={styles.imageWrapper}
onPress={isModelReady ? this.selectImage : undefined}>
{image && <Image source={image} style={styles.imageContainer} />}
{isModelReady && !image && (
<Text style={styles.transparentText}>Tap to choose image</Text>
)}
</TouchableOpacity>
<View style={styles.predictionWrapper}>
{isModelReady && image && (
<Text style={styles.text}>
Predictions: {predictions ? '' : 'Predicting...'}
</Text>
)}
{isModelReady &&
predictions &&
predictions.map(p => this.renderPrediction(p))}
</View>
<View style={styles.bottom}>
<Button style={styles.text} title='SAVE THIS IMAGE' ></Button>
</View>
<Button title='LIVE Scan Now' onPress={() => this.props.navigation.navigate('ScanScreen')}></Button>
</View>
)
}
}
Refactored translation code for class-based component:
class Home extends React.Component {
state = {
isTfReady: false,
isModelReady: false,
predictions: null,
image: null,
textToTranslate: "",
translationResult: "",
};
async componentDidMount() {
await tf.ready();
this.setState({
isTfReady: true,
});
this.model = await mobilenet.load();
this.setState({ isModelReady: true });
//Output in Expo console
console.log(this.state.isTfReady);
this.getPermissionAsync();
}
getPermissionAsync = async () => {
if (Constants.platform.ios) {
const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL);
if (status !== "granted") {
alert("Sorry, we need camera roll permissions to make this work!");
}
}
};
imageToTensor(rawImageData) {
const TO_UINT8ARRAY = true;
const { width, height, data } = jpeg.decode(rawImageData, TO_UINT8ARRAY);
// Drop the alpha channel info for mobilenet
const buffer = new Uint8Array(width * height * 3);
let offset = 0; // offset into original data
for (let i = 0; i < buffer.length; i += 3) {
buffer[i] = data[offset];
buffer[i + 1] = data[offset + 1];
buffer[i + 2] = data[offset + 2];
offset += 4;
}
return tf.tensor3d(buffer, [height, width, 3]);
}
classifyImage = async () => {
try {
const imageAssetPath = Image.resolveAssetSource(this.state.image);
const response = await fetch(imageAssetPath.uri, {}, { isBinary: true });
const rawImageData = await response.arrayBuffer();
const imageTensor = this.imageToTensor(rawImageData);
const predictions = await this.model.classify(imageTensor);
this.setState({ predictions });
console.log(predictions);
} catch (error) {
console.log(error);
}
};
selectImage = async () => {
try {
let response = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
});
if (!response.canceled) {
const source = { uri: response.uri };
this.setState({ image: source });
this.classifyImage();
}
} catch (error) {
console.log(error);
}
};
renderPrediction = (prediction) => {
return (
<Text key={prediction.className} style={styles.text}>
{" "}
{prediction.className}{" "}
</Text>
);
};
renderTranslation = () => {
return (
<View>
<Translator
from="en"
to="fr"
value={this.state.textToTranslate}
onTranslated={(text) => this.setState({ translationResult: text })}
/>
<TextInput
value={this.state.textToTranslate}
onChangeText={(text) => this.setState({ textToTranslate: text })}
/>
<Text>{this.state.translationResult}</Text>
</View>
);
};
// naviScreen = () => {
// const navigation = useNavigation();
// navigation.navigate('ScanScreen');
// }
render() {
const { isTfReady, isModelReady, predictions, image } = this.state;
return (
<View style={styles.container}>
<StatusBar barStyle="light-content" />
{this.renderTranslation()}
<View style={styles.loadingContainer}>
<View style={styles.loadingModelContainer}>
{isTfReady && isModelReady ? (
<Text style={styles.text}> APP IS READY FOR SCANNING! </Text>
) : (
<ActivityIndicator size="small" />
)}
</View>
</View>
<TouchableOpacity
style={styles.imageWrapper}
onPress={isModelReady ? this.selectImage : undefined}
>
{image && <Image source={image} style={styles.imageContainer} />}
{isModelReady && !image && (
<Text style={styles.transparentText}>Tap to choose image</Text>
)}
</TouchableOpacity>
<View style={styles.predictionWrapper}>
{isModelReady && image && (
<Text style={styles.text}>
Predictions: {predictions ? "" : "Predicting..."}
</Text>
)}
{isModelReady &&
predictions &&
predictions.map((p) => this.renderPrediction(p))}
</View>
<View style={styles.bottom}>
<Button style={styles.text} title="SAVE THIS IMAGE"></Button>
</View>
<Button
title="LIVE Scan Now"
onPress={() => this.props.navigation.navigate("ScanScreen")}
></Button>
</View>
);
}
}
Related
Im trying to make a feature for my app where the user can fill a questionnaire with radio buttons and he can save the progress and can return later to finish it.
Take a look at this code:
const Step3 = () => {
const [questions, setQuestions] = useState([]);
const [answers, setAnswers] = useState([]);
const {addQuest} = useContext(AuthContext);
const getQuestions = async () => {
const locale = 'sq'; // TODO: get current locale
const response = await apiStandarts.get(`/questions?locale=${locale}`, {
params: { _limit: MAX_QUESTIONS, active: 1, _sort:'sortId:ASC' },
});
setQuestions(response.data);
};
const isOptionSelected = (option) => {
const answer = answers[option.question]
if (answer) {
return option.id == answer.id
}
return false;
}
const saveData = () =>{
AsyncStorage.setItem('questions', JSON.stringify(answers)).then(() => {
console.log('data saved', answers)
}).catch((error) => {
console.log(error)
})}
const retrieveData = async () => {
try {
const answers = await AsyncStorage.getItem('questions');
const parsed = JSON.parse(answers);
Alert.alert(`${parsed.id}`);
} catch(error) {
Alert.alert(error)
}
}
useEffect(() => {
getQuestions();
}, []);
const OptionList = (groupOption) => {
return (
<FlatList
data={groupOption.options}
keyExtractor={(result) => result.id.toString()}
renderItem={({ item, index}) => {
const clickedRadio = () => {
const selectedOption = {[item.question]:{...item}}
setAnswers({...answers, ...selectedOption})
console.log(answers)
}
const status = isOptionSelected(item) ? true : false
return (
<View key={index}>
<Radio initialValue={status} label={item.description} onChange={() => clickedRadio()}/>
</View>
);
}}
/>
);
};
return (
<View style={styles.container}>
<Text style={{ fontWeight: "bold", fontSize: 16, color: "#6B24AA" }}>
{t("Choose an option/Scroll for more questions")}
</Text>
<FlatList
data={questions}
keyExtractor={(result) => result.id.toString()}
renderItem={({ item, index }) => {
return (
<View style={styles.groupOptions} key={index}>
<Text>{item.description}</Text>
<OptionList options={item?.question_options}></OptionList>
</View>
);
}}
/>
<Button onPress={() => addQuest({answers})}>Save progress</Button>
<Button onPress={() => retrieveData()}>Get progress</Button>
</View>
)
}
I've tried with AsyncStorage but i get my questions from an API and the data re-renders every time the app opens again. Any ideas how to achieve this ? Thanks in advance
I am new to coding. Currently tryin to make a mobile app in react-native + firebase.
I am stuck at some really simple ( as i think ) stage, but spent a couple of days now but cannot find an answer.
In my app, user can create or enter room. Once created, room generates specific folder in firebase.
Creating and entering rooms work fine.
But whhen user enters a new room , he observes the state from the previous room even though it suppose to be blank as this is his first entry.
I dont understand how to solve this problem, absolutely crying now. A
Any help is appreciated.
This is a part of code where state is saved:
class ChatRoom extends React.Component {
constructor(zaza) {
super(zaza);
this.state = {
allTasksComplete: false,
task1: false,
task2: false,
task3: false,
task4: false,
task5: false,
task6: false,
task7: false,
finishedTasks: null,
zozo: false,
newRoomName: '',
creator: '',
};
}
generateTask = async (taskIndex, taskName,) => {
const creatorCheck = await AsyncStorage.getItem('nickname')
this.setState({creator: creatorCheck})
const nicknameSnap = await collectionRef.where('roomName', '==', this.state.newRoomName).get()
const nickCheck = nicknameSnap.docs[0].data()
if(nickCheck.creator === this.state.creator) {
firestore()
.collection('Rooms')
.doc(this.state.newRoomName)
.collection('Alpha')
.doc(taskIndex)
.set({
taskText: taskName,
})
.then(() => {
console.log('Task added')
})
}
else {
firestore()
.collection('Rooms')
.doc(this.state.newRoomName)
.collection('Beta')
.doc(taskIndex)
.set({
taskText: taskName,
})
.then(() => {
console.log('Task added')
})
} }
async componentDidMount() {
try {
const trytextx = await AsyncStorage.getItem('currentRoom')
const trial = JSON.parse(trytextx)
const maybe1 = await AsyncStorage.getItem('task1')
const string1 = JSON.parse(maybe1)
const maybe2 = await AsyncStorage.getItem('task2')
const string2 = JSON.parse(maybe2)
this.setState({newRoomName: trial})
if (string1 === false) {
this.setState({task1: false})
} else {
this.setState({ task1: string1 })
}
if (string2 === false) {
this.setState({task2: false})
} else {
this.setState({ task2: string2 })
}
} catch (e) {
console.log(e)
}
db.collection('Rooms')
.doc('RRN')
.collection('Alpha')
.get()
.then(snapshot => {
const tasks = []
snapshot.forEach(doc => {
const data = doc.data()
tasks.push(data)
})
this.setState({
finishedTasks: tasks
})
})
}
taskOne() {
if (this.state.task1) {
return (
<View>
<TaskOne />
<TouchableOpacity onPress={() => {
this.generateTask('Task1', 'First Task');
this.buttonTaskTwo()
}} raised='true' >
<View style={styles.buttonDone2}>
<Text style={styles.buttonText2}>
Выполнено
</Text>
</View>
</TouchableOpacity>
</View>
)
}
}
taskTwo() {
if (this.state.task2) {
return (
<View>
<TaskTwo />
<TouchableOpacity onPress={() => {
this.generateTask('Task2', 'Second Task');
this.buttonTaskThree()
}}>
<View style={styles.buttonDone2}>
<Text style={styles.buttonText2}>
Выполнено
</Text>
</View>
</TouchableOpacity>
</View>
)
}
}
CongratsMsg() {
if (this.state.allTasksComplete) {
return (
<View>
<CongratsMsg />
<TouchableOpacity onPress={this.lastButton}>
<View style={styles.buttonDone}>
<Text style={styles.buttonText2}>
Получить
</Text>
</View>
</TouchableOpacity>
</View>
)
}
}
lastMessage() {
if (this.state.zozo) {
return (
<View style={styles.MessageBG}>
<View >
{
this.state.finishedTasks.map(task => {
return (
<View>
<Text style={styles.MessageText}>*** {task.taskText} ***</Text>
</View>
)
})
}
</View>
</View>
)
}
}
lastButton = async () => {
this.setState({ zozo: true })
}
buttonTaskOne = async () => {
this.setState({ task1: true })
try {
await AsyncStorage.setItem('task1', JSON.stringify(true))
/* firestore()
.collection('Rooms')
.doc(this.state.newRoomName)
.set({
firstVisit: false
}, { merge: true }) */
} catch (e) {
console.log(e)
}
}
buttonTaskTwo = async () => {
this.setState({ task2: true })
try {
await AsyncStorage.setItem('task2', JSON.stringify(true))
} catch (e) {
console.log(e)
}
}
buttonCongrats = () => {
this.setState({ allTasksComplete: true })
}
render() {
return (
<ImageBackground source={bgImage} style={styles.backgroundContainer}>
<ScrollView style={styles.secondBg}>
<DefaultMsg />
<TouchableOpacity onPress={this.buttonTaskOne}>
<View style={styles.buttonDone}>
<Text style={styles.buttonText2}>
Начать!
</Text>
</View>
</TouchableOpacity>
<View>
{this.taskOne()}
</View>
<View>
{this.taskTwo()}
</View>
<View>
{this.CongratsMsg()}
</View>
<View>
{this.lastMessage()}
</View>
</ScrollView>
</ImageBackground>
)
}
}
I end up saving my state in firebase instead of asyncstorage.
im trying to filter my api array in this just for the users witch speciality == Dermatologista, can you help me?
export default class Dermatologistas extends Component{
state ={
errorMessage: null,
users: []
}
here I create the async function that is getting the users
getUserList = async () => {
try {
const response = await api.get('/auth/list');
const { users } = response.data
console.log(response.data)
this.setState({ users });
} catch (response) {
this.setState({ errorMessage: response.data.error });
}
};
componentDidMount() {
this.getUserList()
}
here it renders all users and not filter, how can I do this ?
render(){
const users = this.state.users
console.log(users)
return(
<View >
{ this.state.errorMessage && <Text>{ this.state.errorMessage }</Text> }
{this.state.users.map(user => (
<View key={user._id} style={{marginTop: 15, alignItems: 'center'}}>
<Text>{user.title}</Text>
<Text>{user.speciality}</Text>
<Button title = 'View Profile'onPress ={() =>
this.props.navigation.navigate('Profile')}/>
</View>
))}
</View>
)
}
}
You can create a function which takes the data that's being received along with the parameter through which you want to filter the data.
const filterBySpeciality = (data, speciality) => data.filter(d => d.speciality == speciality)
let data = [{speciality: "Ortho", title: "Chief Surgeon"}, {speciality: "Dermatologista", title: "Specialist"}];
console.log(filterBySpeciality(data, "Dermatologista"));
So, in your case you can call filterBySpeciality(data, "Dermatologista") in your render function and use the result for populating the View like below.
const filterBySpeciality = (data, speciality) => data.filter(d => d.speciality == speciality)
render() {
const filteredData = this.filterBySpeciality(this.state.users, "Dermatologista");
return(
<View >
{ this.state.errorMessage && <Text>{ this.state.errorMessage }</Text> }
{/* Here I have changed this.state.users to filteredData */}
{filteredData.map(user => (
<View key={user._id} style={{marginTop: 15, alignItems: 'center'}}>
<Text>{user.title}</Text>
<Text>{user.speciality}</Text>
<Button title = 'View Profile'onPress ={() =>
this.props.navigation.navigate('Profile')}/>
</View>
))}
</View>
)
}
Just put condition before rendering to data.
getUserList = async () => {
try {
const response = await api.get('/auth/list');
const usersData = response.data
const users = usersData.filter((user: any) => {
if (user.speciality === 'Dermatologista') return user;
})
console.log(users);
this.setState({ users });
} catch (response) {
this.setState({ errorMessage: response.data.error });
}
};
componentDidMount() {
this.getUserList()
}
Or you can try something like this :
render(){
const usersData = this.state.users
const users = usersData.filter((user: any) => {
if (user.speciality === 'Dermatologista') return user;
})
console.log(users)
return(
<View >
{ this.state.errorMessage && <Text>{ this.state.errorMessage }</Text> }
{this.state.users.map(user => (
<View key={user._id} style={{marginTop: 15, alignItems: 'center'}}>
<Text>{user.title}</Text>
<Text>{user.speciality}</Text>
<Button title = 'View Profile'onPress ={() =>
this.props.navigation.navigate('Profile')}/>
</View>
))}
</View>
)
}
}
in the view just this:
<View >
{ this.state.errorMessage && <Text>{ this.state.errorMessage }</Text> }
{this.state.users.filter(user => user.speciality === 'Dermatologista').map(user => (
<View key={user._id} style={{marginTop: 15, alignItems: 'center'}}>
<Text style={{fontWeight: 'bold', fontSize:20}}>{user.title}</Text>
<Text>{user.speciality}</Text>
<Button title = 'View Profile'onPress ={() => this.props.navigation.navigate('Profile')}/>
</View>
I'm getting the following warning in my react native app screen:
Warning: Cannot update during an existing state transition (such as within 'render'). Render functions should be a pure function of props and state.
As you see it seems to have something related with my getVolunteerDonations method.
Here´s my code:
export default class ProfileScreen extends React.Component {
constructor() {
super();
this.state = {
activeCard : null,
selectedIndex: 0,
user: null,
ongoingDonations: [],
finalizedDonations: [],
volunteerOngoingDonations: [],
deliveredDonations: [],
isLoadingDonations: true,
isLoadingDeliveries: true,
alertStatus: "",
alertTitle: "",
alertMessage: ""
};
this.getVolunteerDonations = this.getVolunteerDonations.bind(this);
this.getOngoingDonations = this.getOngoingDonations.bind(this);
this.displayDropdownAlert = this.displayDropdownAlert.bind(this);
}
loadUser(){
let userEmail = encodeURIComponent(auth().currentUser.email);
Promise.all([
fetch(API_URL + "/users?email=" + userEmail)
])
.then(([res1]) => Promise.all([res1.json()]))
.then(([data1]) => {
this.setState({
user: data1[0]
})})
.catch((error) => console.log(error))
}
componentDidMount(){
this.loadUser();
}
triggerReload (status, title, message) {
this.setState({
isLoadingDonations: true,
isLoadingDeliveries: true,
alertStatus: status,
alertTitle: title,
alertMessage: message
})
}
displayDropdownAlert(status, title, message) {
if(this.dropDownAlertRef) {
this.dropDownAlertRef.alertWithType(status, title, message);
}
}
getVolunteerDonations() {
if (this.state.user != null && this.state.user.category === "Voluntario" && this.state.isLoadingDonations === false
&& this.state.isLoadingDeliveries) {
const email = this.state.user.email.replace("+", "%2B");
return fetch(API_URL + "/donations?volunteer=" + email)
.then(response => response.json())
.then(volunteerDonations => {
let volunteerDonationsAux = [];
let volunteeerDonationsDone = [];
volunteerDonations.map(donation => {
if (donation.status === 'DELIVERED' || donation.status === 'CANCELLED-BY-USER') {
volunteeerDonationsDone.push(donation);
} else {
volunteerDonationsAux.push(donation);
}
})
this.setState({
volunteerOngoingDonations: volunteerDonationsAux,
deliveredDonations: volunteeerDonationsDone,
isLoadingDeliveries: false
});
});
} else if (this.state.user != null && this.state.user.category != "Voluntario" && this.state.isLoadingDeliveries) {
this.setState({
isLoadingDeliveries: false
});
}
}
render() {
if(this.state.alertStatus != "") {
this.displayDropdownAlert(this.state.alertStatus, this.state.alertTitle, this.state.alertMessage);
}
this.getOngoingDonations();
this.getVolunteerDonations();
let options;
let listData;
let itemType;
if (this.state.user != null) {
if (this.state.user.category == "Donante" || this.state.user.category == "Quiero ser Voluntario") {
options = ['Donaciones'];
listData = this.state.ongoingDonations;
itemType = "offer";
} else {
options = ['Entregas', 'Donaciones'];
if(this.state.selectedIndex == 0) {
listData = this.state.volunteerOngoingDonations;
itemType = "delivery";
} else {
listData = this.state.ongoingDonations;
itemType = "offer";
}
}
}
const {navigate} = this.props.navigation;
if (this.state.isLoadingDonations || this.state.isLoadingDeliveries){
return(
<ScrollView contentContainerStyle={{alignItems: "center", flex: 1, justifyContent: 'center'}}>
<Spinner isVisible={true} size={100} type={'Pulse'} color={'#013773'}/>
</ScrollView>
)
} else {
const getHeader = () => {
return <View>
<Ionicons name="ios-settings" size={40} color="#013773"
onPress={() => navigate('Configuración', {user: this.state.user, finalizedDonations: this.state.finalizedDonations, deliveredDonations: this.state.deliveredDonations})}
style={{position: "absolute", right: 10}}/>
<View style={{marginTop: 45, alignItems: "center"}}>
<View style={styles.avatarContainer}>
<Image style={styles.avatar}
source={require('../../../assets/logo.png')}/>
</View>
<Text style={styles.name}> {auth().currentUser.displayName} </Text>
</View>
<View style={styles.stat}>
<Text style={styles.statTitle}> {this.state.user.category === "Voluntario" ? "Voluntario": "Donante"} - {this.state.user.phone} </Text>
<Text style={styles.statTitle}> {this.state.user.email} - {this.state.user.address} </Text>
{this.state.user.category === "Donante" ? <Button
buttonStyle={styles.wantVolunteer}
title='Quiero ser voluntario' onPress={() => navigate("Quiero ser voluntario", {user: this.state.user, finalizedDonations: this.state.finalizedDonations, deliveredDonations: this.state.deliveredDonations})}/>
: null}
</View>
{this.renderSummary()}
{options.length > 1 ?
<SegmentedControlTab
values={options}
selectedIndex={this.state.selectedIndex}
onTabPress={this.handleIndexChange}
tabsContainerStyle={styles.tabsContainerStyle}
tabStyle={styles.tabStyle}
tabTextStyle={{fontSize: 18, color: '#013773'}}
activeTabStyle={{ backgroundColor: '#013773' }}
/> :
null}
</View>
}
const getFooter = () => {
if(listData.length <= 0){
return <View style={{alignItems: 'center'}}>
<Text style={styles.nostuff}> ¡Nada para mostrar! </Text>
</View>;
}
return null;
}
return (
<View>
<FlatList
data={listData}
renderItem={({ item }) => <ProfileItem itemType={itemType} item={item} volunteer="test" triggerAlert={this.displayDropdownAlert.bind(this)} updateParentState={this.triggerReload.bind(this)}/>}
keyExtractor={(item, index) => index.toString()}
ListHeaderComponent={getHeader}
ListFooterComponent={getFooter}
onRefresh={() => this.triggerReload("", "", "")}
refreshing={this.state.isLoadingDonations}
/>
<DropdownAlert ref={ref => this.dropDownAlertRef = ref} />
</View>
);
}
}
}
Sorry for the long code but I'm not sure what might be relevant or not. I tried to remove some functions to make it a little bit shorter.
As you see I call getVolunteerDonations inside my render method.
I think the issue may be that you are calling the getVolunteerDonations function within your render, but that function does setState. Whenever you setState, you re-render so it's a bit of a vicious cycle.
Are you sure you need to call the function within render?
I suggest you call the getVolunteerDonations function within componentDidMount or if you rely on the loadUser call first, then call getVolunteerDonations within a .then() of the loadUser function.
I have Flatlist with an array of items and when I select an item, all other items take the state/color of the selected item grey. How do I ensure that only selected items changes state?
Also the items I select are stored in a firestore database and are deleted when unselected. Can you also help me to store this changed state into firestore db. Thank you and I appreciate your effort.
const [catalogueArray, setCatalogueArray] = useState([])
const [addCompare, setAddCompre] = useState(false)
const [textvalue, setTextValue] = useState(`Add to \n Cart`)
const [textColor, setTextColor] = useState('green')
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 clickedBtn = () => {
setAddCompre(!addCompare ? true : false)
setTextValue(!addCompare ? `Item \n Added` : `Add to \n Cart`)
setTextColor(!addCompare ? 'grey' : 'green')
}
render(
....
<FlatList
keyExtractor={(item) => item.id}
data={catalogueArray}
renderItem={({ item }) => (
......
<TouchableOpacity style={styles.btn} onPress={() => { storeToDB(item); clickedBtn() }}>
<MaterialCommunityIcons name='plus-circle-outline' size={24} color={textColor} />
......
<Text style={...}>{textvalue}</Text>
</TouchableOpacity>
/>
const [isSelected, setIsSelected] = useState([])
const [addCompare, setAddCompare] = useState(false)
const catalogueList = () => {
const catalogue = data.filter(item => {
return item.storeName == navigation.state.params.selectStore
}).map(item => ({ ...item }))
setCatalogueArray(catalogue)
}
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 clickedBtn = 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 (
....
<FlatList
extraData={isSelected}
keyExtractor={(item) => item.id}
data={catalogueArray}
renderItem={({ item }) => (
<View style={styles.contain}>
<TouchableOpacity style={styles.btn} onPress={() => { storeToDB(item); clickedBtn(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>
)}
/>
)
}```