0

I am using React-Native and React-Native-Firebase and am trying to have my Events component make a different Firebase query (and then update redux store) depending what the value of the activityType prop is.

Here is the parent component which is working just fine. It updates state.eventType when I change the dropdown value and passes the value into <Events />.

let eventTypes = [{value: 'My Activity'}, {value: 'Friend Activity'}, {value: 'All Activity'}];

  state = {
    showEventFormModal: false,
    eventType: 'Friend Activity'
  }
          <View style={styles.container}>
          <Dropdown
            data={eventTypes}
            value={this.state.eventType}
            containerStyle={{minWidth: 200, marginBottom: 20}}
            onChangeText={val => this.setState({eventType: val})}
          />
          <Events activityType={this.state.eventType}/>
        </View>

And here is Events component. Using a Switch statement to determine which activityType was passed into props. The issue I am having is an infinite loop because within each case statement I am dispatching the action to update the store which causes a rerender and the componentWillUpdate() to retrigger. What I am trying to understand is what the optimal way to handle this problem is? Because clearly my method now does not function properly. Is there a common react pattern to achieve this?

// GOAL: when this components props are updated
// update redux store via this.props.dispatch(updateEvents(events))
// depending on which type of activity was selected

componentWillUpdate() { 
    let events = [];

    switch(this.props.activityType) {
        case 'Friend Activity': // get events collections where the participants contains a friend

            // first get current users' friend list
            firebase.firestore().doc(`users/${this.props.currentUser.uid}`)
            .get()
            .then(doc => {
                return doc.data().friends
            })
            // then search the participants sub collection of the event
            .then(friends => {
                firebase.firestore().collection('events')
                .get()
                .then(eventsSnapshot => {
                    eventsSnapshot.forEach(doc => {
                        const { type, date, event_author, comment } = doc.data();
                        let event = {
                            doc, 
                            id: doc.id,
                            type,
                            event_author,
                            participants: [],
                            date,
                            comment,
                        }
                        firebase.firestore().collection('events').doc(doc.id).collection('participants')
                        .get()
                        .then(participantsSnapshot => {
                            for(let i=0; i<participantsSnapshot.size;i++) {
                                if(participantsSnapshot.docs[i].exists) {
                                    // if participant uid is in friends array, add event to events array
                                    if(friends.includes(participantsSnapshot.docs[i].data().uid)) {
                                        // add participant to event
                                        let { displayName, uid } = participantsSnapshot.docs[i].data();
                                        let participant = { displayName, uid }
                                        event['participants'].push(participant)
                                        events.push(event)
                                        break;
                                    }
                                }
                            }
                        })
                        .then(() => {
                            console.log(events)
                            this.props.dispatch(updateEvents(events))
                        })
                        .catch(e => {console.error(e)})
                    })
                })
                .catch(e => {console.error(e)})
            })
        case 'My Activity': // get events collections where event_author is the user
            let counter = 0;
            firebase.firestore().collection('events').where("event_author", "==", this.props.currentUser.displayName) 
            .get()
            .then(eventsSnapshot => {
                eventsSnapshot.forEach(doc => {
                    const { type, date, event_author, comment } = doc.data();
                    let event = {
                        doc, 
                        id: doc.id,
                        type,
                        event_author,
                        participants: [],
                        date,
                        comment,
                    } 
                    // add participants sub collection to event object
                    firebase.firestore().collection('events').doc(event.id).collection('participants')
                    .get()
                    .then(participantsSnapshot => {
                        participantsSnapshot.forEach(doc => {
                            if(doc.exists) {
                                // add participant to event
                                let { displayName, uid } = doc.data();
                                let participant = { displayName, uid }
                                event['participants'].push(participant)
                            }
                        })
                        events.push(event);
                        counter++;
                        return counter;
                    })
                    .then((counter) => {
                        // if all events have been retrieved, call updateEvents(events)
                        if(counter === eventsSnapshot.size) {
                            this.props.dispatch(updateEvents(events))
                        }
                    })
                })
            })
        case 'All Activity':
            // TODO
            // get events collections where event_author is the user 
            // OR a friend is a participant
    }
}
Eric Furspan
  • 742
  • 3
  • 15
  • 36

2 Answers2

1

Updating the store is best to do on the user action. So, I'd update the store in the Dropdown onChange event vs. in the componentWillUpdate function.

R. Wright
  • 960
  • 5
  • 9
0

I've figured out what feels like a clean way to handle this after finding out I can access prevProps via componentDidUpdate. This way I can compare the previous activityType to the current and if they have changed, then on componentDidUpdate it should call fetchData(activityType).

class Events extends React.Component {

 componentDidMount() {
     // for initial load 
     this.fetchData('My Activity')
 }

 componentDidUpdate(prevProps) {     
     if(this.props.activityType !== prevProps.activityType) {
         console.log(`prev and current activityType are NOT equal. Fetching data for ${this.props.activityType}`)
         this.fetchData(this.props.activityType)
     }
 } 
 fetchData = (activityType) => {
    //switch statements deciding which query to perform
      ...
      //this.props.dispatch(updateEvents(events))
 }

}

https://reactjs.org/docs/react-component.html#componentdidupdate

Eric Furspan
  • 742
  • 3
  • 15
  • 36