Implementing Firebase Auth With React Native + react-native-oauth - reactjs

I want to authenticate users w/ Twitter in my React Native app. I'm using the react-native-oauth library https://github.com/fullstackreact/react-native-oauth
I just want to make sure I'm going about this in the most effective way.
First things first I add firebase to my app in a config/constants file
import firebase from 'firebase'
firebase.initializeApp({
apiKey: "MY-API-KEY",
authDomain: "MY-AUTH-DOMAIN",
databaseURL: "MY-DATABASE-URL",
storageBucket: "MY-STORAGE-BUCKET",
messagingSenderId: "MY-MESSAGING-ID"
});
const ref = firebase.database().ref()
const firebaseAuth = firebase.auth()
export { ref, firebaseAuth }
Then I install the react-native-oauth library
Now, in my redux/authenticationI would probably do something like this where I eventually dispatch an action that saves the response object in my redux authentication state to use later.
import OAuthManager from 'react-native-oauth';
const manager = new OAuthManager('Nimbus') // I'm sort of confused on what the name of the app should be. Is it just the name of the app when I ran react-native init? Or something else?
export default function handleAuthWithFirebase () {
// Some redux thunk
return function (dispatch, getState) {
dispatch(authenticating());
manager.configure({
twitter: {
consumer_key: 'SOME_CONSUMER_KEY',
consumer_secret: 'SOME_CONSUMER_SECRET'
},
});
manager.authorize('twitter', {scopes: 'profile email'})
.then(resp => dispatch(getProfile(resp))) // Save response object
.catch(err => console.log('There was an error'));
// Do some other stuff like pushing a new route, etc.
}
}
Then finally, in SplashContainer.js I would add this to the handleSignIn method (ultimately called by the presentational component).
import React, { PropTypes, Component } from 'react'
import { View, Text } from 'react-native'
// Import function
import { handleAuthWithFirebase } from '~/redux/modules/authentication'
import { Splash } from '~/components'
export default class SplashContainer extends Component {
handleSignIn = () => {
// Sign in user with Twitter
handleAuthWithFirebase.bind(this);
}
render () {
return (
<Splash handleSignIn={this.handleSignIn}/>
)
}
}
Sorry, I know it was sort of a lot but just want to make sure I'm implementing this correctly. Any suggestions to improve the flow would be appreciated. Thanks!

can you check authenticate twitter with this package
https://github.com/GoldenOwlAsia/react-native-twitter-signin ?

Related

Firebase remoteConfig not returning anything in react.js

I'm currently working on an app that uses react.js, and we want to be able to have some custom config with firebase remoteConfig, but, since i don't have that much experience using it, i haven't been able to figure out how to fetch the data.
First of all, i want to show you my the way i'm doing it.
This is my firebase config (psdt: i'm using multiple firebase projects, so, that's why i had to put "third" when initializeApp)
import { getFirestore } from '#firebase/firestore';
import { initializeApp } from 'firebase/app';
const firebaseConfig = {
apiKey: process.env.REACT_APP_DISTRIBUCION_API_KEY,
authDomain: process.env.REACT_APP_DISTRIBUCION_AUTH_DOMAIN,
appId: process.env.REACT_APP_DISTRIBUCION_APP_ID,
databaseURL: process.env.REACT_APP_DISTRIBUCION_DATABAS_EURL,
measurementId: process.env.REACT_APP_DISTRIBUCION_MEASUREMENT_ID,
messagingSenderId: process.env.REACT_APP_DISTRIBUCION_MESSAGING_SENDER_ID,
projectId: process.env.REACT_APP_DISTRIBUCION_PROJECT_ID,
storageBucket: process.env.REACT_APP_DISTRIBUCION_STORAGE_BUCKET,
};
export const distribucion = initializeApp(firebaseConfig, 'third');
export const distribucion_db = getFirestore(distribucion);
This is how i'm calling getRemoteConfig
import { getRemoteConfig } from '#firebase/remote-config';
import { distribucion } from '../adapter/distribucionConfig';
export const remoteConfig = getRemoteConfig(distribucion);
And this is how i'm fetching the values ussing useEffect
const webConfig = async () => {
const isConfighFetched = await fetchAndActivate(remoteConfig);
if (isConfighFetched) {
console.log(getValue(remoteConfig, 'map_config'));
} else {
console.log('fuck it');
console.log(getValue(remoteConfig, 'map_config'));
}
};
useEffect(() => {
webConfig();
}, []);
This is what this is currently returning in my console
So, before you ask, yes, i do have values saved in my firebase app, i actually have two, one named 'authentication', and the other one 'map_config', they both are JSON values, but i'm not receiving that as you can see, what is going on ?

Getting global config to a react hook

I have a React App, that talks to several REST APIs.
I have refactored my app from redux-thunks to use react-query for the business logic of calling the APIs.
Watching videos on react-query, it was advised to abstract this into a custom hook.
So, for example:
//
// useTodos.js
import { useQuery } from 'react-query';
import { TodoApi } from 'my-api-lib';
import config from '../config';
const todoApi = new TodoApi(config.TODO_API_BASE_URL);
const useTodos = (params) =>
useQuery(
[todo, params],
() => todoApi.fetchTodos(params)
);
I have another App where I could use these hooks to also talk to the REST APIs. So I'd like to move the hooks into a common library. But the config is provided by the client. How do I get the config (TODO_BASE_API_URI) or even the "todoApi" instance, to the custom hook from the client?
In Redux I essentially dependency-injected the TodoApi instance at startup with "thunk with extra argument"
Is there a "hooky" way to get the global config to my custom hook?
The library (I assume it's my-api-lib) should export a function that expects the url (or any other config), and returns the useTodoApi hook.
In your common library:
import { useQuery } from 'react-query';
import { TodoApi } from './TodoApi';
export const createUseTodoApi = url => {
const todoApi = new TodoApi(url);
return params =>
useQuery(
[todo, params],
() => todoApi.fetchTodos(params)
);
}
In your apps:
import { createTodoApi } from 'my-api-lib';
import config from '../config';
export const useTodoApi = createUseTodoApi(config.TODO_API_BASE_URL);

Reactjs import dynamically js file with default export function

I have a reactjs app
In MyApp component I use an import at top like this:
import { ProvideAuth } from "util/auth.js";
Internally this file util/auth.js I have this code (I import another js file at top like this):
import analytics from "./analytics";
export function ProvideAuth({ children }) {
.....
}
How can I make this import analytics from "./analytics" dynamically depending on a cookie value?.
I made this code, but it doesn't work:
function loadLazyModule() {
console.log("loadLazyModule");
const _module = React.lazy(() =>
import("./analytics.js")
);
return _module;
}
// Provider hook that creates auth object and handles state
export function ProvideAuth({ children }) {
if (statisticsCookie == 'Y') {
console.log("statisticsCookie", statisticsCookie);
loadLazyModule();
}
.....
}
Finally my analytics.js has this code:
// Initialize analytics and plugins
// Documentation: https://getanalytics.io
const analytics = Analytics({
debug: process.env.NODE_ENV !== "production",
plugins: [
googleAnalyticsPlugin({
trackingId: process.env.NEXT_PUBLIC_GA_TRACKING_ID,
}),
],
});
....
export default analytics;
I need to this file import only if my cookie is enabled (has value 'Y'):
import analytics from "./analytics";
Help me please!
Thanks!
you can do it like this.
you can also use, .than().catch() function after that.
async function load() {
let say = await import('./say.js');
say.hi(); // Hello!
say.bye(); // Bye!
say.default(); // Module loaded (export default)!
}
or via import module
let modulePath = prompt("Which module to load?");
import(modulePath)
.then(obj => <module object>)
.catch(err => <loading error,e.g. if no such module>)
it's described here
https://javascript.info/modules-dynamic-imports

Firebase: .default is not a constructor

I am trying to follow this tutorial.
I'm currently stuck at the step which introduces react context to firebase.
This code block is the source of the current problem:
import Firebase, { FirebaseContext } from './components/firebase';
ReactDOM.render(
<FirebaseContext.Provider value={new Firebase()}>
<App />
</FirebaseContext.Provider>,
document.getElementById('root'),
);
serviceWorker.unregister();
When I try this, I get an error that says:
TypeError:_components_firebase__WEBPACK_IMPORTED_MODULE_5__.default is not a constructor
I have seen this post, which relates to Vue but says that the cause of an error with .default is not a constructor (not the rest of it), is because Firebase object should not be called with new keyword.
I tried removing new, but that generates an error message that says:
TypeError: Object(...) is not a function
I'm wondering if this has anything to do with the unusual way that the tutorial configures the app for firebase - which is with a class that uses a constructor (still don't understand why this is done this way):
class Firebase {
constructor() {
app.initializeApp(config);
this.auth = app.auth();
this.db = app.database();
}
export default Firebase;
Does anyone using Firebase with React know how to use the context API and if you do, have you found a way around this problem?
The firebase config setup files are:
index:
import FirebaseContext, { withFirebase } from './Context';
import Firebase from '../../firebase.1';
export default Firebase;
export { FirebaseContext, withFirebase };
context:
import React from 'react';
const FirebaseContext = React.createContext(null);
export const withFirebase = Component => props => (
<FirebaseContext.Consumer>
{firebase => <Component {...props} firebase={firebase} />}
</FirebaseContext.Consumer>
);
export default FirebaseContext;
NEXT ATTEMPT
I found this post, which looks like it might have been trying to follow the same tutorial.
That approach requires that I add back the auth method in the firebase.1.js config file so that it now looks like this:
class Firebase {
constructor() {
app.initializeApp(config).firestore();
this.auth = app.auth();
// this.db = app.database();
// this.db = app.firebase.database()
this.db = app.firestore();
}
doCreateUserWithEmailAndPassword = (email, password) =>
this.auth.createUserWithEmailAndPassword(email, password);
}
Then, the submit handler in the form is like this:
handleCreate = values => {
values.preventDefault();
const { name, email, password } = this.state;
Firebase
.doCreateUserWithEmailAndPassword = (email, password) => {
return this.auth
.createUserWithEmailAndPassword(email, password)
.then((res) => {
Firebase.firestore().collection("users").doc(res.user.uid).set({
email: values.email,
name: values.name,
role: values.role,
createdAt: Firebase.FieldValue.serverTimestamp()
}).then(() => this.history.push(ROUTES.DASHBOARD));
})
.catch(err => {
console.log(err.message);
});
};
};
When I try this, I don't get any errors, but the form does not submit - it just hangs.
NEXT ATTEMPT
Since the FirebaseContext.Consumer includes a line with firebase in lowercase, I tried all of the same steps above, but replacing title case Firebase with lower case firebase. I also tried this.firebase (I don't know why) and this.props.firebase (I have seen other posts try that but still don't know why).
None of these approaches work either.
When I try to console.log(Firebase) above the FirebaseContext.Provider, I get this a big log with lots of drop down menus that starts with this:
FirebaseAppImpl {firebase_: {…}, isDeleted_: false, services_: {…},
tokenListeners_: Array(0), analyticsEventRequests_: Array(0), …}
INTERNAL: {analytics: {…}, getUid: ƒ, getToken: ƒ,
addAuthTokenListener: ƒ, removeAuthTokenListener: ƒ}
One of the drop down menus inside this log is labelled "options_" and includes my firebase app credentials.
I think this could be related to the problem in my recent other answer.
I managed to get new Firebase working by simplifying the import/export setup.
In the react app the imports are now:
import { FirebaseContext } from './components/context';
import Firebase from './components/firebase';
Those imports and the new work after I replaced the complicated "import and re-export" code in the components/firebase.js with simply the definition for the class Firebase from the tutorial.
After this another error Firebase: Firebase App named '[DEFAULT]' already exists (app/duplicate-app). pops up, but that could be because I didn't follow the whole tutorial and some configuration is missing.
Replicating everything you are dealing with is quite difficult without having the full source of your project.
Here is the test App.js I used after the npx create-react-app react-firebase-authentication and after installing firebase.
import React from 'react';
import logo from './logo.svg';
import './App.css';
import { FirebaseContext } from './components/context';
import Firebase from './components/firebase';
function App() {
const foo = new Firebase()
return (
<div className="App">
... omitted ...
</div>
);
}
export default App;

Authentication with Firebase and Cloud Firestore

I am trying to figure out how to add authentication to a react app that uses Cloud Firestore rather than Realtime Database.
I followed this tutorial and got the whole thing working. Then - the change I'm trying to add is the move from Realtime Database to Cloud Firestore - this makes a difference to whether authentication works. I have made 20 new projects to try to get this work - totally without the process in the tutorial and just relying on firebase documentation. None of them work.
Currently, I have a config file with:
import app from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
import firestore from "firebase/firestore";
class Firebase {
constructor() {
app.initializeApp(config).firestore();
this.auth = app.default.auth();
// this.db = app.firebase.database()
this.db = app.firestore();
}
Then, i have a form with this submit handler:
import Firebase from '../../../firebase.1';
handleCreate = () => {
const { form } = this.formRef.props;
form.validateFields((err, values) => {
if (err) {
return;
};
const payload = {
// ...values,
name: values.name,
email: values.email,
organisation: values.organisation,
beta: values.beta,
role: values.role,
// createdAt: Firebase.FieldValue.serverTimestamp()
}
console.log("formvalues", payload);
Firebase
.auth()
.createUserWithEmailAndPassword(values.email, values.password)
console.log('Received values of form: ', values);
Firebase
.collection("users")
.add(payload)
// .then(docRef => {
// resetForm(initialValues);
// })
.then(e => this.setState({ modalShow: true }))
form.resetFields();
this.setState({ visible: false });
this.props.history.push(DASHBOARD);
});
};
At the moment, when I console.log(Firebase) I get:
Uncaught ReferenceError: Firebase is not defined
I have seen this post and followed each one of the recommendations in all of the answers.
I have tried changing the config file uses:
this.auth = app.default.auth();
It makes no difference.
When I try to use this, i get an error that says:
TypeError: _firebase_1__WEBPACK_IMPORTED_MODULE_14__.default.auth is not a function
Does anyone know how to use auth with firebase - where there is a Cloud Firestore instead of a Realtime Database - it's so weird that this makes a difference to whether the authentication tool works.
I've turned off the timestamp entry because I can't get firestore to record that either - but that is a problem for another day. I'm really trying to figure out how to use the authentication tool for now.
NEXT ATTEMPT
I tried to change the firebase.js file so that the config now looks like this:
import app from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
const devConfig = {
};
const prodConfig = {
};
const config =
process.env.NODE_ENV === 'production' ? prodConfig : devConfig;
const Firebase = app.initializeApp(config);
const database = app.firestore();
const auth = app.auth();
const settings = { timestampsInSnapshots: true };
export { Firebase, database as default, settings, auth };
Now, I get an error that says:
TypeError: _components_firebase__WEBPACK_IMPORTED_MODULE_2__.default
is not a constructor
I have been googling - what is a constructor. What is a webpack imported module number reference etc for the last few hours. I would love to know how to translate these error messages into something understandable.
Googling this exact error message suggests that something is wrong with the way the import and export statements are made. The new export in firebase.js is unusual (but others on Stack Overflow have tried it with problems using Firebase). It's still a question mark for me because I don't understand what the error message means.
The error message points to this line of my src/index.js
ReactDOM.render(
<FirebaseContext.Provider value={new Firebase()}>
That line comes from:
import FirebaseContext, { withFirebase } from './Context';
import Firebase from '../../firebase.1';
export default Firebase;
export { FirebaseContext, withFirebase };
That file imports from:
import React from 'react';
const FirebaseContext = React.createContext(null);
export const withFirebase = Component => props => (
<FirebaseContext.Consumer>
{firebase => <Component {...props} firebase={firebase} />}
</FirebaseContext.Consumer>
);
export default FirebaseContext;
It would be a huge reveal if anyone has any advice for learning how to learn what error messages mean. For the moment I'm guessing.
I just finished the tutorial recently also, but I simplified my firebase file. I export only the reference to the initialised firebase
import app from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
const config = {
//...
};
const firebase = app.initializeApp(config);
export default firebase;
And in my project I have:
//...
import firebase from '../../firebase';
//...
useEffect(() => {
const listener = firebase
.firestore()
.collection(COLLECTIONS.USERS)
.onSnapshot(querySnapshot => {
setUsers(querySnapshot);
querySnapshot.forEach(doc => console.log(doc.id, doc.data()));
});
return listener;
}, []);
//...
Check out my Github project here -> https://github.com/henev/react-auth-with-firebase

Resources