Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
331 views
in Technique[技术] by (71.8m points)

react native - Firebase Auth with ReactNative Redux not working using Expo

I'm trying to implement the Firebase Auth in my Project, I was able to do it (at least for Email and Password Auth in Firebase) through the REST API from Firebase. However, I need to work with Social Authentication (Facebook and Google, besides Email and Password at least).

I'm using EXPO for my project (that is why I don't have the Folders of iOS or Android).

I have already install Firebase Dependency in my package.json:

Firebase Dependency

I have also initialized Firebase on my App:

FirebaseKeys.js File:

export default {
    firebaseConfig: {
        apiKey: "[myApi Key]",
        authDomain: "alianzafc2021.firebaseapp.com",
        databaseURL: "https://alianzafc2021-default-rtdb.firebaseio.com",
        projectId: "alianzafc2021",
        storageBucket: "alianzafc2021.appspot.com",
        messagingSenderId: "[Messaging ID]",
        appId: "[App ID]",
        measurementId: "[Measurement ID}]"
      }
}

App.js: (Where I initialize the Firebase)

import React, { useState } from 'react';
import { createStore, combineReducers, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import ReduxThunk from 'redux-thunk';
import * as Font from 'expo-font';
import * as firebase from 'firebase';

//Firebase Initialize Config
import firebaseConfig from "./constants/FireBaseKeys";

//Navigation
import AppNavigator from "./navigation/AppNavigator";

//import de reducers
import jugadoresReducer from "./store/reducers/jugadores";
import noticiasReducer from "./store/reducers/noticias";
import partidosReducer from "./store/reducers/partido";
import tablaReducer from "./store/reducers/tabla";
import authReducer from "./store/reducers/auth";

if (!firebase.apps.length) {
  firebase.initializeApp(firebaseConfig);
}else {
  firebase.app(); // if already initialized, use that one
}

const rootReducer = combineReducers({
  jugadores: jugadoresReducer,
  noticias: noticiasReducer,
  partidos: partidosReducer,
  tabla: tablaReducer,
  auth: authReducer,
});

const store = createStore(rootReducer,applyMiddleware(ReduxThunk));

//Recibe la Tipografia de numeros
const fetchFonts = () => {
  return Font.loadAsync({
    'number': require('./assets/fonts/number.ttf'),
  });
};

export default function App() {
  const [fontLoaded, setFontLoaded] = useState(true);

  if (!fontLoaded) {
    return (
      <AppLoading 
      startAsync={fetchFonts} 
      onFinish={() => {
        setFontLoaded(true);
      }} />
    );
  }

  return (
    <Provider store={store}>
      <AppNavigator />
    </Provider>
  );
}

I also have created the login page without functionality (Just trying to Login which is giving the Error):

    import React, {useState,useCallback} from 'react';
import {
  View,
  Text,
  TouchableOpacity,
  Image,
  Platform,
  StyleSheet,
  ScrollView
} from 'react-native';
import { useDispatch } from 'react-redux';

import FormInput from '../components/UI/FormInput';
import FormButton from '../components/UI/FormButton';
import SocialButton from '../components/UI/SocialButton';
import * as authActions from '../store/actions/auth';

const LoginScreen = ({navigation}) => {
    const [email, setEmail] = useState();
    const [password, setPassword] = useState();
    const [isLoading, setIsLoading] = useState(false);
    const [error, setError] = useState();
    const dispatch = useDispatch();

    const LoginHandler = useCallback ( async (email, password) => {
      setError(null);
        setIsLoading(true);
        try {
            await dispatch(authActions.login(email,password));
            //props.navigation.navigate('Shop');
        } catch (err) {
            setError(err.message);
            setIsLoading(false);
        }
    }, [dispatch, setEmail, setPassword]);

  return (
    <ScrollView contentContainerStyle={styles.container}>
      <Image
        source={require('../assets/alianza-logo.png')}
        style={styles.logo}
      />
      <Text style={styles.text}>Albo App</Text>

      <FormInput
        labelValue={email}
        onChangeText={(userEmail) => setEmail(userEmail)}
        placeholderText="Correo"
        iconType="user"
        keyboardType="email-address"
        autoCapitalize="none"
        autoCorrect={false}
      />

      <FormInput
        labelValue={password}
        onChangeText={(userPassword) => setPassword(userPassword)}
        placeholderText="Contrase?a"
        iconType="lock"
        secureTextEntry={true}
      />

      <FormButton
        buttonTitle="Ingresar"
        onPress={LoginHandler(email, password)}
      />

      <TouchableOpacity style={styles.forgotButton} onPress={() => {}}>
        <Text style={styles.navButtonText}>Olvidaste la Contrase?a?</Text>
      </TouchableOpacity>

      {Platform.OS === 'android' ? (
        <View>
          <SocialButton
            buttonTitle="Ingresa con Facebook"
            btnType="facebook"
            color="#4867aa"
            backgroundColor="#e6eaf4"
            onPress={() => {}}
          />

          <SocialButton
            buttonTitle="Ingresa con Google"
            btnType="google"
            color="#de4d41"
            backgroundColor="#f5e7ea"
            onPress={() => {}}
          />
        </View>
      ) : null}

      <TouchableOpacity
        style={styles.forgotButton}
        onPress={() => navigation.navigate('Signup')}>
        <Text style={styles.navButtonText}>
          Crear una Cuenta
        </Text>
      </TouchableOpacity>
    </ScrollView>
  );
};

export default LoginScreen;

const styles = StyleSheet.create({
  container: {
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
    paddingTop: 50,
    marginTop: 30

  },
  logo: {
    height: 150,
    width: 150,
    resizeMode: 'cover',
  },
  text: {
    fontSize: 28,
    marginBottom: 10,
    color: '#051d5f',
  },
  navButton: {
    marginTop: 15,
  },
  forgotButton: {
    marginVertical: 35,
  },
  navButtonText: {
    fontSize: 18,
    fontWeight: '500',
    color: '#2e64e5'
  },
});

Login Page

Now my problem is that I'm not able to give the Functionality to save some info upon login on my Reducer (or even reach the login event on my Actions).

Here is my Actions file (I comment out the code which works when using the Rest API to Login I have modified just the login function):

import AsyncStorage from '@react-native-community/async-storage';
import Auth from "firebase/firebase-auth";

//export const SIGNUP = 'SIGNUP';
//export const LOGIN = 'LOGIN';
export const AUTHENTICATE = 'AUTHENTICATE';
export const LOGOUT = 'LOGOUT';
export const SET_DID_TRY_AL = 'SET_DID_TRY_AL';

let timer;

export const setDidTryAL = () => {
    return { type: SET_DID_TRY_AL };
};

export const authenticate = (userId, token, expiryTime) => {
    return dispatch => {
        dispatch(setLogoutTimer(expiryTime));
        dispatch({ type: AUTHENTICATE, userId: userId, token: token });
    }
}

export const signup = (email, password) => {
    return async dispatch => {
        const response = await fetch('https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[Here my ID Key]', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                email: email,
                password: password,
                returnSecureToken: true,
            })
        });
        if (!response.ok) {
            const errorResData = await response.json();
            const errorId = errorResData.error.message;
            let message = 'Algo salio mal!';
            if (errorId === 'EMAIL_EXISTS') {
                message = 'Este Correo ya esta en Uso';
            }
            throw new Error(message);
        }

        const resData = await response.json();
        console.log(resData.localId);
        dispatch(
            authenticate(
                resData.localId,
                resData.idToken,
                parseInt(resData.expiresIn) * 1000
            )
        );
        const expirationDate = new Date(new Date().getTime() + parseInt(resData.expiresIn) * 1000);
        saveDataToStorage(resData.idToken, resData.localId, expirationDate);
    };
};

export const login = (email, password) => {

    return async dispatch => {
     await firebase
            .auth()
            .signInWithEmailAndPassword(email, password)
            .then(resData => {
                console.log(resData);
                dispatch(
                    authenticate(
                        resData.localId,
                        resData.idToken,
                        parseInt(resData.expiresIn) * 1000,
                    )
                )
                const expirationDate = new Date(new Date().getTime() + parseInt(resData.expiresIn) * 1000);
                saveDataToStorage(resData.idToken, resData.localId, expirationDate);
            })
            .catch(err => { console.log(err) });
    }

    // return async dispatch => {
    //     const response = await fetch('https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=[Here my ID Key]', {
    //         method: 'POST',
    //         headers: {
    //             'Content-Type': 'application/json',
    //         },
    //         body: JSON.stringify({
    //             email: email,
    //             password: password,
    //             returnSecureToken: true,
    //         })
    //     });
    //     if (!response.ok) {
    //         const errorResData = await response.json();
    //         const errorId = errorResData.error.message;
    //         let message = 'Algo salio mal!';
    //         if (errorId === 'EMAIL_NOT_FOUND') {
    //             message = 'Este Correo no esta en Uso';
    //         } else if (errorId === 'INVALID_PASSWORD') {
    //             message = 'Esta Contrase?a esta Equivocada.'
    //         }

    //         throw new Error(message);
    //     }

    //     const resData = await response.json();
    //     console.log(resData);
    //     dispatch(
    //         authenticate(
    //             resData.localId,
    //             resData.idToken,
    //             parseInt(resData.expiresIn) * 1000,
    //         )
    //     );
    //     const expirationDate = new Date(new Date().getTime() + parseInt(resData.expiresIn) * 1000);
    //     saveDataToStorage(resData.idToken, resData.localId, expirationDate);
    // };
};

export const logout = () => {
    clearLogoutTimer();
    AsyncStorage.removeItem('userData');
    return { type: LOGOUT };
};

const clearLogoutTimer = () => {
    if (timer) {
 

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The error of too many re-render is here:

You should never call onPress like that on render method.

It's missing an callback function in onPress like onPress={() => yourFunction()} and you are calling like onPress={yourFunction()}

Original:

      <FormButton
        buttonTitle="Ingresar"
        onPress={LoginHandler(email, password)}
      />

Correct

      <FormButton
        buttonTitle="Ingresar"
        onPress={() => LoginHandler(email, password)}
      />

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...