No Firebase App '[DEFAULT]' has been created - react-native

I realize that that there have already been several questions that address this kind of error, but none of them seem to provide the correct solution. I'm following Stephen Grider's React Native course on Udemy.
I'm pretty sure I've followed everything exactly, so I'm guessing the problem might have to do with an update to React or Firebase or something else, but I might be completely wrong. When pressing the button that activates the following code in onButtonPress():
state = { email: '', password: '', error: '' };
//a definition of the component's state, updated with onChangeText
onButtonPress() {
const { email, password } = this.state;
this.setState({ error: ' ' });
firebase.auth().signInWithEmailAndPassword(email, password) //this line is a "promise"
.catch(() => { //if it fails:
firebase.auth().creatUserWithEmailAndPassword(email, password) //also returns a promoise
.catch(() => { //if it also fails to create a username and password:
this.setState({ error: 'Authentication Failed.' });
});
});
}
I get the following error:
Since a lot of solutions on the web dealing with this error have to do with Firebase initialization, here's my code for that:
import React, { Component } from 'react';
import { View } from 'react-native';
import firebase from 'firebase';
import { Header } from './components/common/index.js'; //selects index.js automatically
import LoginForm from './components/LoginForm.js';
class App extends Component {
conponentWillMount() {
//called before render, will automatically be called because it's a life cycle method
firebase.initializeApp({
apiKey: '(I actually have my api key here, I just do not want people to steal it, same with the other values)',
authDomain: 'authenticationtutorial-ee660.firebaseapp.com',
databaseURL: 'my databaseURL',
projectId: 'my projectId',
storageBucket: 'authenticationtutorial-ee660.appspot.com',
messagingSenderId: 'my SenderId'
});
}
render() {
return (
<View>
<Header headerText="Authentication" />
<LoginForm />
</View>
);
}
}
export default App;
Any help would be appreciated. I've been dealing with this error for about a week now, and with no help on the Udemy website, I've turned to Stack Overflow :)

I had a similar issue and I solved it by adding a condition before the class
if (!firebase.apps.length) {
firebase.initializeApp(config);
}

Correct the spelling of conponentWillMount to componentWillMount and correct the spelling of creatUserWithEmailAndPassword to createUserWithEmailAndPassword.
Thanks!

I had a similar issue in a login redirect structure. As you state in your code ComponentWillMount is called before render, but that doesn't mean all promise are resolved when render its called. I've found a workaround by async / awaiting this method.
async conponentWillMount() {
//called before render, will automatically be called because it's a life cycle method
await firebase.initializeApp({
apiKey: '(I actually have my api key here, I just do not want people to steal it, same with the other values)',
authDomain: 'authenticationtutorial-ee660.firebaseapp.com',
databaseURL: 'my databaseURL',
projectId: 'my projectId',
storageBucket: 'authenticationtutorial-ee660.appspot.com',
messagingSenderId: 'my SenderId' }); }

If you make a global reference to firebase, (ex : const storageRef = firebase.storage().ref() ), it will throw this error. But if you initialize that reference under a scope you are using, it works fine.

Try to Call all configuration of firebase in index.js (TOP LEVEL) in REACT NATIVE than share result.

Related

React Native: AWS Amplify Auth.signOut() not working

React Native noob here, trying to implement AWS Amplify authentication flow into my project. But the Auth.signOut() function is not working at all. Nothing happens when I press the logout button.
const onLogOutPressed = async () => {
//Auth.signOut();
try {
await Auth.signOut({ global: true });
} catch (error) {
console.log('Error Logging Out', error);
}
}
My first version was purely Auth.signOut() as that was what the tutorial I was following did. Another guide suggested using the try method so I commented the first Auth function and added the rest.
Some help would be greatly appreciated. Do let me know if more info is required, thanks in advance.
If you're using React Native UI from Amplify and wrapped your component with withAuthenticator, below code should work.
class App extends React.Component {
constructor(props) {
super(props);
};
...
Auth.signOut().then(() => {
this.props.onStateChange(("signedOut");
});
}
// Functional component
const App = (props) => {
...
Auth.signOut().then(() => {
this.props.onStateChange("signedOut", null);
})
}
If you're not using React Native UI, then you need to handle redirection yourself. Auth.signOut() will only clear session.

compiled application not loading in real device

For the life of me, I can't figure it out. All it shows is spinning without end and i am confused on the order of the life cycle happening. Basically, it goes to login or home screen and it works correctly on emulator but not on real device. I am on react 16.8.6 and react-native 0.60.5 environment.
I am getting started with RN and my debugging tools are not great. But for now just used Alert to see and the logic that was supposed to redirect to login/home screen is never reached. The Alerts shown are in the following order:
BS
mount2
render
mount1
My code is below: if the token exists, load home screen. else load auth screen is what I wanted to achieve but for now the line:
this.props.navigation.navigate(!goToLogin ? 'App' : 'Auth');
is never reached and so, spins a lot. Any help?
import React, {Component} from 'react';
import {StatusBar, View, Alert} from 'react-native';
import {
getUserToken,
loggedInToAssociation,
extractToken,
} from '../shared/loggedinUser';
import {setLanguage} from '../shared/localization';
import {appOptions} from '../config';
import Spinner from '../components/Spinner';
export default class AuthLoadingScreen extends Component {
constructor() {
super();
this.state = {
languageLoaded: false
};
}
componentDidMount() {
Alert.alert("mount1","oumnt1") // shown
loggedInToAssociation()
.then(details => {
// details is an array now
setLanguage(details['language']);
this.setState({languageLoaded: true});
Alert.alert("mount2","oumnt2") // SHOWN
})
.catch(err => {
setLanguage(appOptions.defaultLanguage);
this.setState({languageLoaded: true});
Alert.alert("mount3","oumnt3")
});
}
// Fetch the token from storage then navigate to our appropriate place
_bootstrapAsync = async () => {
const userToken = await getUserToken();
Alert.alert("bs","bs") // SHOWN
const tokenInfo = extractToken(userToken, 'both');
let goToLogin = true; // force user to go to the login page
if (tokenInfo.length == 2) {
goToLogin = false;
}
Alert.alert("bs2","bs2") // NEVER SHOWN
this.props.navigation.navigate(!goToLogin ? 'App' : 'Auth');
};
// Render any loading content that you like here
render() {
if (this.state.languageLoaded){
this._bootstrapAsync().then(s=>{
console.log(s)
}).catch(e=>{
console.log(e)
})
}
return (
<View>
<Spinner />
<StatusBar barStyle="default" />
</View>
);
}
}
did you check your debug console when running on device? There might be an unhandled promise rejection. The promise didn't go through but nowhere to handle the catch (consider try-catch scenario for this context).
It might be having a problem with this method.
extractToken(userToken, 'both')

Dispatching Redux Data and Get the State

I stuck on Redux Implementation during developing an app using React Native and Redux. I do this for the first time and followed this example.
I've already installed Redux and React Native Navigation. I would like to save the state containing data for countries (the user picked a country and would like to keep the choice by the time when it browses to all screens).
Good. I've created a component that could be seen to all screens like this:
LinksScreen.navigationOptions = {
headerTitle: 'Links',
headerRight: <CountriesPickButton/>,
};
Next, I visualize the button and wait for a change in the component. By default, it should show primary country. Next, the user clicks on the button and it opens a modal where has a dropdown menu. For example, I show you the default fetching a country:
import { connect } from 'react-redux'
import store from '../../redux/countries'
export default class CountriesPick extends Component {
render() {.... // here is the button and modal, etc. It's work.
}
constructor(props, context) {
super(props, context);
this.state = store.getState();
store.subscribe(() => {
this.setState(store.getState());
});
this.defaultCountry(251);
}
async defaultCountry(countryId) {
return fetch(URL)
.then((response) => response.json())
.then((responseJson) => {
for (const key of Object.keys(responseJson.result)) {
// this works for current screen: this.setState({ defaultCountry: responseJson.result[key], selectedCountry: responseJson.result[key].country_id });
store.dispatch({ defaultCountry: responseJson.result[key], selectedCountry: responseJson.result[key].country_id , type: 'countries' });
}
return responseJson.result;
})
.catch((error) => {
console.error(error);
});
state = {
showModal: false,
countries: [],
selectedCountry: 0,
defaultCountry: [],
type: 'countries'
};
}
Without store.dispatch({}) I can change the state with the country but it has not to share between screens. That's because I started with Redux.
Here is the Redux code ():
import { createStore } from 'redux'
const defaultState = {
showModal: false,
countries: [],
selectedCountry: 0,
defaultCountry: [],
type: 'countries'
};
function store(state = defaultState) {
return state;
}
export default createStore(store);
Something is not like it should be. When I invoke store.dispatch({...}) it's not changing the state, it returns the default array. I guess I should use <Provider></Provider> in App.js to catch every change but first, I need to understand what I wrong?
Is it connected at all? In the example that I followed, I did not see connect(). Also, I'm not sure I'm using type properly.
Thank you in advance.
Problems here are the following:
Example on the link you provided is bad to say the least. Do not follow it
You said to be using react-native-navigation, but the code you provided comes from react-navigation. I suggest using the latter, especially for starters
Your createStore code is not going to work, as reducer for the store should be a function of state and action
With that being said, you should definitely see Basic Tutorial of redux with examples. You will almost never have to do store.getState() or store.dispatch() while using react with redux, as react-reduxpackage (included in the tutorial I linked) will do this for you. You will instead declare dependency between your store state and props your component receives

Changing state in React native App.js from another component

I'm making authentication in an app, and I'm kind of stuck. I have 2 different navigations. One shows if the user is logged in and another one if not. Basically, a Sign in screen. It's working fine if I change the value manually upon the start. But I can't find a way to change a state when a user signs in, for example. Even though the value in auth module changes, it doesn't update in App.js So how can I update the App.js's state from Sign in screen, for example?
import React, { Component } from 'react';
import { AppRegistry, Platform, StyleSheet, Text, View } from 'react-native';
import DrawerNavigator from './components/DrawerNavigator'
import SignedOutNavigator from './components/SignedOutNavigator'
import auth from './auth'
type Props = {};
export default class App extends Component<Props> {
constructor(props) {
super(props)
this.state = {
isLoggedIn: auth.isLoggedIn
}
}
render() {
return (
(this.state.isLoggedIn) ? <DrawerNavigator /> : <SignedOutNavigator />
);
}
}
AppRegistry.registerComponent('App', () => App)
and my auth module, which is very simple
import { AsyncStorage } from 'react-native';
// try to read from a local file
let api_key
let isLoggedIn = false
function save_user_settings(settings) {
AsyncStorage.mergeItem('user', JSON.stringify(settings), () => {
AsyncStorage.getItem('user', (err, result) => {
isLoggedIn = result.isLoggedIn
api_key = result.api_key
});
isLoggedIn = true
});
}
module.exports.save_user_settings = save_user_settings
module.exports.api_key = api_key
module.exports.isLoggedIn = isLoggedIn
First off, there are loads of ways to approach this problem. Because of this I'm going to try explain to you why what you have now isn't working.
The reason this is happening is because when you assign auth.isLoggedIn to your isLoggedIn state, you are assigning the value once, kind of as a copy. It's not a reference that is stored.
In addition to this, remember, React state is generally only updated with setState(), and that is never being called here, so your state will not update.
The way I would approach this problem without bringing in elements like Redux, which is overkill for this problem by itself, is to look into building an authentication higher order component which handles all the authentication logic and wraps your entire application. From there you can control if you should render the children, or do a redirect.
Auth Component
componentDidMount() {
this._saveUserSettings(settings);
}
_saveUserSettings(settings) {
AsyncStorage.mergeItem('user', JSON.stringify(settings), () => {
AsyncStorage.getItem('user', (err, result) => {
isLoggedIn = result.isLoggedIn
api_key = result.api_key
});
this.setState({isLoggedIn: true});
});
}
render() {
const { isLoggedIn } = this.state;
return isLoggedIn ? this.props.children : null;
}
App.js
render() {
<AuthComponent>
//the rest of authenticated app goes here
</AuthComponent>
}
Here's a really quick, incomplete example. But it should showcase to you how you may want to lay your authentication out. You'll also want to consider error handling and such, however.

Axios not catching Network Offline

Challenge is to catch network offline status error during POST request using AXIOS library in React-Native.
axios.post(Constants.API.LOGIN, {
username: email,
password: password
})
.then(function (response) {
console.log('SUCCESS!');
loginUserSuccess(dispatch, user);
})
.catch(function (error) {
if(!error.response){
networkError(dispatch);
} else {
loginUserFail(dispatch);
}
});
but when I switch off WiFi getting error
Possible Unhandled Promise Rejection (id:0)
What is the way to handle network statuses with AXIOS?
Thanks!
Check out NetInfo:
import { NetInfo } from 'react-native'
https://facebook.github.io/react-native/docs/netinfo.html
isConnected
Available on all platforms. Asynchronously fetch a boolean to determine internet connectivity.
NetInfo.isConnected.fetch().then(isConnected => {
console.log('First, is ' + (isConnected ? 'online' : 'offline'));
});
function handleFirstConnectivityChange(isConnected) {
console.log('Then, is ' + (isConnected ? 'online' : 'offline'));
NetInfo.isConnected.removeEventListener(
'change',
handleFirstConnectivityChange
);
}
NetInfo.isConnected.addEventListener(
'change',
handleFirstConnectivityChange
);
You may have a bit of extra issue there with your handling. I can't see exactly what is triggering the unhandled rejection in your code, but I can assume it is making it into the catch block.
If so, that currently means that either networkError() or loginUserFail() are failing, which is what is actually generating the unhandled rejection.
Take a look at those functions and make sure they have catch blocks inside them if they are asynchronous. Ask yourself where exactly is that error coming from, and answer that first, then look at NetInfo. Otherwise, the unhandled rejection may still be able to occur. Make sure you test all the different ways the code could fail :)
With NetInfo, you could set up something near the root-level in your app architecture, by way of that event listener. This could allow you to manage a setting in something like Redux. If the app detects offline, you could set the value to false and the entire app would know it is offline. You could probably make a middleware.
The code might look something like:
middleware:
`store.dispatch(changeConnectivityState())`
or you could have an action creator (shown with redux-thunk):
export function onAppConnectivityChange(newState) {
return (dispatch) {
dispatch({
type: APP_CONNECTIVITY_CHANGE,
payload: newState
})
}
}
Redux reducer:
case APP_CONNECTIVITY_CHANGE:
return {
...state,
isConnected: action.payload
}
In your components:
render() {
if (this.props.isConnected === true) {
return <View><Text>We are connected.</Text></View>
}
}
const mapStateToProps = (state) => {
const isConnected = state.someReducer.isConnected
return {
isConnected
}
}
export default connect(mapStateToProps, null)(SomeComponent)
Hopefully that gives you some ideas. Axios shouldn't be responsible for checking if the app is online or offline (except for quickly checking against a boolean). Your app should always know if it online or offline, and your components should be able to detect the state. You will find that much more scalable and easier to work with.
If I saw where you were calling Axios from, I could give you a more specific answer.