3

I'm trying to make a login process with react native / redux / firebase and i got some issues...

I try to implement onAuthStateChanged to dispatch an action, but it's not working as i want.

It's working for two cases :

1 - I implement directly my onAuthStateChanged in my component like below :

componentDidMount() {
    firebaseAuth.onAuthStateChanged()
        .then((user) => {
            if (user) {
                Actions.home();
            } else {
                Actions.login();
            }
        });
}

2 - I implement it in as an action with redux-thunk but without dispatch (but then i cant dispatch an action and redirect to my correct route)

export const isAuthenticated = () => {
    firebaseAuth.onAuthStateChanged()
        .then((user) => {
            if (user) {
                console.log("launch.action#isAuthenticated - user already connected");
            } else {
                console.log("launch.action#isAuthenticated - user not connected");
            }
        });

};

And what i want to do is this (but doesn't work) :

export const isAuthenticated = () => {
return (dispatch) => {
    firebaseAuth.onAuthStateChanged()
        .then((user) => {
            console.log('user', user);
            if (user) {
                console.log("launch.action#isAuthenticated - user already connected");
                dispatch(isUserConnected(true));
            } else {
                console.log("launch.action#isAuthenticated - user not connected");
                dispatch(isUserNotConnected(true));
            }
        });
};

};

Can someone explain me why it doesn't work with the dispatch ?

Thanks!

Bloumdsq
  • 81
  • 2

2 Answers2

1

Two things:

  1. Use one function (for example, isUserConnected) and setting the value to either true or false (instead of using two different functions, isUserNotConnected and isUserConnected, as you currently are)

  2. Change firebaseAuth to firebase.auth() per the firebase documentation


Try this.

(This works for me)

In Redux (actions):

// Firebase
import firebase from 'firebase';

// Redux Function
export const testFirebaseInRedux = () => {
  return (dispatch, getState) => {
    firebase.auth().onAuthStateChanged(function (user) {
      if (user) {
        console.log("testFirebaseInRedux: logged in");
        dispatch(isUserConnected(true));
      } else {
        console.log("testFirebaseInRedux: not logged in");
        dispatch(isUserConnected(false));
      }
    })
  }
}

export const isUserConnected = (payloadToSet) => {
  return {
    type: 'IS_USER_CONNECTED',
    payload: payloadToSet
  }
}

In Redux (reducers):

export default function (state=initialState, action) {
  switch(action.type) {
  case 'IS_USER_CONNECTED':
    return {
      ...state,
      isUserConnected: action.payload
    }
  default:
    return {
        ...state
    }
  }
}

Component:

// Libraries
import React from 'react';

// Redux
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {testFirebaseInRedux} from './../actions/index.js';

class YourComponent extends React.Component {
  constructor(props) {
    super(props);
  }

  componentDidMount() {
    this.props.testFirebaseInRedux()
  }

}

function mapStateToProps(state) {
    return {
      user: state.user
    };
}

function matchDispatchToProps(dispatch) {
    return bindActionCreators({
      testFirebaseInRedux: testFirebaseInRedux,
    }, dispatch)
}


export default connect(mapStateToProps, matchDispatchToProps)(YourComponent);
Rbar
  • 3,112
  • 8
  • 30
  • 59
  • My firebaseAuth is firebase.auth(). And what i have, is exactly what you did. The fact is it never goes inside the onAuthStateChanged response when i use the return (dispatch) thing... :/ – Bloumdsq Dec 17 '17 at 11:51
0

. Here is an example from my Root Container, which is almost my highest component

** In your case You need to move your authStateChangeListener to an app level component, like inside a componentDidMount(). Then separate your concerns, if user exists.... THEN call an function from your actions that DISPATCHES a store update.

 componentDidMount() {
// if redux persist is not active fire startup action
if (!ReduxPersist.active) {
  this.props.startup()
}

// ********* Add a listener from the database to monitor whos logged in. *********
firebase.auth().onAuthStateChanged((user) => {
  // ********* If a user is logged in firebase will return the user object. THEY ARE NOT LOGGED IN THOUGH *********
  if (user) {
    console.log('onAuthStateChanged', user)
    // ********* Then we call an official Firebase login function through actions *********
    this.props.loginRequest(user);
  } else {
    console.log('No user signed in')
  }
});

// ********* After logging in the found user from above we need to set them to redux store *********  
let signedInUser = firebase.auth().currentUser;

if (signedInUser) {
  this.props.loginRequest(signedInUser);
  console.log('currentUserSignedIn', signedInUser)
} else {
  console.log('no active user', signedInUser)
}

}

And this is my loginRequest that lives within my actions

export const loginRequest = user => dispatch => {
    // ******** This gets called in RootContainer on mount, it will populate redux store with the entire User object from firebase ********
    // ******** FYI - The entire user object also contains their vehicles ********
    // ******** Here we need to check if user already exists in Firebase Database so that we dont overwrite their old data ********
    // ******** WARNING! With Firebase if you set data to a spot that has existing data it will overwrite it! ********
    console.log('RECIEVED USER TO LOOKUP', user);
    firebase.database().ref('users/' + user.uid).once('value').then(function (snapshot) {
        // ******** This method is straight from their docs ********
        // ******** It returns whatever is found at the path xxxxx/users/user.uid ********
        let username = snapshot.val();
        console.log(' FOUND THIS USER FROM THE DB', username);
        {
            // ******** If the username object is empty there wasn't any data at xxxxxx/user/user.uid ********
            // ******** It's safe to write data to this spot ********
            username === null ? firebase.database().ref('users/' + user.uid).set({
                account: username
            }).then(function () {
                console.log('STORED THIS USER TO FIREBASE DB', username);
                dispatch(userSet(username))
            })
                // ******** Otherwise, the user already exists and we should update redux store with logged in user ********
                : dispatch(userSet(username))
        }
    })
        .catch((err) => console.log(err));

    dispatch(userSet(user))
    console.log('INSIDE FIREBASEE DB SET', user)

};
Gavin Thomas
  • 1,702
  • 8
  • 16
  • So i guess thats not possible to have onAuthStateChangedListener inside my actions ? Having a litener works only on component ? – Bloumdsq Dec 17 '17 at 11:41
  • The short answer is yes you can put them in your actions. But you still need to invoke them from your app Level. So In the first answer he does it that way. Check out my upates for you – Gavin Thomas Dec 17 '17 at 16:01
  • I just hooked up your functions into my app and it doesn't work with everything in your actions. – Gavin Thomas Dec 17 '17 at 16:42