Reputation: 868
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.
Upvotes: 0
Views: 144
Reputation: 352
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.
Upvotes: 2