简体   繁体   中英

React Native / Redux / Firebase - onAuthStateChanged not dispatched

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!

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);

. 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)

};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM