0

In a react-native, redux, firebase project, I have a drawer component that subscribes to an onSnapshot listener when the component mounts, and on will unmount, it calls the snapshot reference. this component looks like this:

import { onAccountChange } from '../actions/Agenda';    
import {dispatch} from 'redux';

class DrawerContentComponent extends React.Component {
    constructor (props) {
        super(props);
    }
    componentDidMount(){
        this.unsubscribeAccount = firebase.firestore().collection('users').doc(this.props.authUser.uid).onSnapshot((doc) => {
        dispatch({type: types.LOAD_ACCOUNT, payload: doc.data()})

    });
    }
    componentWillUnmount() {
        this.unsubscribeAccount();
    }

    < ...rest of component... >

EDIT:
    const mapStateToProps = ({ account, auth, inbox, agenda }) => {
    const { role, profileImg, legalName, username, rating, phoneNumber } = account;
    const { conversations } = inbox;
    const { authUser } = auth;
    const { events } = agenda;
    return {
        role,
        profileImg,
        legalName,
        username,
        rating,
        phoneNumber,
        authUser,
        conversations,
        events
    };
};

    const mapDispatchToProps = { logoutUser, onProfileChange, onAccountChange, getConversations, getAgenda };

    export default connect(mapStateToProps, mapDispatchToProps)(DrawerContentComponent);
} 

Edit: onAccountChange():

export const onAccountChange = (uid) => {
    return (dispatch) => {
      firebase.firestore().collection('users').doc(uid).onSnapshot((doc) => {
        dispatch({ type: types.LOAD_ACCOUNT, payload: doc.data() });
      });
    };
};

The above functions as necessary, because I couldn't manage to unsubscribe from the action, which previously was placed in an external directory for actions.

Problem: I want to be able to implement this by somehow using the function thats already created in the actions file ( getAgenda()) without having to rewrite the code in the component, because im currently doing that just to have the ability to unsubscribe from the listener on unmount, only way I thought of to make it work.

ideally, id like to do something like this:

componentDidMount() {
  this.unsubscribeAgenda = this.props.getAgenda();
}
componentWillUnmount() {
  this.unsubscribeAgenda();
}

But the above results in: TypeError: 'dispatch is not a function' if I take out the dispatch import, the error is ReferenceError: Cant find variable: dispatch, I obviously need to dispatch changes for a onSnapshot listener

What are some strategies to handle this?

4
  • What does your getAgenda action creator look like? Commented Apr 23, 2020 at 23:49
  • I dont have one ive never needed one. I have my actions in another directory, and initially was just calling them on mount through props. but that doesnt help me with having to call a reference to the onSnapshot listener to detach it and prevent app crash Commented Apr 23, 2020 at 23:50
  • 1
    Can you post what getAgenda's code is? Commented Apr 23, 2020 at 23:52
  • @ZacharyHaber check it out now, with onAccountChange instead for brevity, same concept, less code Commented Apr 23, 2020 at 23:59

2 Answers 2

1

You can't import dispatch directly from redux.

You need to either use react-redux's connect() function to wrap your action creators with dispatch or get dispatch directly from it.

If you are using a functional component, you could use useDispatch to get access to it.

If you don't want to use one of the normal react-redux options, you can export dispatch from your store, and then import it from where you created your store.

export const dispatch = store.dispatch

If most of your logic for the firestore is in an redux thunk action (or similar with asynchronous capabilities), use connect to get the action wrapped in dispatch and run it as you have in your ideal at the end. Whatever you return from a thunk action is returned from the call as well, so you should be able to set it up to return the unsubscribe function.

 connect({},{onAccountChange})(DrawerContentComponent)

Then you can dispatch onAccountChange action creator using:

this.props.onAccountChange()

Edit:

Modify your onAccountChange function to this so that your thunk returns your unsubscibe function.

export const onAccountChange = (uid) => {
  return (dispatch) => {
    return firebase
      .firestore()
      .collection('users')
      .doc(uid)
      .onSnapshot((doc) => {
        dispatch({ type: types.LOAD_ACCOUNT, payload: doc.data() });
      });
  };
};

Then you just need to add onAccountChange to the mapDispatch to props and use this in your componentDidMount method:

this.unsubscribeAccount = this.props.onAccountChange();
Sign up to request clarification or add additional context in comments.

1 Comment

ahh I see, so the issue was with not returning the actual firebase listener attachment
1

For making components to be attached to store for both dispatch actions or mapping props, it is used with connect(mapStateToProps, mapDispatchToProps)(Component). in your case, there is no props passed to component so I'll just send null for mapStateToProps

(assuming you used Provider at some parent component REDUX. I cant understand how to connect a component defined as a class extending React.Component in order to read the store)


 import { connect } from 'react-redux';

 class DrawerContentComponent extends React.Component {
    ...rest code...
   componentDidMount() {
     this.unsubscribeAgenda = this.props.getAgenda();
    }
   componentWillUnmount() {
    this.unsubscribeAgenda();
    }
   }
  export default connect(null, { getAgenda })(DrawerContentComponent)

1 Comment

what is loadSuccess() used for? because error coming from there... anyhow, you cant import at UI side something directly from 'redux' and not 'react-redux', if you want to import dispatch against the normal flow of redux import it from your store

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.