0

I am using Firebase.auth() to authenticate a login with Google Firebase then I retrieve the UID and send it to my Redux Store. The UID is not being sent to the store unless I navigate to the next page then return to the login page. It seems my order of operations is off, how can I get the UID in my Redux store without haveing to re-login/ refresh the page.

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

        this.state = {
            id: ''
        }
    }

id (value) {
        this.props.id(value);
    }
handleLogin = (load) => {

        const { email, password } = this.state

        Firebase.auth()
            .signInWithEmailAndPassword(email, password)
            .then(async cred => {
                return db.collection('users').doc(cred.user.uid).set({
                    test: 'test'
                })
            })
            .then(() => this.props.navigation.navigate('AddProfiles'))

            .catch(error => console.log(error))
        

        const currentUser = firebase.auth().currentUser;
        
        const userId = currentUser["uid"];
       
        this.setState({
            id: userId
        })
        this.props.id(this.state.id);
    }

<TouchableOpacity style={styles.signupbutton}>
      <Button
           color='white'
           title="Log in"
           onPress={(payload) => this.handleLogin()}
       />
</TouchableOpacity>
const mapStateToProps = (state) => {
    return {
        counter: state.counter,
        value: state.id
    };
}

const mapDispatchToProps = dispatch => {
    return {
        id: (value) => dispatch({ type: 'id', payload: value })
    }
};

export default connect(mapStateToProps, mapDispatchToProps)(Home)
Matt Laszcz
  • 373
  • 3
  • 20

1 Answers1

1

Right now, the code starting with the line const currentUser is running before the signInWithEmailAndPassword completes, since signInWithEmailAndPassword is an asynchronous function. The reason that it works on refresh is at that point, firebase.auth().currentUser has a value, so

You can move your code inside the then block so that it runs only when the function is complete. It'll look something like this (untested, because I don't have the rest of your code):

handleLogin = (load) => {

        const { email, password } = this.state

        Firebase.auth()
            .signInWithEmailAndPassword(email, password)
            .then(async cred => {
                this.setState({
                 id: cred.user.uid
                })
                this.props.id(cred.user.id);
                return db.collection('users').doc(cred.user.uid).set({
                    test: 'test'
                })
            })
            .then(() => this.props.navigation.navigate('AddProfiles'))

            .catch(error => console.log(error))
}

Note that setState is also asynchronous, so calling this.props.id(this.state.id); right after setState is likely to fail on the first run.

Although the above should fix the immediate issue, I'd suggest onAuthStateChanged: https://firebase.google.com/docs/auth/web/start#set_an_authentication_state_observer_and_get_user_data

This way, you can do your sign in and set the Redux state based on its value or run the same code to set the Redux value when the user just returns to a page. It'll probably lead to a more robust situation than tying everything to signInWithEmailAndPassword

jnpdx
  • 45,847
  • 6
  • 64
  • 94
  • Thanks! I was not sure as to how to run these operations in the correct order. I moved my code inside the .then block but now I am returning undefined from my state upon running my code for the first time. I think I should use onAuthStateChanged as well. – Matt Laszcz Jun 29 '21 at 01:21
  • Yeah, you'll have to manage when you set the `id` part of your state. I think `onAuthStateChanged` is the way to go, but of course, that won't be available on first render, either (since it's async), so you'll have to account for what happens before there's a value available. – jnpdx Jun 29 '21 at 01:32
  • If this answered your initial question, please consider accepting the answer. – jnpdx Jun 29 '21 at 01:32
  • It answered the order of operations question but I am still not having access to the uid on the first iteration of rendering the page. – Matt Laszcz Jun 29 '21 at 01:34
  • Previously I would return no value from the store upon first auth and render, now upon first auth and render I am receiving undefined – Matt Laszcz Jun 29 '21 at 01:36
  • On first render, you will not have access to the uid, unless it's stored in a rehydrated redux state. In your previous example, it looks like `state.id` should have been `''` on first render. And it should be the same on mine, right? Because `setState` doesn't get called until `signInWithEmailAndPassword` completes – jnpdx Jun 29 '21 at 01:41
  • is there a way to wait for the uid to be sent to the store then access it before navigating to the next page? – Matt Laszcz Jun 29 '21 at 01:59
  • What do you mean "then access it"? To do what? I can probably give an example if I know what should be going on. – jnpdx Jun 29 '21 at 02:02
  • so on the next pages on my app I render data stored under that particular uid who is logged in. The data in the firestore database wont render on the consecutive pages unless i log in then go back to the log in page and log in again for a second time. Then I am able to access the data stored in the database under that particular uid. – Matt Laszcz Jun 29 '21 at 02:06
  • I'd have to see a [mre]. Are you saying that even with this code, on the subsequent page (`AddProfiles`), you're not seeing the `uid` stored in redux? – jnpdx Jun 29 '21 at 02:08
  • Yes prior to the changes mentioned it was storing it in redux store after the second render, now it is returning undefined no matter how many log in attempts I make. – Matt Laszcz Jun 29 '21 at 02:13
  • 1
    You'll have to use a callback or something akin to it to make sure that the navigation only happens once it's stored. I'm not a heavy redux user, so it's not something I'm immediately familiar with. May want to look at: https://stackoverflow.com/questions/39524855/how-to-trigger-off-callback-after-updating-state-in-redux – jnpdx Jun 29 '21 at 02:16
  • 1
    ok I will check it out! seems like that is the solution I am looking for. Essentially waiting for the storage of the uid before navigation. – Matt Laszcz Jun 29 '21 at 02:26